Перейти до вмісту

Модуль 1.4: Deployments — Управління застосунками

Hands-On Lab Available
K8s Cluster beginner 30 min
Launch Lab ↗

Opens in Killercoda in a new tab

Складність: [СЕРЕДНЯ] — Основне управління робочим навантаженням

Час на виконання: 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 забезпечує ЯК це зробити.


Самі по собі Pods мають проблеми:

┌─────────────────────────────────────────────────────────────┐
│ PODS САМІ ПО СОБІ vs DEPLOYMENTS │
├─────────────────────────────────────────────────────────────┤
│ │
│ ОКРЕМИЙ (NAKED) POD: │
│ - Pod вмирає → залишається неактивним │
│ - Вузол (Node) виходить з ладу → Pod втрачено │
│ - Складно масштабувати │
│ - Оновлення потребують ручного видалення/створення │
│ │
│ З DEPLOYMENT: │
│ - Pod вмирає → автоматично перестворюється │
│ - Вузол виходить з ладу → переплановується на інший │
│ - Масштабування однією командою │
│ - Rolling updates без простоїв │
│ - Відкат (Rollback) до попередніх версій │
│ │
└─────────────────────────────────────────────────────────────┘

Імперативний підхід (швидке тестування)

Розділ «Імперативний підхід (швидке тестування)»
Terminal window
# Створити deployment
kubectl create deployment nginx --image=nginx
# З репліками
kubectl create deployment nginx --image=nginx --replicas=3
# Dry run для перегляду YAML
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml

Декларативний підхід (професійний шлях)

Розділ «Декларативний підхід (професійний шлях)»
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
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: 80
Terminal window
kubectl apply -f deployment.yaml

┌─────────────────────────────────────────────────────────────┐
│ ІЄРАРХІЯ DEPLOYMENT │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ DEPLOYMENT │ │
│ │ - Визначає бажаний стан │ │
│ │ - Керує ReplicaSets │ │
│ │ - Обробляє оновлення/відкати (rollbacks) │ │
│ └────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ REPLICASET │ │
│ │ - Гарантує роботу N Pods │ │
│ │ - Створюється/керується через Deployment │ │
│ │ - Зазвичай не потребує прямої взаємодії │ │
│ └────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ POD │ │ POD │ │ POD │ │
│ │ nginx │ │ nginx │ │ nginx │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
│ replicas: 3 → 3 Pods підтримуються автоматично │
│ │
└─────────────────────────────────────────────────────────────┘

Terminal window
# Список deployments
kubectl get deployments
kubectl get deploy # Коротка форма
# Детальна інформація
kubectl describe deployment nginx
# Перегляд пов'язаних ресурсів
kubectl get deploy,rs,pods
Terminal window
# Збільшити/зменшити кількість реплік
kubectl scale deployment nginx --replicas=5
# Або відредагувати YAML та застосувати
kubectl edit deployment nginx
# Змініть replicas, збережіть
# Спостерігайте за масштабуванням Pods
kubectl get pods -w

Зупиніться та подумайте: Якщо ви вручну видалите два Pods із Deployment з 5 репліками, що саме станеться в кластері? Спробуйте: kubectl delete pod <name> <name>, а потім швидко запустіть kubectl get rs. Пояснення: ReplicaSet негайно виявить, що поточна кількість (3) не збігається з бажаною (5), і створить два нових Pods на заміну, щоб підтримати декларативний стан.

Terminal window
# Оновити образ
kubectl set image deployment/nginx nginx=nginx:1.26
# Або відредагувати deployment
kubectl 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.

Terminal window
# Скасувати останню зміну
kubectl rollout undo deployment nginx
# Відкат до конкретної версії (revision)
kubectl rollout history deployment nginx
kubectl rollout undo deployment nginx --to-revision=2

Зупиніться та подумайте: Спробуйте відредагувати ReplicaSet безпосередньо через kubectl edit rs <name> і змінити кількість реплік. Що зробить Deployment? Пояснення: Контролер Deployment виявить відхилення майже миттєво. Він негайно перезапише ваші ручні зміни в ReplicaSet, щоб гарантувати відповідність кластера декларативному стану Deployment.


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/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
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"

Самовідновлення в дії

Розділ «Самовідновлення в дії»
Terminal window
# Створити deployment
kubectl create deployment nginx --image=nginx --replicas=3
# Переглянути Pods
kubectl get pods
# Видалити Pod
kubectl 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.Дочекайтеся завершення оновлення або вивчіть поведінку пропорційного масштабування.

Контрольні запитання

