Модуль 1.4: Deployments — Управління застосунками
Складність:
[СЕРЕДНЯ]— Основне управління робочим навантаженнямЧас на виконання: 40-45 хвилин
Попередні вимоги: Модуль 1.3 (Pods)
Що ви зможете зробити
Розділ «Що ви зможете зробити»Після завершення цього модуля ви зможете:
- Створити Deployments як імперативно, так і декларативно
- Масштабувати застосунки вгору та вниз і пояснювати, що відбувається з відповідними Pods
- Виконувати rolling updates та rollbacks, а також діагностувати застряглі розгортання
- Пояснити ієрархію Deployment → ReplicaSet → Pod та чому існує кожен рівень
Чому це важливо
Розділ «Чому це важливо»Сервіс обробки платежів одного стартапу працював як один Pod. У п’ятницю о 14:00 Pod впав через витік пам’яті. Оскільки це був naked Pod — без Deployment та ReplicaSet — він так і залишився неактивним. Протягом 23 хвилин ніхто не міг обробляти платежі. Коли черговий інженер нарешті виконав kubectl apply для нового Pod, він випадково розгорнув не той образ (image tag). Ще 15 хвилин простою.
Загальна вартість: 12 тисяч доларів втрачених транзакцій і дуже напружена команда. Deployment перезапустив би Pod автоматично менш ніж за 10 секунд. Стратегія rolling update виявила б неправильний образ до того, як він замінив би всі репліки.
Аналогія з менеджером: Уявіть Deployment як менеджера ресторану. Ви (розробник) кажете: «Мені потрібно 3 офіціанти в залі». Менеджер (Deployment) займається наймом (створенням Pods), заміною того, хто захворів (самовідновлення), та навчанням персоналу роботі з новим меню (rolling updates). Ви описуєте, ЩО ви хочете; Deployment забезпечує ЯК це зробити.
Чому Deployments?
Розділ «Чому Deployments?»Самі по собі Pods мають проблеми:
┌─────────────────────────────────────────────────────────────┐│ PODS САМІ ПО СОБІ vs DEPLOYMENTS │├─────────────────────────────────────────────────────────────┤│ ││ ОКРЕМИЙ (NAKED) POD: ││ - Pod вмирає → залишається неактивним ││ - Вузол (Node) виходить з ладу → Pod втрачено ││ - Складно масштабувати ││ - Оновлення потребують ручного видалення/створення ││ ││ З DEPLOYMENT: ││ - Pod вмирає → автоматично перестворюється ││ - Вузол виходить з ладу → переплановується на інший ││ - Масштабування однією командою ││ - Rolling updates без простоїв ││ - Відкат (Rollback) до попередніх версій ││ │└─────────────────────────────────────────────────────────────┘Створення Deployments
Розділ «Створення Deployments»Імперативний підхід (швидке тестування)
Розділ «Імперативний підхід (швидке тестування)»# Створити deploymentkubectl create deployment nginx --image=nginx
# З реплікамиkubectl create deployment nginx --image=nginx --replicas=3
# Dry run для перегляду YAMLkubectl create deployment nginx --image=nginx --dry-run=client -o yamlДекларативний підхід (професійний шлях)
Розділ «Декларативний підхід (професійний шлях)»apiVersion: apps/v1kind: Deploymentmetadata: name: nginx labels: app: nginxspec: replicas: 3 # Кількість копій Pod selector: # Як знайти Pods для управління matchLabels: app: nginx template: # Шаблон Pod metadata: labels: app: nginx # Має збігатися з selector spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80kubectl apply -f deployment.yamlАрхітектура Deployment
Розділ «Архітектура Deployment»┌─────────────────────────────────────────────────────────────┐│ ІЄРАРХІЯ DEPLOYMENT │├─────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────┐ ││ │ DEPLOYMENT │ ││ │ - Визначає бажаний стан │ ││ │ - Керує ReplicaSets │ ││ │ - Обробляє оновлення/відкати (rollbacks) │ ││ └────────────────────┬────────────────────────────────┘ ││ │ ││ ▼ ││ ┌─────────────────────────────────────────────────────┐ ││ │ REPLICASET │ ││ │ - Гарантує роботу N Pods │ ││ │ - Створюється/керується через Deployment │ ││ │ - Зазвичай не потребує прямої взаємодії │ ││ └────────────────────┬────────────────────────────────┘ ││ │ ││ ┌─────────────┼─────────────┐ ││ ▼ ▼ ▼ ││ ┌───────────┐ ┌───────────┐ ┌───────────┐ ││ │ POD │ │ POD │ │ POD │ ││ │ nginx │ │ nginx │ │ nginx │ ││ └───────────┘ └───────────┘ └───────────┘ ││ ││ replicas: 3 → 3 Pods підтримуються автоматично ││ │└─────────────────────────────────────────────────────────────┘Основні операції
Розділ «Основні операції»Перегляд Deployments
Розділ «Перегляд Deployments»# Список deploymentskubectl get deploymentskubectl get deploy # Коротка форма
# Детальна інформаціяkubectl describe deployment nginx
# Перегляд пов'язаних ресурсівkubectl get deploy,rs,podsМасштабування
Розділ «Масштабування»# Збільшити/зменшити кількість реплікkubectl scale deployment nginx --replicas=5
# Або відредагувати YAML та застосуватиkubectl edit deployment nginx# Змініть replicas, збережіть
# Спостерігайте за масштабуванням Podskubectl get pods -wЗупиніться та подумайте: Якщо ви вручну видалите два Pods із Deployment з 5 репліками, що саме станеться в кластері? Спробуйте:
kubectl delete pod <name> <name>, а потім швидко запустітьkubectl get rs. Пояснення: ReplicaSet негайно виявить, що поточна кількість (3) не збігається з бажаною (5), і створить два нових Pods на заміну, щоб підтримати декларативний стан.
Оновлення (Rolling)
Розділ «Оновлення (Rolling)»# Оновити образkubectl set image deployment/nginx nginx=nginx:1.26
# Або відредагувати deploymentkubectl edit deployment nginx
# Спостерігайте за процесом оновлення (rollout)kubectl rollout status deployment nginx
# Перегляд історії оновленьkubectl rollout history deployment nginxЗупиніться та подумайте: Спробуйте виконати
kubectl set image deployment/nginx nginx=nginx:brokenдля працюючого Deployment. Використовуйтеkubectl get podsтаkubectl rollout status deployment nginx. Що ви бачите? Підказка: Kubernetes зупиняє оновлення, оскільки нові Pods ніколи не стають готовими (ready), захищаючи ваші існуючі працюючі Pods від видалення. Ви побачите статусImagePullBackOffдля нових Pods, тоді як старі залишаться в статусіRunning.
Відкат (Rollback)
Розділ «Відкат (Rollback)»# Скасувати останню змінуkubectl rollout undo deployment nginx
# Відкат до конкретної версії (revision)kubectl rollout history deployment nginxkubectl rollout undo deployment nginx --to-revision=2Зупиніться та подумайте: Спробуйте відредагувати ReplicaSet безпосередньо через
kubectl edit rs <name>і змінити кількість реплік. Що зробить Deployment? Пояснення: Контролер Deployment виявить відхилення майже миттєво. Він негайно перезапише ваші ручні зміни в ReplicaSet, щоб гарантувати відповідність кластера декларативному стану Deployment.
Стратегія Rolling Update
Розділ «Стратегія Rolling Update»Deployments оновлюють Pods поступово:
spec: strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% # Макс. додаткових Pods під час оновлення maxUnavailable: 25% # Макс. Pods, що можуть бути недоступні┌─────────────────────────────────────────────────────────────┐│ ПРОЦЕС ROLLING UPDATE │├─────────────────────────────────────────────────────────────┤│ ││ Початковий стан (3 репліки, v1): ││ [v1] [v1] [v1] ││ ││ Початок оновлення до v2: ││ [v1] [v1] [v1] [v2] ← Створено новий Pod ││ ││ Новий Pod готовий: ││ [v1] [v1] [v2] [v2] ← Старий Pod видалено ││ ││ Продовження: ││ [v1] [v2] [v2] [v2] ││ ││ Завершено: ││ [v2] [v2] [v2] ← Усі Pods оновлено ││ ││ Без простоїв! Трафік обслуговується безперервно. ││ │└─────────────────────────────────────────────────────────────┘Пояснення YAML для Deployment
Розділ «Пояснення YAML для Deployment»apiVersion: apps/v1kind: Deploymentmetadata: name: nginx labels: app: nginxspec: replicas: 3 # Бажана кількість Pod selector: matchLabels: app: nginx # Має збігатися з мітками шаблону (template) strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: # Шаблон Pod (такий самий, як специфікація Pod) metadata: labels: app: nginx # Мітки для виявлення сервісів (service discovery) spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "100m" limits: memory: "128Mi" cpu: "200m"Самовідновлення в дії
Розділ «Самовідновлення в дії»# Створити deploymentkubectl create deployment nginx --image=nginx --replicas=3
# Переглянути Podskubectl get pods
# Видалити Podkubectl delete pod <pod-name>
# Негайно перевірте ще разkubectl get pods# Новий Pod уже створюється!
# Deployment підтримує бажаний станkubectl get deployment nginx# READY показує 3/3Чи знали ви?
Розділ «Чи знали ви?»-
Deployments не керують Pods безпосередньо. Вони керують ReplicaSets, які в свою чергу керують Pods. Це дає можливість робити відкати.
-
Кожне оновлення створює новий ReplicaSet. Старі ReplicaSets зберігаються (з 0 реплік) для історії відкатів.
-
maxSurge: 0, maxUnavailable: 0— це неможливо. Ви не можете оновитися без створення нових Pods або видалення старих. -
kubectl rollout restartзапускає нове оновлення без зміни специфікації. Корисно для повторного завантаження образів з тим самим тегом.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
| Selector не збігається з мітками шаблону | Deployment створює “осиротілі” Pods або API взагалі відхиляє YAML. | Переконайтеся, що matchLabels точно збігається з мітками шаблону Pod. |
Використання тегу :latest для образу | Відкати стають непередбачуваними; вузли не завантажуватимуть новий образ, якщо назва тегу не змінилася. | Використовуйте імутабельні, конкретні теги версій (наприклад, хеші git-комітів). |
| Редагування ReplicaSet безпосередньо | Зміни будуть перезаписані через Deployment під час наступного циклу узгодження (reconciliation loop). | Завжди змінюйте безпосередньо Deployment, а не підпорядкований ReplicaSet. |
| Стратегія Recreate для високонавантажених застосунків | Спричиняє повний простій, оскільки всі старі Pods видаляються до запуску нових. | Використовуйте RollingUpdate, якщо застосунок не забороняє одночасну роботу різних версій. |
| Відсутність лімітів ресурсів | Нові Pods під час оновлення можуть вичерпати ресурси для існуючих Pods або призвести до збою вузла. | Завжди встановлюйте запити (requests) та ліміти (limits) ресурсів у шаблоні Pod. |
| Ігнорування статусу оновлення (rollout) | Невдале оновлення може застрягти на невизначений час у фоновому режимі без відома операторів. | Завжди запускайте kubectl rollout status після застосування змін. |
| Незадокументовані оновлення | Історія відкатів показує незрозумілі номери версій без пояснення змін. | Використовуйте анотації kubernetes.io/change-cause для документування причин оновлення. |
| Сліпе масштабування під час оновлення | Може спричинити плутанину, оскільки пропорційне масштабування впливає як на старі, так і на нові ReplicaSets. | Дочекайтеся завершення оновлення або вивчіть поведінку пропорційного масштабування. |
Контрольні запитання
Розділ «Контрольні запитання»-
Сценарій: Ви запускаєте застарілий застосунок зі збереженням стану (stateful), який не може мати два одночасно працюючі екземпляри, оскільки вони пошкодять базу даних. Вам потрібно розгорнути нову версію. Яку стратегію розгортання варто обрати і чому?
Відповідь
Ви повинні використовувати стратегію `Recreate` замість стандартної `RollingUpdate`. Стратегія `RollingUpdate` запускає нові Pods до завершення старих, що призведе до одночасної роботи двох екземплярів і пошкодження бази даних. При виборі `Recreate` Deployment спочатку видалить усі існуючі Pods і дочекається їх повного завершення. Тільки після того, як старі Pods зникнуть, він запустить нові, гарантуючи абсолютну ізоляцію між версіями ціною невеликого простою. -
Сценарій: Черговий інженер помічає, що Pods у Deployment споживають занадто багато пам’яті. У паніці він редагує ReplicaSet безпосередньо за допомогою
kubectl edit rs, щоб змінити ліміти ресурсів. Що станеться далі і чому?Відповідь
Зміни, внесені безпосередньо в ReplicaSet, будуть повністю проігноровані або швидко перезаписані, а Pods не оновляться. Deployments розроблені як декларативне джерело істини для підпорядкованих їм ReplicaSets. Якщо ReplicaSet відхиляється від шаблону Deployment або якщо ви намагаєтеся ініціювати оновлення на рівні ReplicaSet, контролер Deployment поверне стан до відповідності власним специфікаціям. Для вирішення проблеми з пам'яттю інженер має редагувати безпосередньо Deployment, що автоматично створить новий ReplicaSet з правильними лімітами. -
Сценарій: Ви запускаєте оновлення Deployment з новим тегом образу, але через 10 хвилин користувачі скаржаться, що застосунок усе ще старої версії. Ви запускаєте
kubectl get podsі бачитеImagePullBackOffдля нових Pods, тоді як старі все ще в статусіRunning. Чому Deployment повівся саме так?Відповідь
Deployment повівся ідеально, зупинивши оновлення завдяки стандартному налаштуванню `maxUnavailable` у стратегії `RollingUpdate`. Коли нові Pods не змогли завантажити образ і впали, вони ніколи не досягли стану `Ready`. Оскільки Deployment гарантує певну кількість доступних Pods, він відмовився видаляти старі, працюючі Pods, поки нові не стануть здоровими. Цей механізм самозбереження запобіг повному виходу кластера з ладу через неправильну конфігурацію. -
Сценарій: Під час значного стрибка трафіку ваша команда запускає rolling update для виправлення критичного багу. Посеред процесу оновлення трафік подвоюється знову, і ви виконуєте
kubectl scale deployment web --replicas=10. Як Deployment обробляє цю подію масштабування під час активного оновлення?Відповідь
Deployment достатньо розумний, щоб обробляти одночасне масштабування та оновлення без втрати трафіку, використовуючи механізм пропорційного масштабування. Він тимчасово призупиняє rolling update і розподіляє нову кількість реплік між старим і новим ReplicaSets пропорційно їхньому поточному розміру. Після завершення масштабування він відновлює rolling update, поступово переносячи масштабовані Pods зі старої версії на нову. Це гарантує миттєве отримання необхідної потужності для обробки стрибка трафіку з одночасним просуванням до виправлення багу. -
Сценарій: Ваша команда використовує
maxSurge: 100%таmaxUnavailable: 0%для Deployment з 10 репліками, щоб забезпечити надшвидке оновлення. Які наслідки для потужності кластера має така конфігурація під час оновлення?Відповідь
Встановлення `maxSurge` на 100% означає, що Deployment спробує негайно створити повний дублікат із 10 нових Pods, зберігаючи при цьому всі 10 старих Pods працюючими (оскільки `maxUnavailable` дорівнює 0%). Це вимагає від вашого кластера Kubernetes наявності достатньої вільної потужності CPU та пам'яті для одночасної роботи 20 Pods під час фази оновлення. Якщо кластерний автоскейлер не спрацює вчасно або фізичних вузлів буде недостатньо, нові Pods застрягнуть у стані `Pending`. Хоча така конфігурація гарантує відсутність простоїв і швидке оновлення, вона дуже ресурсоємна і може спричинити вузькі місця в плануванні. -
Сценарій: Розробник скаржиться, що його щойно створений Deployment не працює. Ви перевіряєте YAML і помічаєте, що
spec.selector.matchLabelsу Deployment має значенняapp: web-frontend, алеmetadata.labelsу шаблоні Pod має значенняapp: web-backend. Чому це критична помилка для Deployment?Відповідь
Контролер Deployment повністю покладається на селектори міток (label selectors) для ідентифікації Pods, якими він має керувати. Якщо селектор не збігається з мітками, застосованими до Pods, створених за його шаблоном, Deployment створить Pods, але негайно втратить їх із виду, оскільки вони не відповідають критеріям пошуку. Потім він нескінченно створюватиме нові Pods, намагаючись задовольнити кількість реплік, тоді як початкові "осиротілі" Pods накопичуватимуться. Щоб запобігти цій хаотичній ситуації, API Kubernetes перевіряє цей зв'язок і відхиляє YAML під час створення, видаючи фатальну помилку валідації.
Практична вправа
Розділ «Практична вправа»Завдання: Створити Deployment, масштабувати його, оновити та відкотити зміни.
# 1. Створити deploymentkubectl create deployment web --image=nginx:1.24
# 2. Масштабувати до 3 реплікkubectl scale deployment web --replicas=3
# 3. Перевіритиkubectl get deploy,rs,pods
# 4. Оновити образkubectl set image deployment/web nginx=nginx:1.25
# 5. Спостерігати за оновленнямkubectl rollout status deployment web
# 6. Перевірити історіюkubectl rollout history deployment web
# 7. Симулювати проблему — відкат (rollback)kubectl rollout undo deployment web
# 8. Перевірити відкатkubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].image}'# Має показати nginx:1.24
# 9. Очищенняkubectl delete deployment webКритерії успіху:
- Створено deployment з назвою
webта образомnginx:1.24 - Deployment масштабовано до 3 реплік
- Підтверджено роботу 3 Pods за допомогою
kubectl get pods - Образ оновлено до
nginx:1.25 - Дочекалися завершення оновлення за допомогою
kubectl rollout status - Виконано відкат розгортання до попередньої версії
- Підтверджено, що активні Pods працюють на
nginx:1.24 - Проведено очищення шляхом видалення deployment
Підсумок
Розділ «Підсумок»Deployments керують вашими застосунками:
Можливості:
- Декларативні оновлення
- Rolling updates (без простоїв)
- Можливість відкату (rollback)
- Самовідновлення
- Легке масштабування
Основні команди:
kubectl create deploymentkubectl scale deploymentkubectl set imagekubectl rollout statuskubectl rollout undo
Найкращі практики:
- Завжди використовуйте Deployments (а не окремі Pods)
- Використовуйте конкретні теги образів
- Встановлюйте запити та ліміти ресурсів (requests/limits)
Наступний модуль
Розділ «Наступний модуль»Модуль 1.5: Services — стабільна мережа для ваших Pods.