Skip to content

12-Factor App

Розглянемо 12 принципів, які допоможуть створювати програмне забезпечення з правильними інженерними підходами ⬇️

First Factor

📄 Codebase. One codebase tracked in a version control system for each application. Multiple deploys of the same codebase should be possible.

На практиці твій додаток будуть розгортати у багатьох середовищах. І це має бути можливо зробити з тієї самої гілки. Контейнери дозволяють запускати один додаток багато разів, тобто на всіх середовищах буде одна кодова база.

Second Factor

📄 Dependencies. Explicitly declare and isolate dependencies.

Це принцип говорить про те, що ми повинні явно задавати наші залежності. У нашому випадку ми явно вказуємо всі залежності у файлі requirements.txt. Також сам Docker дозволяє «спакувати» всі залежності в один контейнер і зробити сам контейнер одиницею розгортання програмного продукту.

Third Factor

📄 Configs. Store config in the environment.

Усі конфігурації додатка потрібно виносити з самого додатку на рівень, наприклад, Docker-контейнера, щоб їх можна було легко змінити. Подивимось на прикладі файлу docker-compose і Python-додатка. Створимо нову змінну оточення, яку ми будемо читати та присвоїмо її connection string в конфігураціях SQLALCHEMY:

connectionString = os.environ.get("DB_CONNECTION","") app.config['SQLALCHEMY_DATABASE_URI'] = connectionString

Додамо нову змінну середовища вDockerfile:

ENV DB_CONNECTION="default"

І в docker-compose:

 pythonapp:
   image: app:1.2
   build:
     context: .
     dockerfile: Dockerfile.app
   ports:
     - "8080:8080"
   environment:
     - APP_ENV=Development
     - DB_CONNECTION=mysql+mysqlconnector://app_user:1234@my-sql/app_db

Таким чином, можна буде запускати той самий додаток у різних середовищах.

Forth Factor

📄 Backing services. Treat backing services as attached resources.

Під baking services маються на увазі допоміжні сервіси, що додаток споживає через мережу, як бази даних. Наприклад, можна замінити одну базу даних MySQL на іншу, і при цьому не зробивши жодних змін у коді самого додатка. У критичних ситуаціях це може пришвидшити розв'язання проблем на production-середовищі. У цьому нам все ще допомагає Docker — ми просто можемо запустити контейнер з існуючого Image з оновленим connection string через змінну середовища всередині контейнера.

Fifth Factor

📄 Build, release, run. Strictly separate build and run stages.

Твій код чи код команди фактично білдиться і пакується в Docker-контейнер — це і є етап build. Image є нашим release-кандидатом коду, який може бути одночасно розгорнутий на різних середовищах. Кожен реліз повинен мати унікальну назву, для цього можуть слугувати теги на Images. Зазвичай використовують так зване семантичне версіювання:

1.2.2
MAJOR.MINOR.PATCH
  • MAJOR змінюємо, коли робимо зміни у функціоналі чи API, які більше не є сумісними з попередніми версіями продукту.
  • MINOR змінюємо, коли додаємо новий функціонал, але старий функціонал працює як і раніше та є сумісними з попередньою версією продукту.
  • PATCH змінюємо, коли вносимо дрібні зміни чи фікси багів.

Sixth Factor

📄 Processes. Execute the app as one or more stateless processes.

Додаток не повинен нічого зберігати локально. Будь-які дані, якими треба ділитись з іншими сервісами, треба писати в допоміжні сервіси, наприклад, в базу даних. З цим нам теж допомагає Docker: контейнер уже інкапсулює в собі додаток як один сервіс, який не має стану, якщо ми явно не порушимо цей принцип. Читання файлів із локальної файлової системи не порушує цей принцип, а от запис нових файлів на довготривалий час — порушує.

Seventh Factor

📄 Port binding. Export services via port binding.

Додаток має бути самодостатнім і не має бути залежним від інших додатків. Наприклад, додаток не має залежати від стороннього вебсервера, такого як Apache HTTPD чи Tomcat. Обидва ці додатки — це сервери, які просто запускають інші додатки.

Додаток має вміти виставити свій порт, на якому він почне слухати запити на локальній машині. З цим теж допомагає робити Docker за допомогою команди:

docker run --name some-server -d -p 8080:8080 some_image:1.0.0

Eighth Factor

📄 Concurrency.

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

Ninth Factor

📄 Disposability.

Контейнери мають швидко запускатись та безпечно зупинятись або видалятись. Для безпечного завершення використовуй команду docker stop і для не дуже безпечного docker kill.

Tenth Factor

📄 Dev/Prod Parity. Keep development, staging, and production as similar as possible.

Середовища мають бути однаковими та мати однакові конфігурації. Зміни від розробників на спільне середовище потрібно деплоїти якомога частіше — найкраще одразу, як вони змерджені (merge) у гілку master. Також набір додатків, які ти використовуєш на різних середовищах, має бути однаковим. Тобто не потрібно на одному середовищі використовувати MySQL, а на іншому MSSQL.

На практиці з цим чудово справляється Docker: той самий Image на всіх середовищах!

Eleventh Factor

📄 Logs. Treat logs as event streams.

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

Docker дозволяє дивитись усі логи, які потрапляють до srdoutsdterrта централізовано їх зберігати.

Twelfth Factor

📄 Admin processes. Run admin/management tasks as one-off processes.

Якщо треба змінити схему бази даних (міграції схеми) або на старті додатка додати початкові дані в базу даних (database seeding), то використай для цього окремий Docker-контейнер.