Модуль 1.2: Декларативність проти імперативності — Філософія
Складність:
[ШВИДКО]— Концептуальне розумінняЧас на проходження: 25-30 хвилин
Попередні вимоги: Модуль 1 (Чому Kubernetes переміг)
Що ви зможете зробити
Розділ «Що ви зможете зробити»Після завершення цього модуля ви зможете:
- Пояснити різницю між декларативним та імперативним підходами на реальних прикладах Kubernetes
- Передбачити, що зробить Kubernetes, якщо ви вручну зміните щось, чим він керує (і чому)
- Писати декларативні маніфести замість імперативних команд для продуктових навантажень
- Діагностувати проблеми, спричинені імперативним мисленням у декларативній системі
Чому це важливо
Розділ «Чому це важливо»О другій годині ночі чергова інженерка SaaS-компанії отримала сповіщення — критичний Pod перебував у циклі перезавантаження (crash-looping). Напівсонна, вона зайшла через SSH на вузол і вручну перезапустила контейнер. Проблему вирішено, можна спати далі. Проте Kubernetes миттєво видалив її запущений вручну контейнер і замінив його новим — який також пішов у crash-loop. Вона перезапустила його знову. Kubernetes знову його видалив. Протягом 45 хвилин вона боролася із системою, не усвідомлюючи, що Kubernetes не був зламаний — вона думала імперативно в декларативному світі.
Щойно вона оновила Deployment YAML, щоб виправити справжню причину конфігураційної помилки, і виконала kubectl apply, система відновилася сама за 12 секунд. Це і є різниця між імперативним та декларативним мисленням — і це найважливіша концепція в Kubernetes.
Якщо ви розумієте декларативне мислення, у роботі Kubernetes з’являється сенс. Якщо ні — ви будете боротися із системою замість того, щоб використовувати її.
Два підходи
Розділ «Два підходи»Імперативний: кажіть системі, що робити
Розділ «Імперативний: кажіть системі, що робити»# Імперативний підхідssh server1docker run -d nginxdocker run -d nginxdocker run -d nginx# Перевірка, чи вони запущеніdocker ps# Якщо один впаде, запустити інший# Якщо трафік зросте, запустити більше# Якщо сервер вийде з ладу, зайти через SSH кудись ще і повторитиВи і є циклом керування. Ви спостерігаєте, приймаєте рішення та дієте.
Декларативний: кажіть системі, чого ви хочете
Розділ «Декларативний: кажіть системі, чого ви хочете»# Декларативний підхідapiVersion: apps/v1kind: Deploymentmetadata: name: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginxkubectl apply -f nginx-deployment.yaml# Готово. Kubernetes подбає про решту.Kubernetes є циклом керування. Він спостерігає, приймає рішення та діє — безперервно.
Цикл узгодження (Reconciliation Loop)
Розділ «Цикл узгодження (Reconciliation Loop)»Це основний механізм Kubernetes:
┌─────────────────────────────────────────────────────────────┐│ ЦИКЛ УЗГОДЖЕННЯ │├─────────────────────────────────────────────────────────────┤│ ││ ┌──────────────┐ ││ │ │ ││ │ БАЖАНИЙ │◄───── Ви визначаєте це (YAML) ││ │ СТАН │ ││ │ │ ││ └──────┬───────┘ ││ │ ││ │ Порівняння ││ ▼ ││ ┌──────────────┐ ││ │ │ ││ │ ПОТОЧНИЙ │◄───── K8s спостерігає за цим ││ │ СТАН │ ││ │ │ ││ └──────┬───────┘ ││ │ ││ │ Якщо відрізняється... ││ ▼ ││ ┌──────────────┐ ││ │ │ ││ │ ВИКОНАТИ │◄───── K8s діє для узгодження ││ │ ДІЮ │ ││ │ │ ││ └──────┬───────┘ ││ │ ││ └─────────────────────────────────────────┐ ││ │ ││ Цикл назавжди ◄───────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Цей цикл працює постійно. Не один раз при запуску kubectl apply, а вічно.
Аналогія з реального світу: Термостат
Розділ «Аналогія з реального світу: Термостат»Імперативний (без термостата)
Розділ «Імперативний (без термостата)»Ви: "Холодно. Увімкни обігрівач."[Минає час]Ви: "Тепер спекотно. Вимкни обігрівач."[Минає час]Ви: "Знову холодно. Увімкни обігрівач."[Повторювати вічно або здатися і страждати]Ви — цикл керування.
Декларативний (з термостатом)
Розділ «Декларативний (з термостатом)»Ви: "Я хочу, щоб було 22°C."Термостат: [Постійно моніторить і регулює]Термостат — це цикл керування. Ви оголосили свій бажаний стан (22°C), і система його підтримує.
Чому декларативність перемагає
Розділ «Чому декларативність перемагає»1. Самовідновлення (Self-Healing)
Розділ «1. Самовідновлення (Self-Healing)»# Ви кажете: "Я хочу 3 репліки"spec: replicas: 3Зупиніться та подумайте: Що станеться, якщо ви вручну видалите Pod, яким керує Deployment?
Що відбувається, коли:
- Контейнер падає? → K8s запускає інший
- Вузол виходить з ладу? → K8s переносить Pod на інші вузли
- Хтось вручну видаляє Pod? → K8s створює його знову
Ви не писали жодної логіки для цього. Ви просто задекларували те, що хочете отримати.
2. Ідемпотентність
Розділ «2. Ідемпотентність»# Запустіть це 100 разівkubectl apply -f deployment.yaml
# Результат: однаковий стан щоразу# Жодних дублікатів, конфліктів чи помилок "вже існує"Декларативні операції є ідемпотентними — багаторазове застосування однієї і тієї ж конфігурації дає однаковий результат.
3. Контроль версій та GitOps
Розділ «3. Контроль версій та GitOps»# Ваша інфраструктура — це кодgit log --onelinea1b2c3d feat: scale web to 5 replicasd4e5f6g fix: increase memory limitg7h8i9j feat: add health checks
# Відкат інфраструктури за допомогою gitgit revert a1b2c3dkubectl apply -f .Декларативні конфігурації можна версіонувати, рецензувати та перевіряти.
4. Виявлення відхилень (Drift Detection)
Розділ «4. Виявлення відхилень (Drift Detection)»Імперативний світ:- Хтось зайшов через SSH і вніс зміни- Документація не відповідає реальності- "На моїй машині працює"- Страх торкатися продуктового середовища
Декларативний світ:- Git — єдине джерело істини- K8s безперервно підтримує цю істину- Зміни потребують перевірки через PR- Впевненість у розгортанніІмперативна пастка
Розділ «Імперативна пастка»Зупиніться та подумайте: Якщо Kubernetes постійно узгоджує стан, що це означає для ручних виправлень, зроблених безпосередньо на сервері?
Kubernetes має імперативні команди:
# Вони працюють, проте...kubectl run nginx --image=nginxkubectl scale deployment nginx --replicas=5kubectl set image deployment/nginx nginx=nginx:1.19Чому вони небезпечні:
- Відсутність аудиту: Хто запустив команду? Коли?
- Відсутність перевірки: Зміни оминають процес PR/рецензування.
- Дрейф (Drift): Стан системи не відповідає жодному файлу.
- Неможливість відтворення: “Які саме команди ми запускали для налаштування?”
Коли імперативний підхід допустимий:
- Навчання та експерименти.
- Налагодження (тимчасові зміни).
- Надзвичайні ситуації (з негайним оновленням декларативної конфігурації після цього).
Найкраща практика:
# Генеруйте YAML, не застосовуйте напрямуkubectl create deployment nginx --image=nginx --dry-run=client -o yaml > deployment.yaml
# Перевірте, зафіксуйте в git (commit), потім застосуйтеkubectl apply -f deployment.yamlВізуалізація: Стан у часі
Розділ «Візуалізація: Стан у часі»┌─────────────────────────────────────────────────────────────┐│ ІМПЕРАТИВНІ ОПЕРАЦІЇ │├─────────────────────────────────────────────────────────────┤│ ││ Стан ││ ▲ ││ │ Потрібне ручне втручання ││ │ │ │ │ ││ │ ┌─────────┼─────────┼─────────┼─────────┐ ││ │ │ ▼ ▼ ▼ │ ││ │ ───┴─────────X─────────X─────────X─────────┴─── ││ │ Збої / Дрейф ││ │ ││ └────────────────────────────────────────────────► Час ││ ││ Результат: постійне гасіння пожеж, непередбачуваний стан ││ │└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐│ ДЕКЛАРАТИВНІ ОПЕРАЦІЇ │├─────────────────────────────────────────────────────────────┤│ ││ Стан ││ ▲ ││ │ ││ │ ┌─────────────────────────────────────────┐ ││ │ │ Бажаний стан (визначений у YAML) │ ││ │ ───┴─────────────────────────────────────────┴─── ││ │ ▲ ▲ ▲ ▲ ▲ ││ │ │ │ │ │ │ ││ │ Самовідновлення через цикл узгодження ││ │ ││ └────────────────────────────────────────────────► Час ││ ││ Результат: самовідновлення, передбачуваність, спокійний сон││ │└─────────────────────────────────────────────────────────────┘Чи знали ви?
Розділ «Чи знали ви?»-
Цикл узгодження запускається кожні 10 секунд за замовчуванням. Контролери постійно перевіряють, чи відповідає реальність бажаному стану.
-
Кожен ресурс Kubernetes є декларативним. Pods, Services, ConfigMaps — усе це лише декларації бажаного стану, які узгоджують контролери.
-
GitOps народився з цієї моделі. ArgoCD та Flux розширюють декларативне мислення: Git стає джерелом істини, а K8s узгоджує стан відповідно до Git.
-
Terraform використовує ту ж модель. Декларативна революція виходить за межі K8s. Сучасні інструменти інфраструктури майже повсюдно є декларативними.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
| Використання імперативних команд у продакшені | Немає історії змін, ризик дрейфу конфігурації | Завжди використовуйте kubectl apply -f |
Редагування ресурсів “наживо” через kubectl edit | Зміни не зафіксовані в Git | Оновіть YAML-файли, застосуйте з Git |
| Нерозуміння того, що зміни є безперервними | Сюрприз, коли K8s “скасовує” ручні зміни | Прийміть модель — змінюйте декларацію |
| Боротьба з циклом узгодження | Розчарування, складні обхідні шляхи | Працюйте із системою, а не проти неї |
Змішування декларативних інструментів (напр., Helm + kubectl apply) | Інструменти перезаписують конфігурації один одного | Оберіть один метод розгортання для ресурсу |
| Забування про видалення застарілих ресурсів | Старі ресурси залишаються в кластері | Використовуйте GitOps або kubectl apply --prune |
| Зберігання секретів у YAML без шифрування | Відкриває конфіденційні дані в системі контролю версій | Використовуйте Sealed Secrets, SOPS або External Secrets Operator |
Очікування повної атомарності від kubectl apply | Часткові збої можуть залишити застосунок у зламаному стані | Покладайтеся на перевірки стану (health checks) та readiness probes |
Зміна мислення
Розділ «Зміна мислення»Старе мислення (імперативне)
Розділ «Старе мислення (імперативне)»"Мені потрібно розгорнути застосунок"→ Зайти на сервер через SSH→ Стягнути код→ Зібрати→ Запустити процес→ Налаштувати nginx→ Оновити фаєрвол→ Протестувати→ Задокументувати те, що я зробивНове мислення (декларативне)
Розділ «Нове мислення (декларативне)»"Мені потрібно розгорнути застосунок"→ Визначити бажаний стан у YAML→ Зафіксувати в Git→ kubectl apply (або дозволити GitOps зробити це)→ K8s подбає про решту→ Git І Є документацієюКонтрольні запитання
Розділ «Контрольні запитання»-
Ви розгортаєте вебзастосунок із 3 репліками. Раптово на вузлі, де розміщено два з цих Pods, зникає живлення. Без втручання людини кількість реплік застосунку повертається до 3 протягом декількох хвилин. Який саме механізм Kubernetes відповідає за це і як він працює?
Відповідь
Основним механізмом, відповідальним за таку поведінку самовідновлення, є цикл узгодження (reconciliation loop). Kubernetes постійно порівнює бажаний стан (вашу декларацію про 3 репліки) із поточним станом (лише 1 активний Pod після збою вузла). Коли він виявляє цю невідповідність, контролер негайно вживає заходів для запуску 2 нових Pods на справних вузлах. Цей цикл працює у фоновому режимі безперервно. -
Під час великого напливу трафіку інженер швидко запускає
kubectl scale deployment web --replicas=10. Через два дні інший розробник вносить зміни в образ застосунку через PR, і розгортання раптово повертається до 3 реплік, що спричиняє збій. Що стало причиною цього і чому імперативна команда стала пасткою?Відповідь
Імперативна команда `kubectl scale` змінила стан кластера, але не оновила джерело істини в Git, створивши дрейф конфігурації. Коли розробник застосував оновлений YAML з Git, Kubernetes побачив, що задекларовано 3 репліки, і "виправив" кластер відповідно до цього, не знаючи про ручне масштабування. Імперативні команди небезпечні, бо не залишають слідів у системі контролю версій та створюють хибну реальність, яка буде перезаписана при наступному декларативному оновленні. -
Ваш CI/CD пайплайн налаштований на запуск
kubectl apply -f deployment.yamlщоразу, коли зміни вливаються в гілку main. Розробник випадково запускає пайплайн 5 разів поспіль, не змінюючи файл розгортання. Що станеться в кластері та яка властивість декларативних систем робить це безпечним?Відповідь
Стан кластера залишиться незмінним, без створення дублікатів ресурсів, завдяки властивості ідемпотентності. Операція є ідемпотентною, якщо її багаторазове застосування дає той самий результат, що й одноразове. У декларативній системі `kubectl apply` лише вказує кінцевий стан; якщо кластер уже йому відповідає, Kubernetes не виконує жодних дій. Це робить автоматизацію безпечною та передбачуваною. -
Скрипт випадково запустив
kubectl delete podдля Pod бази даних, яким керує StatefulSet. До того як черговий інженер встиг відкрити ноутбук, Pod уже перезапускався. Чому система не чекала втручання людини?Відповідь
Kubernetes негайно створив новий Pod, оскільки він працює за принципом безперервного декларативного циклу керування. Контролер, що стежить за StatefulSet, побачив, що поточний стан (0 Pods) відхиляється від бажаного (1 Pod), вказаного в маніфесті. Йому байдуже, чому Pod зник; його єдина робота — узгодити реальність із задекларованим наміром. Це демонструє, як декларативне самовідновлення замінює ручне гасіння пожеж автоматизованим виправленням. -
Ваша команда використовує ArgoCD (інструмент GitOps) для керування продуктовим кластером. Адміністратор заходить на вузол через SSH і вручну редагує конфігураційний файл Nginx всередині запущеного Pod, щоб виправити баг. Через десять хвилин баг з’являється знову. Чому це сталося і як GitOps обробляє таку ситуацію?
Відповідь
Баг з'явився знову, тому що GitOps забезпечує виконання декларативного стану, збереженого в Git, як абсолютного джерела істини. Ручна зміна всередині Pod створила дрейф конфігурації між поточним станом і репозиторієм Git. Контролер GitOps (або сам Kubernetes) зрештою узгодив стан, або перезапустивши Pod, або перезаписавши ручні зміни. Щоб виправити баг назавжди, інженер повинен оновити конфігурацію в Git.
Вправа для роздумів
Розділ «Вправа для роздумів»Цей модуль є концептуальним — подумайте над цими питаннями:
1. Аналогія з термостатом:
- Які ще системи у вашому житті працюють декларативно? (Круїз-контроль? Автоматична яскравість?)
- Що робить їх простішими у використанні, ніж ручні аналоги?
2. Ваш поточний робочий процес:
- Як ви розгортаєте програмне забезпечення сьогодні?
- Це більше імперативний чи декларативний підхід?
- Що б змінилося, якби ви перейшли на іншу модель?
3. Наслідки самовідновлення:
- Якщо Kubernetes “скасовує” ручні зміни, це перевага чи недолік?
- Як це змінює ваш підхід до пошуку та усунення несправностей?
4. Git та інфраструктура:
- Чому зберігання інфраструктури як YAML у Git є потужним інструментом?
- На які питання ви можете відповісти за допомогою
git log, на які не могли відповісти раніше?
5. Зміна ментальної моделі:
- Оператор запитує: “які команди мені запустити?”. Декларативний мислитель запитує: “який стан мені потрібен?”.
- Яке питання веде до створення більш стабільних систем? Чому?
Цей перехід у мисленні — від “як” до “що” — є найважливішою концепцією в усьому курсі.
Підсумок
Розділ «Підсумок»Декларативна модель — це фундамент Kubernetes:
- Бажаний стан: ви визначаєте, що ви хочете (YAML).
- Узгодження: K8s постійно приводить реальність у відповідність до бажання.
- Самовідновлення: збої виправляються автоматично.
- Ідемпотентність: застосовуйте ту саму конфігурацію багаторазово, отримуйте той самий результат.
- Контроль версій: ваша інфраструктура — це код у Git.
Це не просто технічний вибір — це філософія, яка дозволяє будувати надійну та масштабовану інфраструктуру.
Наступний модуль
Розділ «Наступний модуль»Модуль 1.3: Що ми не розглядаємо (і чому) — розуміння обсягу KubeDojo та куди звертатися за темами, які ми пропускаємо.