С момента публикации концепции Twelve-Factor App значительно изменилось то, как мы создаём, упаковываем и развёртываем приложения. Контейнеры, Kubernetes и облачные технологии стали основными технологиями, которые позволяют нам создавать переносимые, масштабируемые и надёжные приложения. Тем не менее 12 факторов, сформулированных в концепции, всё ещё актуальны в современном технологическом стеке.

Перевели статью, в которой описывается методология Twelve-Factor App и применение её концепций в контексте контейнеров и Kubernetes.

О концепции Twelve-Factor App

Концепция Twelve-Factor App (TFA) появилась в 2012 году, ещё до того, как контейнеры стали общепринятым способом упаковки и развёртывания приложений. Принципы TFA задумывались как рекомендации, помогающие сделать приложение более подходящим для облачных развёртываний, обеспечивая характеристики, которые делают приложения одноразовыми и лёгкими в масштабировании.

☝️ Ознакомиться с принципами Twelve-Factor App на русском языке можно здесь или в существующих статьях на Хабре здесь и здесь.

Если кратко, то согласно принципам Twelve-Factor App, программное обеспечение как услуга (SaaS) должно:

1. Использовать декларативные форматы для автоматизации настройки, чтобы минимизировать время и затраты на присоединение к проекту новых разработчиков.

2. Иметь понятный контракт с базовой операционной системой, обеспечивая максимальную переносимость между средами выполнения.

3. Быть пригодным для развёртывания на современных облачных платформах, избавляя от необходимости в серверах и системном администрировании.

4. Минимизировать расхождение между разработкой и производством, обеспечивая непрерывное развёртывание для максимальной гибкости.

5. Иметь возможность масштабироваться без значительных изменений в инструментах, архитектуре или методах разработки.

Теперь рассмотрим как использовать Twelve-Factor App вместе с контейнерами и Kubernetes. 

I. Кодовая база

Одна кодовая база, отслеживаемая в системе контроля версий, множество развёртываний

Кодовая база — это репозиторий кода, который составляет ваше приложение, и вы должны непрерывно управлять им с помощью системы контроля версий, предпочтительно Git. Вы определяете различные релизы (dev, test, prod) с помощью различных веток.

Kubernetes и контейнеры используют основанные на тексте представления (такие как YAML Kubernetes и Dockerfiles). Инструменты автоматизации, такие как Ansible, описывают ожидаемое состояние системы в своих собственных файлах. Эти артефакты могут постепенно изменяться, поэтому лучше управлять ими с помощью системы контроля версий, как вы управляете кодом приложения.

Источник

В кодовой базе можно хранить конфигурации, связанные с Kubernetes, т.е. Configmap и даже файлы docker. Когда вы можете выразить приложения и инфраструктуру как код, а конфигурации отслеживаются в системе контроля версий Git, вам легче применять такие методы, как GitOps и непрерывная интеграция/непрерывное развёртывание (CI/CD). Если Git является единственным достоверным источником информации, вы перестраховываетесь от неожиданных изменений и обеспечиваете ответственность за изменения, внесённые в ваши среды.

II. Зависимости

Явно объявляйте и изолируйте зависимости

Явно объявляйте зависимости приложения и управляйте ими с помощью менеджера пакетов. В каждом языке есть инструменты для объявления и управления зависимостями. Например, Maven чрезвычайно популярен для Java-приложений, а NPM является менеджером пакетов по умолчанию для Node.js-приложений. Не следует добавлять зависимости в Git. Вместо этого версионируйте конфигурацию, которая описывает зависимости. Менеджер пакетов может извлекать эти зависимости во время сборки и связывать их с приложением.

Приложение должно быть полностью автономным. Вы можете устранить любую связь с инфраструктурой, убедившись, что всё, что нужно приложению для работы, упаковано как единый развёртываемый блок. Благодаря этому вы можете легко перемещать сервисы на разные платформы или инфраструктуру, а также устранять потенциальные несоответствия между средами, когда приложение и инфраструктура хорошо разделены.

Источник

Контейнер может включать все зависимости, на которые опирается приложение, и обеспечивать достаточно изолированную среду.

Есть два способа добиться этого на примере docker и requirement file:

1. Поместите зависимости установки в сам файл docker, как показано в примере ниже:

FROM python:3
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir nibabel pydicom matplotlib pillow && \
    pip install --no-cache-dir med2image
