5 принципів здорового глузду для створення cloud-native apps

"Хмарно-орієнтовані" (cloud native) або просто "хмарні" програми створюються спеціально для роботи в хмарних інфраструктурах. Зазвичай вони будуються як набір слабко пов'язаних мікросервісів, упакованих у контейнери, які, у свою чергу, керуються хмарною платформою. Такі додатки за замовчуванням готові до збоїв, а отже, надійно працюють і масштабуються навіть при серйозних відмових інфраструктурного рівня. Зворотний бік медалі – набори обмежень (контракти), які хмарна платформа накладає на контейнерні програми, щоб мати можливість керувати ними в автоматичному режимі.

5 принципів здорового глузду для створення cloud-native apps

Прекрасно усвідомлюючи необхідність і важливість переходу на хмарні програми, багато організацій все ще не знають, з чого почати. У цьому пості ми розглянемо низку принципів, дотримання яких при розробці контейнерних додатків дозволить реалізувати потенціал хмарних платформ і досягти надійної роботи та масштабування додатків навіть за серйозних відмов на рівні ІТ-інфраструктури. Кінцева мета викладених тут принципів – навчитися створювати програми, які можуть автоматично керуватися хмарними платформами, такими як Kubernetes.

Принципи проектування програмного забезпечення

У світі програмування під принципами розуміються досить загальні правила, яких необхідно дотримуватися розробки ПЗ. Їх можна застосовувати під час роботи з будь-якою мовою програмування. Кожен принцип має свої цілі, інструментом досягнення яких зазвичай служать шаблони і практики. Також існує низка фундаментальних принципів створення якісного софту, з яких випливають усі інші. Наведемо приклади фундаментальних принципів:

  • ПОЦІЛУНОК (Keep it simple, stupid) – не ускладнювати;
  • СУХИЙ (Don't repeat yourself) – не повторюватися;
  • ЯГНІ (You aren't gonna need it) - не створювати те, в чому немає безпосередньої потреби;
  • SoC (Separation of concerns) – поділяти відповідальності.

Як видно, ці принципи не задають жодних конкретних правил, а належать до розряду так званих міркувань здорового глузду на основі практичного досвіду, які поділяють багато розробників і на які вони регулярно посилаються.
Крім того, існує SOLID - Набір з перших п'яти принципів об'єктно-орієнтованого програмування та проектування, сформульованих Робертом Мартіном. SOLID включає узагальнені та відкриті для трактування взаємодоповнюючі принципи, які – якщо застосовувати їх у комплексі – допомагають створювати якісніші програмні системи та краще підтримувати їх у довгостроковій перспективі.

Принципи SOLID відносяться до сфери ОВП та формулюються мовою таких понять та концепцій, як класи, інтерфейси та успадкування. За аналогією, для хмарних програм теж можна сформулювати принципи розробки, тільки базовим елементом тут буде не клас, а контейнер. Дотримуючись цих принципів, можна створювати контейнерні програми, які краще відповідають цілям і завданням хмарних платформ на кшталт Kubernetes.

Хмарно-орієнтовані контейнери: Red Hat

Сьогодні в контейнери можна відносно легко запакувати практично будь-яку програму. Але для того, щоб програми ефективно автоматизувалися та оркеструвалися в рамках хмарної платформи типу Kubernetes, потрібно докласти додаткових зусиль.
Основою для наведених нижче ідей послужила методологія Додаток дванадцяти факторів та безліч інших робіт з різних аспектів створення веб-додатків, від керування вихідним кодом до моделей масштабування. Описувані принципи стосуються тільки розробки контейнерних додатків, які побудовані на основі мікросервісів і призначені для хмарних платформ, таких як Kubernetes. Базовим елементом у наших міркуваннях є образ контейнера, а під цільовим середовищем виконання контейнерів розуміється платформа оркестрації контейнерів. Мета запропонованих принципів полягає в тому, щоб створювати контейнери, для яких на більшості платформ оркестрації можна автоматизувати завдання диспетчеризації (scheduling – вибір хоста для запуску екземпляра контейнера), масштабування та моніторингу. Принципи викладаються у довільному порядку.

Принцип єдиної задачі (Single Concern Principle, SCP)

Цей принцип схожий на принцип єдиної відповідальності (Single Responsibility Principle, SRP), який входить до набору SOLID і свідчить, що кожен об'єкт повинен мати один обов'язок, і цей обов'язок має бути повністю інкапсульований у клас. Суть SRP у тому, що кожен обов'язок – це причина змін, а клас повинен мати одну і лише одну причину зміни.

В SCP замість слова "відповідальність" (responsibility) ми використовуємо слово "завдання" (concern), щоб вказати на більш високий рівень абстракції та ширше призначення контейнера порівняно з ООП-класом. І якщо мета SRP – мати лише одну причину для змін, то за SCP стоїть бажання розширити можливості повторного використання та заміни контейнерів. Наслідуючи SRP і створюючи контейнер, який вирішує одне єдине завдання і робить це функціонально закінченим чином, ви підвищуєте шанси на повторне використання образу цього контейнера в різних контекстах програми.

Принцип SCP свідчить, що кожен контейнер повинен вирішувати одне завдання і робити це добре. Причому, SCP у світі контейнерів досягається простіше, ніж SRP у світі ООП, оскільки контейнери зазвичай виконують один єдиний процес, і більшу частину часу цей процес вирішує єдине завдання.

Якщо якийсь контейнерний мікросервіс повинен вирішувати відразу кілька завдань, його можна розбити на однозадачные контейнери і об'єднати в рамках одного pod-а (одиниці розгортання контейнерної платформи) з допомогою шаблонів sidecar і init-контейнерів. Крім того, SCP полегшує заміну старого контейнера (наприклад, веб-сервера або брокера повідомлень) на новий, який вирішує ту саму задачу, але має розширену функціональність або краще масштабується.

5 принципів здорового глузду для створення cloud-native apps

Принцип зручності моніторингу (HOP)

При використанні контейнерів як уніфікований спосіб упаковки та запуску додатків самі програми розглядаються як «чорна скринька». Однак, якщо це хмарні контейнери, то вони повинні надавати середовищу виконання спеціальні API-інтерфейси, щоб контролювати справність контейнерів та при необхідності вживати відповідних заходів. Без цього не вдасться уніфікувати автоматизацію оновлення контейнерів та керування їх життєвим циклом, що, у свою чергу, погіршить стійкість та зручність використання програмної системи.

5 принципів здорового глузду для створення cloud-native apps
На практиці контейнерний додаток повинен, як мінімум, мати API для різних типів перевірок справності: тестів на активність (liveness) та тестів на готовність (readiness). Якщо додаток претендує на більше, то має надавати інші засоби контролю свого стану. Наприклад, реєстрацію важливих подій через STDERR та STDOUT для агрегування журналів за допомогою Fluentd, Logstash та інших подібних інструментів. А також інтеграцію з бібліотеками трасування та збору метрик, такими як OpenTracing, Prometheus тощо.

Загалом, додаток можна як і розглядати як «чорний ящик», але його треба забезпечити всіма API, які необхідні платформі у тому, щоб моніторити і керувати ним найкраще.

Принцип підстроювання до життєвого циклу (Life-cycle Conformance Principle, LCP)

LCP – це антитеза HOP. Якщо HOP говорить, що контейнер повинен надавати платформі API-інтерфейси для читання, то LCP вимагає від застосування можливості сприймати інформацію від платформи. Причому контейнер повинен не тільки отримувати події, а й підлаштовуватися, інакше кажучи, реагувати на них. Звідси і назва принципу, який можна розглядати як вимогу надавати платформі API-інтерфейсів для запису.

5 принципів здорового глузду для створення cloud-native apps
У платформ є різні типи подій, які допомагають керувати життєвим циклом контейнера. Але вирішувати, які з них сприймати і як реагувати, має сам додаток.

Зрозуміло, що одні події важливіші за інші. Наприклад, якщо додаток погано переносить аварійне завершення роботи, воно зобов'язане приймати повідомлення signal: terminate (SIGTERM) і якнайшвидше ініціювати свою процедуру завершення, щоб встигнути до надходження signal: kill (SIGKILL), що йде після SIGTERM.

Крім того, для життєвого циклу програми можуть бути важливими такі події, як PostStart і PreStop. Наприклад, після запуску додатку може бути потрібний певний час на «прогрів», перш ніж він зможе відповідати на запити. Або додаток має якимось особливим чином вивільняти ресурси після завершення роботи.

Принцип незмінності контейнерного образу (ІМП)

Загальноприйнято, що контейнерні програми повинні залишатися незмінними після збирання, навіть якщо запускаються в різних середовищах. Звідси випливає необхідність екстерналізувати зберігання даних на етапі виконання (інакше кажучи, використовувати для цього зовнішні засоби), а також покладатися на зовнішні, налаштовані під конкретне виконання, конфігурації, замість того щоб модифікувати або створювати унікальні контейнери для кожного середовища. Після будь-яких змін у додатку контейнерний образ повинен збиратися заново і розгортатися у всіх середовищах, що використовуються. До речі, під час управління ІТ-системами використовується подібний принцип, відомий як принцип незмінності серверів та інфраструктури.

Мета IIP – запобігти створенню окремих контейнерних образів для різних середовищ виконання та використовувати скрізь той самий образ разом з відповідною конфігурацією для конкретного середовища. Дотримання цього принципу дозволяє реалізувати такі важливі з погляду автоматизації хмарних систем практики, як відкат (roll-back) та накат (roll-forward) оновлень програми.

5 принципів здорового глузду для створення cloud-native apps

Принцип одноразовості процесів (Process Disposability Principle, PDP)

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

5 принципів здорового глузду для створення cloud-native apps
Як наслідок, контейнерні програми повинні зберігати свій стан за допомогою якихось зовнішніх засобів або використовувати для цього внутрішні розподілені схеми з надмірністю. Крім того, додаток повинен швидко запускатися та швидко завершувати роботу, а також бути готовими до раптової фатальної відмови обладнання.

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

Принцип самодостатності (Self-containment Principle, S-CP)

Відповідно до цього принципу, на етапі збирання до складу контейнера включаються всі необхідні компоненти. Контейнер повинен будуватися для того, що в системі є тільки чисте ядро ​​Linux, тому всі необхідні додаткові бібліотеки треба розміщувати в самому контейнері. Там же мають бути такі речі, як середовище виконання для відповідної мови програмування, платформа додатків (за потреби) та інші залежності, які будуть потрібні під час роботи контейнерної програми.

5 принципів здорового глузду для створення cloud-native apps

Винятки робляться лише конфігурацій, які варіюються від середовища до середовищі, і мають надаватися етапі виконання, наприклад, через Kubernetes ConfigMap.

Додаток може включати кілька контейнеризованих компонентів, наприклад, окремий контейнер СУБД у складі контейнерного веб-додатки. Відповідно до принципу S-CP, ці контейнери треба не об'єднувати в один, а зробити так, щоб контейнер СУБД містив у собі все необхідне для роботи бази даних, а контейнер веб-додатку – все необхідне для роботи веб-додатку, той самий веб-сервер . В результаті, під час виконання контейнер веб-програми залежатиме від контейнера СУБД і звертатиметься до нього при необхідності.

Принцип обмеження етапі виконання (Runtime Confinement Principle, RCP)

Принцип S-CP визначає, як має збиратися контейнер і що має містити двійковий файл образу. Але контейнер – це не просто «чорна скринька», яка має лише одну характеристику – розмір файлу. Під час виконання контейнер знаходить і інші вимірювання: обсяг пам'яті, процесорний час та інші системні ресурси.

5 принципів здорового глузду для створення cloud-native apps
І тут стане в нагоді принцип RCP, згідно з яким контейнер повинен декапувати свої вимоги до системних ресурсів та передавати їх платформі. Маючи ресурсні профілі кожного контейнера (скільки йому потрібно ресурсів ЦП, пам'яті, мережі та дискової системи), платформа може оптимальним чином виконувати диспетчеризацію та автомасштабування, керувати ІТ-потужностями та підтримувати рівні SLA для контейнерів.

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

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

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

  • Намагайтеся зменшувати розмір образів: видаляйте тимчасові файли і не ставте непотрібні пакети – що менше розмір контейнера, то швидше він збирається і копіюється на цільовий хост мережею.
  • Орієнтуйтесь на довільні User-ID: не використовуйте команду sudo або якісь особливі userid для запуску своїх контейнерів.
  • Маркуйте важливі порти: номери портів можна задавати і під час виконання, але краще вказати їх за допомогою команди EXPOSE – іншим людям та програмам буде простіше використовувати ваші образи.
  • Зберігайте постійні дані на томах: дані, які залишаються після знищення контейнера, слід записувати на томи.
  • Прописуйте метадані образи: теги, мітки та анотації полегшують використання образів – інші розробники вам будуть вдячні.
  • Синхронізуйте хост та образи: для деяких контейнерних програм потрібно синхронізувати контейнер з хостом за певними атрибутами, такими як час або ідентифікатор машини.
  • На закінчення ділимося шаблонами та найкращими практиками, які допоможуть ефективніше реалізувати перелічені вище принципи:
    www.slideshare.net/luebken/container-patterns
    docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices
    docs.projectatomic.io/container-best-practices
    docs.openshift.com/enterprise/3.0/creating_images/guidelines.html
    www.usenix.org/system/files/conference/hotcloud16/hotcloud16_burns.pdf
    leanpub.com/k8spatterns
    12factor.net

Вебінар за новою версією OpenShift Container Platform – 4
11 червня о 11.00

Що ви дізнаєтеся:

  • Immutable Red Hat Enterprise Linux CoreOS
  • OpenShift service mesh
  • Operator framework
  • Knative framework

Джерело: habr.com

Додати коментар або відгук