Розділ «Контрольні запитання»
  1. Сценарій: Ви запускаєте застарілий застосунок зі збереженням стану (stateful), який не може мати два одночасно працюючі екземпляри, оскільки вони пошкодять базу даних. Вам потрібно розгорнути нову версію. Яку стратегію розгортання варто обрати і чому?

    Відповідь Ви повинні використовувати стратегію `Recreate` замість стандартної `RollingUpdate`. Стратегія `RollingUpdate` запускає нові Pods до завершення старих, що призведе до одночасної роботи двох екземплярів і пошкодження бази даних. При виборі `Recreate` Deployment спочатку видалить усі існуючі Pods і дочекається їх повного завершення. Тільки після того, як старі Pods зникнуть, він запустить нові, гарантуючи абсолютну ізоляцію між версіями ціною невеликого простою.
  2. Сценарій: Черговий інженер помічає, що Pods у Deployment споживають занадто багато пам’яті. У паніці він редагує ReplicaSet безпосередньо за допомогою kubectl edit rs, щоб змінити ліміти ресурсів. Що станеться далі і чому?

    Відповідь Зміни, внесені безпосередньо в ReplicaSet, будуть повністю проігноровані або швидко перезаписані, а Pods не оновляться. Deployments розроблені як декларативне джерело істини для підпорядкованих їм ReplicaSets. Якщо ReplicaSet відхиляється від шаблону Deployment або якщо ви намагаєтеся ініціювати оновлення на рівні ReplicaSet, контролер Deployment поверне стан до відповідності власним специфікаціям. Для вирішення проблеми з пам'яттю інженер має редагувати безпосередньо Deployment, що автоматично створить новий ReplicaSet з правильними лімітами.
  3. Сценарій: Ви запускаєте оновлення Deployment з новим тегом образу, але через 10 хвилин користувачі скаржаться, що застосунок усе ще старої версії. Ви запускаєте kubectl get pods і бачите ImagePullBackOff для нових Pods, тоді як старі все ще в статусі Running. Чому Deployment повівся саме так?

    Відповідь Deployment повівся ідеально, зупинивши оновлення завдяки стандартному налаштуванню `maxUnavailable` у стратегії `RollingUpdate`. Коли нові Pods не змогли завантажити образ і впали, вони ніколи не досягли стану `Ready`. Оскільки Deployment гарантує певну кількість доступних Pods, він відмовився видаляти старі, працюючі Pods, поки нові не стануть здоровими. Цей механізм самозбереження запобіг повному виходу кластера з ладу через неправильну конфігурацію.
  4. Сценарій: Під час значного стрибка трафіку ваша команда запускає rolling update для виправлення критичного багу. Посеред процесу оновлення трафік подвоюється знову, і ви виконуєте kubectl scale deployment web --replicas=10. Як Deployment обробляє цю подію масштабування під час активного оновлення?

    Відповідь Deployment достатньо розумний, щоб обробляти одночасне масштабування та оновлення без втрати трафіку, використовуючи механізм пропорційного масштабування. Він тимчасово призупиняє rolling update і розподіляє нову кількість реплік між старим і новим ReplicaSets пропорційно їхньому поточному розміру. Після завершення масштабування він відновлює rolling update, поступово переносячи масштабовані Pods зі старої версії на нову. Це гарантує миттєве отримання необхідної потужності для обробки стрибка трафіку з одночасним просуванням до виправлення багу.
  5. Сценарій: Ваша команда використовує maxSurge: 100% та maxUnavailable: 0% для Deployment з 10 репліками, щоб забезпечити надшвидке оновлення. Які наслідки для потужності кластера має така конфігурація під час оновлення?

    Відповідь Встановлення `maxSurge` на 100% означає, що Deployment спробує негайно створити повний дублікат із 10 нових Pods, зберігаючи при цьому всі 10 старих Pods працюючими (оскільки `maxUnavailable` дорівнює 0%). Це вимагає від вашого кластера Kubernetes наявності достатньої вільної потужності CPU та пам'яті для одночасної роботи 20 Pods під час фази оновлення. Якщо кластерний автоскейлер не спрацює вчасно або фізичних вузлів буде недостатньо, нові Pods застрягнуть у стані `Pending`. Хоча така конфігурація гарантує відсутність простоїв і швидке оновлення, вона дуже ресурсоємна і може спричинити вузькі місця в плануванні.
  6. Сценарій: Розробник скаржиться, що його щойно створений 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, масштабувати його, оновити та відкотити зміни.

Terminal window
# 1. Створити deployment
kubectl 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 deployment
  • kubectl scale deployment
  • kubectl set image
  • kubectl rollout status
  • kubectl rollout undo

Найкращі практики:

  • Завжди використовуйте Deployments (а не окремі Pods)
  • Використовуйте конкретні теги образів
  • Встановлюйте запити та ліміти ресурсів (requests/limits)

Модуль 1.5: Services — стабільна мережа для ваших Pods.