CMD ["cat", "/etc/os-release"]

2. Поместите зависимости установки в отдельный файл requirement.txt и используйте ваш общий docker file для создания образов docker, как показано в примере ниже:

requirements.txt
matplotlib
med2image
nibabel
pillow
pydi

и используйте следующий общий Dockerfile

FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt
COPY . .
CMD [ "python", "./your-daemon-or-script.py" ]

III. Конфигурации

Храните конфигурацию в среде

Конфигурация приложения обычно специфична для среды, в которой запускается приложение (dev, test, prod). Обычно хорошей практикой считается избегать специальной сборки приложения для конкретных сред. Соберите приложение один раз и применяйте конфигурацию во время выполнения или при запуске приложения.

Лучший способ сделать это — убедиться, что конфигурация приложения для конкретных сред не встроена в приложение, а предоставляется средой, в которой выполняется рабочая нагрузка. Kubernetes предоставляет несколько конструкций, которые легко позволяют присоединить специфичную для среды конфигурацию к вашим работающим подам с помощью переменных окружения и ConfigMaps. Убедитесь, что всё, что различается между разными средами (или развёртываниями), экстраполируется одним из этих двух способов и присоединяется к подам во время выполнения.

Когда вы развёртываете приложение, работающее непосредственно на хосте, лучший способ связать специфичную для среды конфигурацию со средой — сделать её доступной на хосте. Технологии контейнеров и оркестровки контейнеров упрощают это с помощью ConfigMaps, переменных окружения и секретов. Вам не нужно включать специфичную для среды конфигурацию в контейнер. Вместо этого экстраполируйте её в ConfigMap, чтобы вы могли запустить это же изображение контейнера в другой среде с другой конфигурацией.

Это пример Yaml для получения конфигурации.

apiVersion: v1
 kind: Pod
 metadata:
   name: User-services
 spec:
   containers:
     - name: user-service
       image: userservice
       env:
        # Define the environment variable
         - name: MONGO_CONNECTION_STRG
           valueFrom:
             secretKeyRef:
               name: mongsecretes
               key: mongo-connection-string # To Store value in env 
       env:
        - name: USER_CURRENT_STATE
          valueFrom:
            configMapKeyRef:
              name: user-prod-valus          
              key: user_init_state # To Store value in env

В приведенном выше примере мы сохраняем значение connection string из секретов Kubernetes в переменную окружения MONGO_CONNECTION_STRG. Точно так же мы сохраняем значение начального состояния пользователя из карты конфигурации в переменную окружения USER_CURRENT_STATE.

Ваши секреты и Configmap будут варьироваться в зависимости от окружения и плавно перетекать вместе с CI/CD pipeline.

IV. Вспомогательные службы

Рассматривайте вспомогательные службы как подключённые ресурсы

Вспомогательные службы (Backing services) — это службы, к которым осуществляется доступ по сети. Максимально разделяйте базы данных, очереди сообщений, сторонние службы или любые другие типы внешних ресурсов от системы и взаимодействуйте с ними через API. Если вам нужно заменить базу данных приложения, вы не должны модифицировать кодовую базу, чтобы учесть это изменение. 

API должны придерживаться согласованных контрактов, позволяющих базовым реализациям изменяться без ведома клиентов. Храните информацию о подключении к внешним службам в Kubernetes ConfigMaps и переменных окружения, чтобы вам не нужно было пересобирать образ контейнера, если информация о подключении изменится. По возможности сообщайте о взаимодействии со сторонними службами через API с согласованными контрактами.

Для приложений, созданных с учётом методологии Twelve-Factor App и предназначенных для Kubernetes, есть два способа реализовать этот фактор.

1. Состояние внутри Kubernetes: сервисы, развёрнутые в подах Kubernetes, балансируются с помощью компонента service в Kubernetes. Можно развернуть в Kubernetes любые базы данных и службы очередей, так как конфигурация хранится в переменной окружения через Configmap, а взаимодействие происходит через компонент service в Kubernetes.

2. Состояние вне Kubernetes: эта конфигурация будет более централизованной. Все конфигурационные данные сервисов должны храниться в секретах и Configmaps в Kubernetes. Они будут передаваться как переменные окружения во время развёртывания в рабочей среде.

Источник

V. Сборка, выпуск, запуск

Строго разделяйте этапы сборки, выпуска и выполнения 

