X. Dev/prod паритет
Прагніть максимальної ідентичності development, staging та production середовищ
Історично склалося, що є суттєві відмінності між 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 середовища) мають використовувати один і той самий тип і версію кожного зі сторонніх сервісів.