Перейти к содержанию

Приложение двенадцати факторов — The Twelve-Factor App

В наши дни программное обеспечение обычно распространяется в виде сервисов, называемых веб-приложения (web apps) или software-as-a-service (SaaS). Приложение двенадцати факторов — это методология для создания SaaS-приложений, которые:

  • Используют декларативный формат для описания процесса установки и настройки, что сводит к минимуму затраты времени и ресурсов для новых разработчиков, подключённых к проекту;
  • Имеют соглашение с операционной системой, предполагающее максимальную переносимость между средами выполнения;
  • Подходят для развёртывания на современных облачных платформах, устраняя необходимость в серверах и системном администрировании;
  • Сводят к минимуму расхождения между средой разработки и средой выполнения, что позволяет использовать непрерывное развёртывание (continuous deployment) для максимальной гибкости;
  • И могут масштабироваться без существенных изменений в инструментах, архитектуре и практике разработки.

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

Двенадцать факторов

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

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

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

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

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

Сохраняйте конфигурацию в среде выполнения

IV. Сторонние службы (Backing Services)

Считайте сторонние службы (backing services) подключаемыми ресурсами

V. Сборка, релиз, выполнение

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

VI. Процессы

Запускайте приложение как один или несколько процессов не сохраняющих внутреннее состояние (stateless)

VII. Привязка портов (Port binding)

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

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

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

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

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

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

Держите окружения разработки, промежуточного развёртывания (staging) и рабочего развёртывания (production) максимально похожими

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

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

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

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

Коротко по пунктам

Одно приложение — один репозиторий

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

Если у вас несколько приложений используют общий код, то общий код надо выделить в отдельную библиотеку, и объявить ее как зависимость. Если на каком-нибудь этапе разработки, у вас в одном репозитории лежит несколько слабосвязанных приложений, то вы должны разделить приложение на несколько, каждое из которых должно быть 12-факторным приложением.

Явные зависимости

Приложения не должны иметь неявных зависимостей. Во-первых, все зависимости как системные, так и библиотеки должны быть прописаны в манифесте зависимостей. Все современные языки предоставляю менеджер пакетов с манифестом зависимостей. Кроме этого зависимости должны быть изолированные, чтобы системная библиотека «не просочилась» в приложений.

Так в Ruby использует Gemfile как формат манифеста для объявления зависимостей, bundle exec – для изоляции зависимостей. Кроме одинаковой работы приложения на разных платформах, это позволит новым разработчикам быстрее включаться в проект, или быстрее подключать новые зависимости.

Тут следует упомянуть Docker, который изолирует и явно объявляет даже зависти ОС.

Конфигурация — это свойства среды выполнения

Конфигурация — это все параметры, которые меняются в зависимости от того где запущено приложение:

  • логины, пароли и адреса баз данных;
  • сторонние сервисы и ключи АПИ.

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

Довольно популярный вариант – это использование заранее подготовленных наборов конфигурации (development, test и production). Такое разделение нельзя считать хорошим решением, так как добавление новых окружений (development-joe, qa, staging) непропорционально увеличивает количество параметров, которые надо поддерживать.

Локальные и сторонние службы

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

Замена локальной базы на Amazon RDS, или замена локального почтового сервера на сторонний, не должно влиять на код приложения.

Разделение сборки, релиза и выполнения

Развертывание приложения состоит из трех раздельных этапов:

  1. Сборка – это преобразование кода в исполняемый пакет — загрузка зависимостей, компиляция файлов и ресурсов.
  2. Релиз – объединение сборки с конфигурацией. Релиз сразу готов к запуску в среде исполнения.
  3. Выполнение – запуск некоторого количества процессов из релиза.

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

Приложение – набор процессов

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

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

Приложение не зависит от сервера

PHP-приложение может быть запущено как модуль внутри Apache HTTPD, или Java-приложение может быть запущено внутри Tomcat. Напротив, 12 факторное приложение — является полностью самодостаточным, и не полагается на наличие веб-сервера.

Это обычно реализуется с помощью объявления зависимости для добавления библиотеки веб-сервера к приложению такой, как Tornado в Python, Thin в Ruby, Jetty в Java и ReactPHP в PHP.

Масштаб с помощью процессов

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

Масштаб с помощью процессов

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

Быстрый запуск и корректное завершение

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

Фоновые процессы должны возвращать текущую задачу в очередь, а процессы обработки запросов корректно заканчивать запросы. Каждая задача любого процесса должна быть доступна для повторного выполнения (например, используя транзакции).

Приблизьте разработку к развертыванию

Приблизьте разработку к развертыванию

Сейчас между разработкой и развертыванием существует значительная разница — это делают разные люди, в разное время и разными инструментами. При внедрении 12 факторов надо стараться сделать разработку и развертывание как можно ближе:

  • Время – код должен попадать в рабочую версию через несколько часов после того, как разработчик его написал.
  • Люди – разработчик должен принимать участие в развертывание своего кода и следить за его работой в работе.
  • Инструменты – среда разработки должна максимально соответствовать среде тестирования (сторонние службы, ОС).

Логи в stdout

Лог — это поток событий, и надо обращаться к нему как к потоку событий. Приложение, не должно само записывать данные в файл логов, и тем более управлять файлами (архивировать или удалять).12 факторное приложение выводит лог своей работы в stdout. Менеджер, которой запускает процесс, должен направлять логии систему анализа или архивирования.

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

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

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

Разовые процессы администрирования (миграции, исправления базы) должны подчиняться тем же правилам, что и остальные процессы:

  • Код задач должен лежать в репозитории, чтобы соответствовать коду основного приложения
  • Зависимости должны быть объявлены в основном манифесте зависимостей, чтобы процесс мог быть выполнен при обычном развертывании
  • Конфигурация задачи должна находиться в переменных окружения, чтобы ее можно было выполнить в разных окружениях