Сохраняйте чёткое разделение между этапами сборки, выпуска и выполнения. Многие организации предпочитают автоматизировать сборку, тестирование и продвижение рабочих нагрузок с помощью инструментов CI/CD. Конвейеры CI/CD обычно состоят из набора шагов (гейтов), которые выполняют определённые действия, объединённые в цепочку как часть жизненного цикла выпуска программного обеспечения.

Определите чётко обозначенные шаги в рамках рабочего процесса, и ни один конкретный шаг не должен выполнять более одной функции. Например, стандартный конвейер приложения может объединять различные шаги для сборки, тестирования, упаковки, архивирования, развёртывания и продвижения приложения в производственные среды.

1. Сборка: на этом этапе код извлекается и преобразуется в исполняемые файлы, такие как образ Docker или артефакт, которые должны храниться в репозиториях Artifactory, таких как Maven или Docker Hub, или в частном репозитории, например, Harbor.

2. Выпуск: на этом этапе к образу/Artifactory, созданному на предыдущем этапе, применяются конфигурации, хранящиеся в переменной окружения. Конфигурации и образ/Artifactory подготавливают сервисы к перемещению в среду развёртывания. Конфигурации хранятся в Kubernetes Configmap или секретах или переменных окружения. Обычно для среды развёртывания, такой как Kubernetes, в конвейере CI/CD можно использовать Helm в качестве инструмента выпуска и развёртывания.

3. Запуск: на этом этапе приложение, выпущенное на предыдущем этапе, запускается в среде развёртывания, такой как Kubernetes.

Источник

Разбив конвейер на набор последовательных задач, вы повышаете воспроизводимость, ответственность и уверенность в шагах, необходимых для перемещения приложения по жизненному циклу выпуска. Весь процесс является воспроизводимым, поэтому разработчики могут легко определить любые сбои в выпуске и получить более глубокое представление о шагах, необходимых для перехода от кода в системе контроля версий к приложению, обслуживающему производственный трафик.

В мире контейнеров конвейер должен только один раз собрать образ контейнера, а затем протестировать, продвинуть и развернуть образ в виде серии запущенных экземпляров контейнеров. Собрав только один раз, биты продвинутого контейнера будут идентичны в разных средах, что повышает уверенность в производственных развёртываниях и уменьшает различия между разными развёртываниями, если вы столкнётесь с необходимостью устранения неполадок.

VI. Процессы

Запускайте приложение как один или несколько stateless процессов

Контейнеры по своей природе эфемерны, то есть данные, хранящиеся внутри контейнера, исчезают, когда контейнер исчезает. В Kubernetes запросы пользователей обслуживаются с помощью подов. HPA контролирует количество подов или масштабирование пода. Количество подов в любой момент времени зависит от лимитов, определённых в HPA. Количество запущенных подов может варьироваться от 1 до N за секунды в зависимости от объёма трафика. Поэтому сохранение данных внутри подов — плохая идея.

Использование контейнеров заставляет разработчиков приложений искать новые способы хранить данные в своих приложениях, это могут быть базы данных или внешний кэш. Минимизация состояния в контейнеризованных рабочих нагрузках помогает обеспечить лёгкое масштабирование приложений вверх и вниз без влияния на пользовательский опыт.

Источник

VII. Привязка портов

Экспортируйте сервисы с привязкой к порту

Приложение, которое соответствует концепции Twelve-Factor App должно быть самодостаточным, чтобы принимать клиентские запросы на нужный порт. Все сервисы приложения будут привязаны и доступны через порт, который будет слушать входящие запросы.

В Kubernetes эта часть учитывается при разработке контейнеров. Контейнеры одних и тех же сервисов предоставляют один порт, на котором они слушают HTTP-запросы. Этот порт привязывается к сервисам Kubernetes, которые передают входящие запросы от сервисов Kubernetes базовым подам/контейнерам. Ниже приведена иллюстрация этого процесса.

Источник

Это пример докер-файла, в котором можно выставить порт.

FROM node:alpine
# Create app directory
WORKDIR /home/myappservices
# Install app dependencies
RUN npm install
EXPOSE 8090 ## Your pods will listern to this port
CMD [ "npm", "start" ]

Вот пример определения службы в Kubernetes:

kind: Service
apiVersion: v1
metadata:
  name: test-app-service
  namespace: example
  
spec:
  type: LoadBalancer
  selector:
    app: test-app-service
  ports:
    - name: http
      protocol: TCP
      port: 80 ### Port where K8s Services will listen to requests
      targetPort: 80  ## K8s Forward requests to Containers

