Застосунок дванадцяти факторів
Застосунок дванадцяти факторів (англ. Twelve-Factor App, 12 factor) — це методологія для створення SaaS-застосунків, які:
- Використовують декларативний формат для автоматизації встановлення та налаштування, що зводить до мінімуму витрати часу і коштів для нових розробників, що приєднуються до проекту;
- Мають угоду з операційною системою, пропонуючи максимальну переносимість між середовищами виконання;
- Придатні для розгортання на сучасних хмарних платформах, що усуває необхідність у серверах та їх системному адмініструванні;
- Мінімізують різницю між середовищем розробки і production середовищем, що дозволяє безперервне розгортання для забезпечення максимальної спритності розробки (agility);
- Можуть масштабуватися без значних змін в інструментах, архітектурі і практиці розробки.
Цикл розробки програмного забезпечення |
---|
Програміст за роботою |
Діяльність і кроки |
Допоміжні дисципліни |
Практики |
Інструменти |
|
Стандарти та галузі знань |
Методологію дванадцяти факторів можна використати для застосунків, що написані будь-якою мовою програмування та використовують будь-яку комбінацію із сторонніх служб (бази даних, черги, кеш-пам’ять тощо).[1]
Дванадцять факторів
# | Фактор | Опис |
---|---|---|
I | Кодова база | Одна кодова база, що відслідковується в системі контролю версій та має багато розгортань. |
II | Залежності | Явно оголошуйте та ізолюйте залежності. |
III | Конфігурація | Зберігайте конфігурацію в середовищі виконання. |
IV | Сторонні служби | Вважайте сторонні служби (backing services) підключеними ресурсами. |
V | Збірка, реліз, виконання | Суворо відокремлюйте етапи збірки та виконання. |
VI | Процеси | Запускайте застосунок як один або декілька процесів без збереження внутрішньго стану (stateless). |
VII | Прив’язка портів | Експортуйте сервіси за допомогою прив’язки портів (port binding). |
VIII | Конкурентність | Масштабуйте застосунок за допомогою процесів |
IX | Утилізовуваність | Підвищуйте надійність за допомогою швидкого запуску і коректного вимкнення. |
X | Dev/prod паритет | Усі середовища (development, staging, production, тощо) мають бути максимально ідентичними між собою. |
XI | Журналювання | Сприймайте журналювання (logs) як потоки подій. |
XII | Задачі адміністрування | Виконуйте задачі адміністрування/керування за допомогою разових процесів. |
Детальний опис
I. Кодова база
Застосунок дванадцяти факторів завжди відслідковуються в системі контролю версій, такій як Git, Mercurial або Subversion. Копія бази даних відстеження ревізій називається репозиторій коду (code repository), що часто скорочується до code repo або просто repo.
Кодова база — це один репозиторій (в централізованих системах контролю версій, як Subversion), або декілька репозиторіїв, які мають спільний початковий комміт (в децентралізованих системах контролю версій, як Git).
Одна кодова база — багато розгортань
Завжди існує однозначна відповідність між кодовою базою і застосунком:
- За наявності кількох баз коду, це не застосунок, це — розподілена система. Кожен компонент в розподіленій системі є застосунком, і кожен з них може окремо дотримуватися дванадцяти факторів.
- Кілька різних застосунків, що спільно використовують загальну базу коду, є порушенням дванадцяти факторів. Рішенням в даній ситуації є виділення загального коду в бібліотеки, які можуть бути підключені через менеджер залежностей.
Існує тільки одна кодова база для кожного застосунку, але може бути багато розгортань одного і того самого застосунку. Розгортанням є запущений екземпляр застосунку. Це, як правило, production-сайт і один або більше staging-сайтів (проміжних розгортань). Крім того, розробник має копію застосунку, запущеного в його локальному середовищі розробки. Кожну з таких копій також можна кваліфікувати як розгортання.
Кодова база має бути єдина для всіх розгортань, хоча в кожному розгортанні можуть бути активні різні її версії. Наприклад, розробник може мати деякі зміни у коді, які ще не додані в staging-розгортання; staging-розгортання може мати деякі зміни, які ще не додані в production-розгортання. Але всі вони використовують одну і ту саму кодову базу, таким чином можна їх ідентифікувати як різні розгортання одного і того ж застосунку.
II. Залежності
Більшість мов програмування мають системи пакунків для розповсюдження бібліотек, такі як CPAN для Perl або Rubygems для Ruby. Бібліотеки, встановлені через систему пакунків, можуть бути доступними для всієї системи (так звані “site-packages”) або встановлені в каталог застосунку (так звані “vendoring” або “bundling”).
Застосунок дванадцяти факторів ніколи не залежить від неявно існуючих, досупних всій системі пакунків. Застосунок повно і точно вказує всі свої залежності за допомогою маніфесту оголошення залежностей. Крім того, він використовує інструмент ізоляції залежністей під час виконання, щоб гарантувати, що ніякі неявні залежності не “просочилися” з зовнішньої системи. Повна і явна специфікація залежностей використовується однаково як при розробці, так і в production.
Наприклад, Bundler в Ruby використовує Gemfile як формат маніфесту для оголошення залежностей і bundle exec для ізоляції залежностей. У Python є два окремі інструменти для цих задач - Pip використовується для оголошення і Virtualenv для ізоляції. Навіть C має Autoconf для оголошення залежностей, а статичне зв’язування може забезпечити ізоляцію залежностей. Який би не використовувався набір інструментів, оголошення і ізоляція залежностей завжди мають використовуватися разом — тільки одне або інше не є достатньою умовою для задоволення дванадцяти факторів.
Однією з переваг явного оголошення залежностей є те, що це спрощує налаштування застосунку для нових розробників. Новий розробник може скопіювати кодову базу застосунку на свою машину, необхідними вимогами для якої є тільки наявність середовища виконання мови програмування та наявність менеджера залежностей. Все необхідне для запуску коду застосунку може бути налаштоване за допомогою визначеної команди збірки. Наприклад, команда збірки для Ruby/Bundler є bundle install, а для Clojure/Leiningen це lein deps.
Застосунок дванадцяти факторів також ніколи не залежить від неявно існуючих будь-яких системних інструментів. Прикладом може бути запуск застосунком таких системних інструментів, як ImageMagick або curl. У той час, як ці інструменти можуть бути встановлені на багатьох або навіть більшості систем, немає жодної гарантії, що вони будуть встановлені на всіх системах, де застосунок може запускатися в майбутньому, або версія інструменту, встановлена в системі, буде сумісна з застосунком. Якщо застосунку потрібно запускати певні системні інструменти, то такі інструменти мають бути включені в сам застосунок.
III. Конфігурація
Конфігурація застосунку — це все, що може змінюватися між розгортаннями (staging-розгортання, production-розгортання, локальне середовище розробника тощо). Це включає:
- Параметри підключення до бази даних, Memcached і інших сторонніх сервісів;
- Реєстраційні дані для підключення до зовнішніх сервісів, таких як Amazon S3 або Twitter;
- Значення, що залежать від середовища розгортання, такі як канонічне ім’я хосту.
Застосунки іноді зберігають конфігурації як константи в коді. Це є порушенням методології дванадцяти факторів, яка вимагає обов’язкового відокремлення конфігурації від коду. Конфігурації застосунку в розгортаннях суттєво відрізняються, код — однаковий.
Лакмусовим папірцем того, чи правильно розділені конфігурація і код, є можливість в будь-який момент відкрити вихідний код застосунку у вільний доступ, при цьому не оприлюднюючи будь-яких приватних даних.
Визначення “конфігурації” не включає в себе внутрішні налаштування застосунку, такі як сonfig/routes.rb в Rails, або як пов’язані основні модулі в Spring. Ці налаштування не змінюються між розгортаннями, і тому краще місце для них — саме в коді.
Іншим підходом до конфігурації є використання конфігураційних файлів, що не зберігаються в систему контролю версій, таких як сonfig/database.yml в Rails. Це перевага у порівнянні з використанням констант в коді, але все ж таки має суттєві недоліки: є ймовірність помилково зберегти файл конфігурації в репозиторій; існує тенденція коли конфігураційні файли розкидані в різних місцях і в різних форматах, і стає важко передивлятися всі налаштування і керувати ними в одному місці. Крім того, формати цих файлів, як правило, специфічні для конкретної мови програмування чи фреймворку.
Застосунок дванадцяти факторів зберігає конфігурацію в змінних оточення (часто скорочується до env vars або env). Значення змінних оточення легко змінити між розгортаннями без зміни коду; на відміну від конфігураційних файлів, менш ймовірно випадково зберегти їх в репозиторій коду; і на відміну від конфігураційних файлів або інших механізмів конфігурації, таких як Java System Properties, вони є стандартом, незалежним від мови програмування чи фреймворку.
Іншим аспектом керування конфігурацією є групування. Іноді застосунки об’єднують конфігурації в іменовані групи (які часто називаються “оточеннями”), які називаються в залежності від конкретного розгортання, наприклад, development, test і production оточення в Rails. Цей метод погано масштабується: чим більше створюється різних розгортань застосунку, тим більше необхідно нових імен оточень, наприклад, staging або qa. При подальшому рості проекту розробники можуть додавати свої власні спеціальні оточення, наприклад, joes-staging, що призводить до комбінаторного вибуху конфігурації, який робить керування розгортанням застосунку нестабільним.
У застосунку дванадцяти факторів змінні оточення є незв’язаними між собою засобами керування. Кожна змінна повністю незалежна від інших. Вони ніколи не групуються разом в “оточення”, керування ними здійснюється незалежно для кожного розгортання. Ця модель добре масштабується разом з появою більшої кількості розгортань застосунку протягом його експлуатації.
IV. Сторонні служби
Стороння служба — це будь-яка служба, яка доступна застосунку по мережі і необхідна для його нормальної роботи: бази даних (наприклад, MySQL або CouchDB), системи черг повідомлень (наприклад, RabbitMQ або Beanstalkd), служби SMTP для вихідної пошти (наприклад, Postfix), системи кешування (наприклад, Memcached) тощо.
Допоміжні служби, такі як бази даних, традиційно управляються тими ж системними адміністраторами, які розгортають застосунок. Окрім локальних служб, застосунок може також використовувати служби, що надаються і керуються третіми сторонами: SMTP-сервіси (наприклад, Postmark), сервіси збору метрик (наприклад, New Relic або Loggly), сховища бінарних даних (наприклад, Amazon S3), а також різні сервіси, що надають доступ через API (наприклад, Twitter, Google Maps, або Last.fm).
Код застосунку дванадцяти факторів не бачить жодних відмінностей між локальними і сторонніми сервісами. Для застосунку кожен з них є підключеним ресурсом, доступним за URL-адресою або іншими даними, що зберігаються в конфігурації. Розгортання застосунку дванадцяти факторів повинно мати можливість, наприклад, замінити локальну базу даних MySQL на будь-яку керовану третьою стороною (наприклад, Amazon RDS) без жодних змін в коді застосунку. Крім того, локальний сервер SMTP може бути замінений на сторонній SMTP-сервіс (наприклад, Postmark) без зміни коду. В обох випадках необхідно змінити лише налаштування відповідного ресурсу в конфігурації застосунку.
Кожна окрема стороння служба є ресурсом. Наприклад, база даних MySQL є ресурсом; дві бази даних MySQL (що використовуються для шардінгу на рівні застосунку) кваліфікуються як два різних ресурси. Застосунок дванадцяти факторів сприймає ці бази даних як підключені ресурси, що вказує на їхній слабкий зв’язок з розгортанням, в якому вони підключені.
Ресурси за необхідності можуть бути підключені та відключені до розгортання застосунку. Наприклад, якщо база даних застосунку функціонує некорекно у зв’язку з апаратними проблемами, адміністратор може запустити новий сервер бази даних, відновленої з останньої резервної копії. Поточна база даних може бути відключена, а нова база даних підключена — все це без будь-яких змін коду.
V. Збірка, реліз, виконання
Кодова база перетворюється в розгортання (крім розгортання для розробки) у три етапи:
- Етап збірки — це трансформація, яка перетворює код в репозиторії у пакунок, що може бути запущений, і який називається збірка. Використовуючи версію коду за вказаним у процесі розгортання коммітом, етап збірки завантажує залежності та компілює бінарні файли і ресурси.
- Етап релізу приймає збірку, отриману на етапі збірки, і об’єднує її з поточною конфігурацією розгортання. Отриманий реліз містить збірку і конфігурацію і готовий до негайного запуску в середовищі виконання.
- Етап виконання запускає застосунок у середовищі виконання, увімкнувши деякий набір процесів застосунку з певного релізу.
Код стає збіркою, яка поєднується з конфігурацією для створення релізу.
Застосунок дванадцяти факторів дотримується суворого відокремлення етапів збірки, релізу і виконання. Наприклад, не можна вносити зміни в код під час етапу виконання, оскільки немає способу поширити ці зміни назад на етап збірки.
Інструменти розгортання, як правило, надають засоби керування релізами, які дають можливість відкату до попередньої версії. Наприклад, інструмент розгортання Capistrano зберігає релізи в підкаталог з назвою releases, де поточний реліз є символічним посиланням на каталог поточного релізу. Команда Capistrano rollback дає можливість швидко виконати відкат до попередньої версії.
Кожен реліз повинен завжди мати унікальний ідентифікатор, наприклад, мітку часу релізу (наприклад, 2011-04-06-20:32:17) або номер, що зростає (наприклад, v100). Релізи можуть тільки додаватися, неможливо змінити реліз після його створення. Будь-які зміни мають створювати новий реліз.
Збірка ініцюється розробником застосунку щоразу при розгортанні нового коду. Запуск етапу виконання, навпаки, може відбуватися автоматично в таких випадках, як перезавантаження сервера або перезапуск процесу, що впав, менеджером процесів. Таким чином, етап виконання має бути максимально технічно простим, бо проблеми, які заважають застосунку запуститися, можуть призвести до його зупинки посеред ночі, коли розробників немає на місці. Етап збірки може бути більш складним, бо можливі помилки завжди видимі розробнику, який запустив процес розгортання.
VI. Процеси
Застосунок запускається в середовищі виконання у вигляді одного або декількох процесів.
У найпростішому випадку код є окремим скриптом, середовище виконання — ноутбук розробника зі встановленим середовищем виконання мови програмування, а процес запускається за допомогою командного рядка (наприклад, python my_script.py). В іншому випадку, це може бути production-розгортання складного застосунку, яке може використовувати багато типів процесів, кожен з яких запущений у необхідній кількості екземплярів.
Процеси застосунку дванадцяти факторів не зберігають внутрішній стан (stateless) і не розділяють ресурси. Будь-які дані, що підлягають збереженню, мають зберігатися в сторонній службі зі збереженням внутрішнього стану (stateful) (як правило, в базі даних).
Пам’ять та файлова система процесу можуть бути використані як короткостроковий кеш. Наприклад, завантаження, обробка і збереження великого файлу в базі даних. Застосунок дванадцяти факторів ніколи не припускає, що щось, закешоване в пам’яті або на диску, буде доступне при наступному запиті — за наявності багатьох запущених процесів різних типів є велика ймовірність, що наступний запит буде оброблений іншим процесом. Навіть при роботі тільки одного процесу перезапуск (викликаний розгортанням, змінами конфігурації або переміщенням процесу в інше фізичне місце розташування середовищем виконання), як правило, призведе до знищення всіх локальних (у пам’яті і файловій системі) станів.
Пакувальники ресурсів (наприклад, Jammit або django-compressor) використовують файлову систему як кеш для скомпільованих ресурсів. Застосунок дванадцяти факторів надає перевагу здійсненню такої компіляції під час етапу збірки, наприклад, як в Rails asset pipeline, а не під час виконання.
Деякі веб-системи покладаються на “липкі сесії” — тобто кешують дані сесії користувача в пам’яті процесу застосунку і очікують, що наступні запити від того ж самого користувача будуть спрямовані до того ж самого процесу. Липкі сесії є порушенням дванадцяти факторів і їх ніколи не слід використовувати та покладатися на них. Дані сесії користувача є хорошим кандидатом для сховища даних, яке надає функцію обмеження терміну зберігання, наприклад, Memcached або Redis.
VII. Прив’язка портів
Вебзастосунки іноді запускаються всередині контейнера веб-сервера. Наприклад, PHP-застосунок може бути запущений як модуль всередині веб-сервера, або Java-застосунок може бути запущений всередині Apache Tomcat.
Застосунок дванадцяти факторів є повністю автономним і в процесі виконання, щоб створити веб-сервіс, доступний через web, не покладається на ін’єкцію[що це?] веб-сервера в середовище виконання. Вебзастосунок експортує HTTP-сервіс шляхом прив’язки до порту і прослуховує запити, що надходять на цей порт.
У локальному development середовищі розробник відвідує URL-адресу вигляду http://localhost:5000/ для доступу до сервісу, що експортується застосунком. При розгортанні рівень маршрутизації обробляє запити до загальнодоступного хосту і перенаправляє їх до порту, до якого прив’язано веб-процес.
Як правило, це реалізується за допомогою оголошення залежностей шляхом додавання бібліотеки веб-сервера до застосунку, наприклад, Tornado для Python, Thin для Ruby або Jetty для Java та інших мов на основі JVM. Це відбувається повністю в просторі користувача, тобто в коді застосунку. Прив’язка до порту для обробки запитів є “угодою” із середовищем виконання.
HTTP — не єдиний сервіс, який може бути експортований шляхом прив’язки до порту. Майже будь-який вид серверного програмного забезпечення може бути запущений, прив’язаний до порту і може очікувати вхідні запити. Прикладами є ejabberd (використовує XMPP) і Redis (використовує протокол Redis).
Також зверніть увагу, що підхід прив’язки до портів означає, що застосунок може виступати як стороння служба для іншого застосунку, надаючи свою URL-адресу як ресурс в конфігурації застосунку-споживача.
VIII. Конкурентність
Будь-яка комп’ютерна програма після запуску представлена одним або декількома процесами. Вебдодатки мають різні форми виконання процесів. Наприклад, PHP-процеси виконуються як дочірні процеси Apache, які запускаються в разі потреби в залежності від навантаження. Java-процеси використовують протилежний підхід: JVM забезпечує один масивний мета-процес, який резервує велику кількість системних ресурсів (процесора і пам’яті) під час його запуску, і керує конкурентністю всередині себе за допомогою потоків виконання (threads). В обох випадках запущені процеси видимі для розробників застосунку мінімально.
Масштабування виражається у вигляді запущених процесів, різноманітність навантаження виражається в типах процесів.
В застосунку дванадцяти факторів, процеси є сутностями першого класу. Процеси в застосунку дванадцяти факторів взяли сильні сторони від моделі процесів UNIX для запуску сервісів. Використовуючи цю модель, розробник може спроектувати свій застосунок таким чином, що для обробки різних робочих навантажень необхідно призначити кожному виду робіт свій тип процесу. Наприклад, HTTP-запити можуть бути оброблені за допомогою веб-процесу (web process), а тривалі фонові завдання оброблені робочим процесом (worker process).
Це не виключає можливості використання індивідуального мультиплексування для окремих процесів через потоки виконання віртуальної машини або асинхронні/подієві моделі в таких інструментах, як EventMachine, Twisted або Node.js. Але індивідуальна віртуальна машина може масшабуватися тільки обмежено (вертикальне масшабування), тому застосунок також повинен мати можливість бути запущеним як декілька процесів на декількох фізичних машинах.
Модель, побудована на процесах, дійсно показує себе з найкращого боку, коли постає необхідність масштабування. Відсутність розділених даних і горизонтальне розділення процесів застосунку дванадцяти факторів означає, що додавання більшої конкурентності є простою і надійною операцією. Масив типів процесів і кількість процесів кожного типу називається формацією процесів.
Процеси застосунку дванадцяти факторів ніколи не мають демонізуватися та записувати PID-файли. Замість цього вони мають покладатися на менеджер процесів операційної системи (наприклад, systemd, розподілений менеджер процесів на хмарній платформі, або в процесі розробки на такий інструмент, як Foreman) для керування потоком виведення, реагування на падіння процесів і обробку ініційованих користувачем перезавантаження чи завершення роботи.
IX. Утилізовуваність
Процеси застосунку дванадцяти факторів є утилізовуваними, тобто вони можуть бути запущені або зупинені в будь-який момент. Це сприяє гнучкому масштабуванню, швидкому розгортанню коду або змінам конфігурації і надійності production-розгортання.
Слід намагатися мінімізувати час запуску процесів. В ідеалі час між моментом виконання команди запуску процесу і моментом, коли процес готовий приймати запити чи задачі, має тривати лише пару секунд. Короткий час запуску забезпечує більшу гнучкість для релізу і масштабування. Крім того, це підвищує стійкість, оскільки менеджер процесів може легко переміщувати процеси на нові фізичні машини у разі необхідності.
Процеси мають коректно завершувати свою роботу, коли вони отримують SIGTERM сигнал від диспетчеру процесів. Для веб-процесу коректне завершення роботи досягається завдяки припиненню прослуховування порту, до якого він прив’язаний (що означає відмову від отримання будь-яких нових запитів), завершенню обробки будь-яких поточних запитів та зупинці самого процесу. В цій моделі передбачається, що HTTP-запити короткі (не більше ніж кілька секунд), а у разі довгих запитів (long polling) клієнт має намагатися відновити з’єднання у разі його втрати.
Для процесу, що виконує фонові задачі (worker), коректне завершення роботи досягається за рахунок повернення поточного завдання назад у чергу задач. Наприклад, в RabbitMQ робочий процес може надіслати команду NACK; в Beanstalkd завдання повертається в чергу автоматично щоразу, коли процес втрачає з’єднання. Системи, що використовують блокування, такі як Delayed Job, мають бути повідомлені, щоб звільнити блокування задачі. В цій моделі передбачається, що всі задачі є повторно вхідними, що зазвичай досягається шляхом обертання результатів їхньої роботи в транзакції або шляхом використання ідемпотентних операцій.
Процеси також мають бути стійкі до раптової зупинки в разі відмови апаратних засобів, на яких вони запущені. Хоча це менш ймовірна подія, ніж коректне завершення роботи за допомогою сигналу SIGTERM, вона все ж таки може статися. Рекомендованим підходом є використання надійних черг завдань, таких як Beanstalkd, які повертають завдання в чергу задач, коли клієнти втрачають з’єднання або від’єднуються по тайм-ауту. У будь-якому випадку, застосунок дванадцяти факторів має проектуватися таким чином, щоб обробляти несподівані та некоректні вимкнення. Прикладом вдалої реалізації архітектури “тільки аварійного вимкнення” (Crash-only design) є СouchDB.
X. Dev/prod паритет
Історично склалося, що є суттєві відмінності між development середовищем (розробник вносить живі зміни в локально розгорнутий застосунок) і production середовищем (до якого мають доступ кінцеві користувачі). Ці відмінності проявляються в трьох областях:
- Різниця в часі: Розробник може працювати над кодом, який потрапить у production через дні, тижні або навіть місяці;
- Різниця в персоналі: Розробники пишуть код, Ops-інженери розгортають його;
- Різниця в інструментах: Розробники можуть використовувати стек технологій такий, як Nginx, SQLite та OS X, в той час як на production використовується Apache, MySQL та Linux.
Застосунок дванадцяти факторів проектується для безперервного розгортання, завдяки мінімізації різниці між production і development середовищами. Розглянемо три відмінності, описані вище:
- Зменшити різницю в часі: розробник може написати код і він буде розгорнутий через декілька годин або навіть хвилин;
- Зменшити різницю в персоналі: розробники, які писали код, беруть активну участь в його розгортанні і спостерігають за його поведінкою на production;
- Зменшити різницю в інструментах: тримати development та production середовища максимально ідентичними.
Резюмуючи сказане вище в таблицю:
Традиційний застосунок | Застосунок дванадцяти факторів | |
---|---|---|
Час між розгортаннями | Тижні | Години |
Автор коду/той хто розгортає | Різні люди | Ті ж люди |
Dev/Prod розгортання | Різні | Максимально ідентичні |
Сторонні служби, такі як бази даних, системи черг повідомлень або кеш, є однією з областей, де dev/prod паритет має важливе значення. Багато мов програмування мають бібліотеки, які спрощують доступ до сторонніх служб, в тому числі, адаптери для різних видів сервісів. Деякі приклади наведені в таблиці нижче.
Тип | Мова | Бібліотека | Адаптери |
---|---|---|---|
База даних | Ruby/Rails | ActiveRecord | MySQL, PostgreSQL, SQLite |
Черга повідомлень | Python/Django | Celery | RabbitMQ, Beanstalkd, Redis |
Кеш | Ruby/Rails | ActiveSupport::Cache | Пам'ять, файлова система, Memcached |
Іноді розробники бачать переваги у використанні “легких” сторонніх служб в їхньому локальному середовищі, в той час як більш серйозні і надійні сторонні служби будуть використовуватися у production. Наприклад, локально використовують SQLite, а на production PostgreSQL; або локально пам’ять процесу для кешування, а на production Memcached.
Розробник застосунку дванадцяти факторів уникає використання різних сторонніх служб в development і production середовищах, навіть якщо адаптери теоретично абстраговані від будь-яких відмінностей у сторонніх службах. Відмінності між сторонніми службами означають, що може виникнути крихітна несумісність, в результаті чого код, який працював і пройшов тестування в development та staging середовищах, після розгортання не працює в production середовищі. Такий тип помилок створює перешкоди, які нівелюють переваги безперервного розгортання. Ціна цих перешкод і подальшого відновлення безперервного розгортання надзвичайно висока, якщо розглядати в сукупності за весь час експлуатації застосунку.
Встановлення локально “легких” сторонніх сервісів вже не є таким привабливим, як було раніше. Сучасні надійні сторонні сервіси, такі як Memcached, PostgreSQL і RabbitMQ, досить легко встановити і запустити завдяки сучасним менеджерам пакунків, таким як Homebrew і apt-get. Крім того, декларативні інструменти підготовки середовища, такі як Chef і Puppet, у поєднанні з “легким” віртуальним середовищем, таким як Vagrant, дозволяють розробникам запускати локальні середовища, які наближені до production. Ціна встановлення і використання цих систем є низькою у порівнянні з користю dev/prod паритету і безперервного розгортання.
Адаптери для різних сторонніх сервісів все ж корисні, тому що вони роблять перенесення застосунку для використання з іншими сторонніми сервісами відносно безболісним. Але всі розгортання застосунку (development, staging та production середовища) мають використовувати один і той самий тип і версію кожного зі сторонніх сервісів.
XI. Журналювання
Журналювання забезпечує наочне уявлення про поведінку запущеного застосунку. Зазвичай у серверних середовищах журнали записуються у файл на диску (“logfile”), але це лише один з форматів виведення.
Журнал — це потік агрегованих, впорядкованих за часом подій, зібраних з потоків виведення всіх запущених процесів і сторонніх сервісів. Журнал в сирому вигляді, як правило, має текстовий формат з однією подією на кожен рядок (хоча трасування винятків можуть займати кілька рядків). Журнали не мають фіксованого початку і кінця, потік безперервний поки працює застосунок.
Застосунок дванадцяти факторів ніколи не займається маршрутизацію і зберіганням свого потоку виведення. Застосунок не повинен записувати журнал у файл або керувати файлами журналів. Замість цього кожен запущений процес записує свій потік подій без буферизації в стандартне виведення stdout. В development середовищі розробник має можливість переглядати цей потік в терміналі, щоб спостерігати за поведінкою застосунку.
В staging та production розгортаннях потік виведення кожного процесу перехоплюється середовищем виконання, збирається разом з усіма іншими потоками виведення застосунку і спрямовується до одного або кількох кінцевих пунктів призначення для перегляду і довгострокового архівування. Ці кінцеві пункти призначення не видимі для застосунку і не налаштовуються ним, вони керуються середовищем виконання. Для цього можуть бути використані маршрутизатори журналів з відкритим вихідним кодом (наприклад, Logplex та Fluentd).
Потік подій застосунку може бути направлений у файл або переглянутий у терміналі в режимі реального часу. Найважливішим є те, що потік може бути направлений у систему індексування і аналізу журналів, таку як Splunk, або систему зберігання даних загального призначення, таку як Hadoop/Hive. Ці системи мають широкі можливості і гнучкість для детального аналізу поведінки застосунку протягом тривалого часу, в тому числі:
- Виявлення конкретних подій у минулому;
- Побудова графіків трендів (наприклад, кількість запитів за хвилину);
- Активне оповіщення відповідно до визначених користувачем евристичних правил (наприклад, попередження, коли кількість помилок за хвилину перевищує певний поріг).
XII. Задачі адміністрування
Формація процесів є певним набором процесів, які необхідні для виконання регулярних задач застосунку (наприклад, обробка веб-запитів). Разом з тим, розробникам часто необхідно виконувати разові адміністративні задачі для обслуговування застосунку, такі як:
Запуск міграції бази даних (наприклад, manage.py migrate в Django, rake db:migrate в Rails). Запуск консолі (REPL) для виконання довільного коду або перевірки моделі застосунку на діючій базі даних. Більшість мов надають REPL шляхом запуску інтерпретатора без будь-яких аргументів (наприклад, python або perl) або в деяких випадках мають окрему команду (наприклад, irb для Ruby, rails console для Rails). Запуск разових скриптів, збережених в репозиторії застосунку (наприклад, php scripts/fix_bad_records.php). Разові процеси адміністрування слід запускати в такому ж середовищі, в якому запущені регулярні тривалі процеси застосунку. Вони запускаються на базі релізу, використовуючи ту ж кодову базу і конфігурацію, як і будь-який інший процес на базі цього релізу. Для уникнення проблем з синхронізацією код адміністрування має поставлятися з кодом застосунку.
Для всіх типів процесів мають використовуватися однакові методи ізоляції залежностей. Наприклад, якщо веб-процес Ruby використовує команду bundle exec thin start, то для міграції бази даних слід використовувати bundle exec rake db:migrate. Аналогічно, для програми на Python з Virtualenv слід використовувати bin/python як для запуску веб-сервера Tornado, так і для запуску будь-яких manage.py процесів адміністрування.
Методологія дванадцяти факторів надає перевагу мовам, які мають REPL “з коробки”, і які дозволяють легко запускати разові скрипти. У локальному development середовищі розробник може запустити процес адміністрування за допомогою консольної команди всередині директорії застосунку. У production середовищі для запуску такого процесу розробники можуть використовувати ssh або інший механізм віддаленого виконання команд, що надається середовищем виконання.
За межами дванадцяти факторів
Існують розширення оригінальної методології дванадцяти факторів для побудови ситем призначених для розгортання в хмарному середовищі, так званих cloud-native систем. До дванадцяти оригінальних факторів додаються ще три: Телеметрія, Безпека і концепція "Спочатку API".[2]
Спочатку API
Цей фактор визначає, що той продукт, що розробляється, являє собою API який, в свою чергу, має клієнтів, тобто використовується іншими застосунками чи сервісами. Наприклад, той же графічний інтерфейс, чи то мобільний, чи веб, є нічим іншим ніж просто споживачем якогось API. Підхід "Спочатку API" є важливою складовою розробки нативних хмарних (cloud-native) систем і застосунків які базуються на мікросервісній чи сервіс-орієнтовній архітектурі. Існує безліч інструментів і стандартів для підтримки розробки в стилі "Спочатку API". Наприклад, стандартний формат для специфікацій API, що використувує розмітковий синтакс API Blueprint. Цей формат є більш прочитним ніж JSON чи WSDL і може бути використаний кодом для генерування документації, або, навіть, для створення серверних моків. В той же час, набір інструментів на кшталт Apiary надає можливості такі як інтеграція з GitHub і генерування моків. Наприклад, якщо є необхідність в створенні клієнта для API - все що треба це надати посилання Apiary де вона зможе прочитати API Blueprint, побачити приклад коду для споживання даного API і, навіть, виконати запити на запущенний мок.
Телеметрія
Розгортання застосунку на локальній машині дає змогу спостерігати що відбувається всередині запущеної системи, зневаджувати та використовувати сотні інструментів що дають змогу зазирнути в глибини застосунку. Але системи які розгорнуті в хмарному середовищі не надають таких можливостей. Тому дуже важливо мати інструменти які дозволять віддалено моніторити стан системи в хмарі. Виділяють кілька категорій даних для відслідковування:
- Моніторинг продуктивності
- Доменно-специфічна телеметрія
- Здоров'я та системні журнали
Аутентифікація та авторизація
Оригінальна концепція дванадцяти факторів не говорить нічого про безпеку, яка є життєво важливим елементом будь-якого застосунку чи хмарного середовища. Сloud-native система завжди повинна бути безпечною та захищеною системою. В ідеальному світі всі запити до застосунку мають бути захищені контролем доступу за ролями (role-based access control). Застосунок повинен "знати" від кого прийшов запит і які ролі має цей споживач. Ці ролі диктують чи має цей клієнт доступ до даного функціоналу чи інформації чи ні. За допомогою таких інструментів як OAuth2, OpenID Connect, різноманітні SSO сервери і стандарти, бібліотеки авторизації і аутентифікації, безпека має бути чимось що народжується в перший же день розробки проекту і не повинна бути чимось що прикручується в продакшені.
Посилання
- Wiggins, Adam. The Twelve-Factor App (Переклад українською). 12factor.net (англ.). Процитовано 30 січня 2018.
- Hoffman, Kevin (2016). Beyond the Twelve-Factor App (English). Beijing Boston Farnham Sebastopol Tokyo: O’Reilly Media, Inc. ISBN 978-1-491-94401-1.