VIII. Параллелизм

Масштабируйте приложение с помощью процессов

Kubernetes позволяет вам гарантировать, что определённое количество подов выполняется в любой момент времени с помощью различных контроллеров. Например, ReplicationControllers гарантирует, что нужное количество подов всегда будет запущено в кластере Kubernetes. Horizontal Pod Autoscaler (HPA) позволяет пользователям определять пороги ресурсов для масштабирования подов в зависимости от потребления CPU и памяти, а также максимальное и минимальное количество реплик, которые должны присутствовать на платформе в любой момент времени.

Эта диаграмма иллюстрирует масштабирование подов в соответствии с потоком трафика в Kubernetes для одного процесса или микросервиса:

Источник

IX. Утилизируемость

Максимизируйте надёжность с помощью быстрого запуска и корректного завершения работы

В этом факторе рассматривается, как должен запускаться и останавливаться процесс приложения. Процесс приложения должен запускаться быстро и устанавливать соединение со всеми внешними процессами (например, с базой данных и очередями) для поддержания надёжности.

Если процесс завершается аварийно, внешние соединения также должны немедленно разрываться. При этом должна происходить регистрация причины сбоя или аварийного завершения. Это даёт различные преимущества для приложения, такие как быстрое развёртывание кода, большая гибкость для процесса выпуска и надёжное производственное развёртывание.

Похоже, что этот принцип разработан для Kubernetes, поскольку в Kubernetes есть встроенная функция для развёртывания и HPA. Обе технологии позаботятся о бесшовном масштабировании и в то же время обеспечат надёжность подов.

Источник

X. Паритет разработки/работы приложения

Поддерживайте разработку, тестирование и производство как можно более похожими

Организации часто выбирают упаковку рабочих нагрузок в контейнеры для обеспечения мобильности. Когда вы собираете образ контейнера в одной среде, этот образ должен предсказуемо работать на любой инфраструктуре или среде, где вы его инициализируете, если в образ включено всё необходимое для запуска контейнера.

Конечно, всегда могут быть случаи небольшого расхождения сред, но один из лучших способов избежать этого — стандартизировать использование одной и той же версии Kubernetes во всех средах. Это обеспечивает пользователям контейнерной платформы единообразный опыт работы во всех средах с использованием этой платформы.

Какие могут быть расхождения:

  1. Временные: разработчик может работать над кодом, которому требуются дни, недели или даже месяцы для запуска в производство.

  2. Расхождения в персонале: разработчики пишут код, операционные инженеры его развертывают.

  3. Расхождения в инструментах: Разработчики могут использовать такие стеки, как Nginx, SQLite и OS X, в то время как в производственном развертывании используются Apache, MySQL и Linux.

DevOps Team должна спроектировать все среды (QA/Dev/Staging/Prod) с одним и тем же технологическим стеком, чтобы минимизировать эти разрывы. Однако конфигурация будет отличаться.

Предположим, что вы хотите развернуть в продакшене стабильную версию кода (назовём её V1), а в Dev-окружении для тестирования нужно внедрить новое функциональное требование (назовём его V2). CI/CD-пайплайн должен развернуть оба билда в соответствующих средах с применением отдельных конфигураций, как показано на рисунке ниже. Это требование Twelve-Factor App не имеет прямого отношения к Kubernetes, так как CI/CD легко справится с этой задачей.

Источник

XI. Журналирование

Рассматривайте логи как потоки событий

Журналы приложений критически важны для понимания того, как ведёт себя приложение во время работы. Когда организации переходят от развёртывания приложений на хосте к контейнеризованным приложениям, ведение и понимание логов может стать большой проблемой.

Количество подов, из которых состоит приложение, перемещается с хоста на хост, может масштабироваться вверх и вниз, и должно быть доступно и удобно для поиска командами и операторами, работающими с приложением. Многие организации уже имеют системы для агрегирования логов, такие как Splunk, для сбора, индексации и обеспечения поиска логов во многих системах через единую точку входа. Технологии вроде Splunk, отделённые от приложения, должны только знать, как получать логи для их сбора. Для этого убедитесь, что ваши контейнеризованные рабочие нагрузки записывают свои логи в STDOUT/STERR.

Многие современные библиотеки и фреймворки для приложений делают это автоматически, поскольку они адаптированы к этой практике. Таким образом, большая часть работы уже сделана за вас. Пока приложение пишет логи в стандартный вывод, бесплатные сборщики данных, такие как Fluentd, могут передавать их в базу данных, например Elastic, для хранения, анализа и архивирования.

Всю систему логирования можно настроить в кластере Kubernetes, как показано на рисунке ниже, и она будет безупречно выполнять свою работу.

Источник

XII. Задачи администрирования

Выполняйте задачи администрирования/управления с помощью разовых процессов

Некоторые задачи управления выполняются редко (например, заполнение базы данных) или периодически (резервное копирование базы данных) администратором рабочей нагрузки. Рассмотрите возможность реализации однократных задач, которые выполняются редко или через определённые промежутки времени как Jobs Kubernetes.

Возможно, вам потребуется инициализировать некоторые процессы управления на основе условий среды, таких как сложные процедуры восстановления после сбоев или перебалансировка ресурсов под нагрузкой. Распространённой архитектурой Kubernetes является шаблон Operator, в котором логика обработки этих условий реализуется в пользовательском контроллере, который работает на Kubernetes с вашей рабочей нагрузкой. Оператор непрерывно проверяет состояние системы и выполняет логику согласования, когда встречает предопределённые условия. Вы можете создавать операторы для последовательной обработки таких сложных задач управления с помощью инструмента Operator SDK.

Кроме того, админские процессы следует развёртывать так же, как и процессы приложения, описанные в предыдущих разделах, применяя все факторы, рассмотренные ранее, такие как релизы (фактор V), использование общей кодовой базы (фактор I) и конфигурации (фактор III). Админский код должен поставляться вместе с кодом приложения, чтобы избежать проблем с синхронизацией.

Источник

Выход за рамки Twelve-Factor App

Существуют определенные факторы, которые не включены в описанную выше методологию. Взгляните на них:

1. Телеметрия — это крайне важно при создании облачных приложений. Телеметрия включает в себя использование специального оборудования для проведения определённых измерений чего-либо и последующей передачи этих измерений в другое место с помощью радиосвязи. Здесь присутствует связь с удаленностью, дистанцией и неосязаемостью источника телеметрии.

Облачные приложения сильно отличаются от тех, что создаются на рабочей станции. У вас нет прямого доступа к облачному приложению, потому что оно может находиться за много километров от вас. Вы не можете просто ударить по нему молотком, чтобы заставить его работать правильно при возникновении проблем.

В таких ситуациях вам нужно знать, какая телеметрия вам нужна, нужно знать данные и удалённые средства управления, чтобы убедиться, что ваше приложение работает успешно.

2. Безопасность, аутентификация и авторизация — при создании облачных приложений легко игнорировать эти три фактора. Слишком часто разработчики фокусируются только на функциональных аспектах продукта. Ваше приложение должно быть защищено. Существуют такие инструменты, как OAuth2, OpenID Connect, различные серверы SSO и стандарты, включая бесчисленные библиотеки аутентификации и авторизации для конкретных языков. Безопасность — это первое, на чём вам следует сосредоточиться с первого же дня.

3. API First — когда вы создаёте приложение для облака, само собой разумеется, что ваш фокус должен быть на создании приложения, которое является участником экосистемы сервисов. Возможно, вы знаете о подходе mobile-first. Подобно этому, API First подразумевает, что вы строите API для использования клиентскими приложениями и сервисами.

Заключение

Twelve-Factor App для разработки приложений были сформулированы до того, как контейнеризация стала популярной. Kubernetes, контейнеры и облачные фреймворки для приложений развивались и стали основой для разработки приложений сегодня, но Twelve-Factor App всё ещё актуальны в современной среде. Если помнить о 12 факторах при разработке облачных приложений, то можно обеспечить их гибкость, масштабируемость и переносимость на годы вперёд.


Если вы только знакомитесь с Kubernetes, то приходите в Слёрм на курс Kubernetes: База. Это стартовый курс для администраторов, после которого вы будете знать его основные компоненты и абстракции, иметь опыт настройки кластера и запуска в нём приложений.

???? Полная программа

Попробуйте бесплатный демо-доступ к курсу по этой ссылке. Вы получите на три дня видеоуроки из первого модуля.

Когда вы полностью пройдете всю теорию и практику и успешно сдадите сертификацию, вы будете готовы к работе с Kubernetes в продакшене.

Комментарии (0)