Як організувати rolling update в Kubernetes
Rolling Update — це заміна коліс на багатоосній вантажівці або потязі, що рухається:
🟢 Junior Level
30-секундна відповідь
Rolling Update (Плавне хвильове оновлення) — це стандартна стратегія оновлення застосунків в об’єкті Deployment, при якій старі поди замінюються новими поступово, невеликими групами, без зупинки сервісу та без простою (Zero Downtime).
- Замість одночасного знищення всіх працюючих інстансів (стратегія
Recreate), Kubernetes запускає один або кілька нових подів. - Дочікується, поки нові поди успішно пройдуть пробу готовності (
readinessProbe). - Лише після підтвердження готовності нової версії Kubernetes починає плавно гасити старі поди.
- У будь-який момент часу користувачі отримують безперервний доступ до застосунку.
Наочна аналогія з життя
Rolling Update — це заміна коліс на багатоосній вантажівці або потязі, що рухається:
- У вантажівки 8 коліс.
- Механіки підіймають одну вісь, замінюють старе колесо на нове, перевіряють затягування болтів (
readinessProbe) і опускають його на дорогу. - Потім переходять до наступного колеса.
- Вантажівка ні на секунду не зупиняється і продовжує везти вантаж. Альтернатива
Recreate— заглушити двигун, зняти всі 8 коліс одразу, залишивши вантажівку на цеглинах (повний простій бізнесу).
Базовий маніфест Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Максимум +1 под понад норму (не більше 5 подів усього)
maxUnavailable: 0 # Жоден под не повинен бути недоступним (завжди мінімум 4)
selector:
matchLabels:
app: payment
template:
metadata:
labels:
app: payment
spec:
containers:
- name: payment-app
image: payment-service:2.1.0 # Конкретний тег версії (НЕ :latest!)
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
periodSeconds: 5
🟡 Middle Level
Математика maxSurge та maxUnavailable
Поведінка хвильового оновлення керується двома ключовими параметрами у відсотках або абсолютних числах:
Базова кількість реплік: replicas = 4
maxSurge: 1 -> У піку оновлення в кластері може бути створено: 4 + 1 = 5 подів
maxUnavailable: 0 -> У будь-який момент часу клієнтам мають відповідати мінімум: 4 - 0 = 4 поди
Фази оновлення за кроками:
- Крок 1: Створюється 1 новий под версії
v2. Усього в кластері 5 подів (4v1+ 1v2). - Крок 2: Новий под
v2проходитьreadinessProbe. Трафік починає надходити на нього. - Крок 3: Видаляється 1 старий под
v1. У кластері залишається 4 поди (3v1+ 1v2). - Крок 4: Процес циклічно повторюється до повної заміни всіх 4 подів на версію
v2.
Керування процесом через kubectl rollout
Kubernetes надає потужний набір команд для контролю деплою:
# 1. Запустити оновлення нової версії образу
kubectl set image deployment/payment-service payment-app=payment-service:2.2.0
# 2. Відстежувати прогрес оновлення в реальному часі
kubectl rollout status deployment/payment-service
# 3. Призупинити деплой (наприклад, для ручної перевірки на канарковому поді)
kubectl rollout pause deployment/payment-service
# 4. Відновити деплой далі
kubectl rollout resume deployment/payment-service
# 5. Переглянути історію ревізій
kubectl rollout history deployment/payment-service
# 6. МИТТЄВИЙ ВІДКАТ до попередньої стабільної ревізії при аварії
kubectl rollout undo deployment/payment-service
Внутрішній механізм: Роль ReplicaSet
Об’єкт Deployment сам по собі не керує подами безпосередньо. Він керує об’єктами ReplicaSet:
- При зміні секції
spec.templateконтролер Deployment створює новий ReplicaSet (наприклад,payment-78d4f8). - Поступово збільшує лічильник
replicasу новому ReplicaSet і зменшує його в старому ReplicaSet (payment-59c6b8). - Старий ReplicaSet залишається в кластері зі значенням
replicas: 0. Це дозволяє виконати командуrollout undoза пів секунди без повторної генерації конфігурацій!
🔴 Senior Level
Проблема співіснування версій та патерн «Expand / Contract»
Під час Rolling Update у кластері одночасно працюють поди старої версії (v1) та нової версії (v2):
- Запит одного користувача може потрапити на
v1, а наступний — наv2. - Якщо розробник у версії
v2видалить стовпчик у базі даних або перейменує поле в JSON, працюючі подиv1негайно почнуть падати з помилками.
Патерн еволюції БД «Expand and Contract» (Паралельний запуск):
Фаза 1 (Expand): Виконуємо міграцію Liquibase/Flyway: ДОДАЄМО нову колонку як NULLABLE.
Стара версія v1 продовжує працювати, ігноруючи цю колонку.
Фаза 2 (Rollout): Викочуємо Rolling Update версії v2. v2 пише дані і в стару, і в нову колонку.
Фаза 3 (Contract):Після 100% успіху викочування окремим скриптом видаляємо стару непотрібну колонку.
Конфлікт із PodDisruptionBudget (PDB) та ResourceQuota
Дві найчастіші причини «зависання» Rolling Update у продакшені:
1. Зависання через ResourceQuota (Брак квот)
Якщо в Namespace встановлена жорстка квота, наприклад рівно на 10 подів, а у вас працює replicas: 10:
- При деплої з
maxSurge: 2Kubernetes спробує створити 11-й та 12-й под. - API-сервер заблокує їхнє створення з помилкою
exceeded quota. - Нові поди зависнуть у статусі
Pending, і оновлення заблокується на 10 хвилин (progressDeadlineSeconds). - Рішення: при дефіциті квот використовувати конфігурацію
maxSurge: 0,maxUnavailable: 1(спочатку звільнити місце, потім створювати).
2. Зависання через конфлікт із PodDisruptionBudget
Якщо оголошено PDB з вимогою minAvailable: 100%, а в Deployment задано maxUnavailable: 25%:
- Контролер деплою не зможе видалити жоден старий под, оскільки це порушить контракт PDB!
Ідеальна формула 100% Zero-Downtime для Java/Spring Boot
Для гарантованої відсутності помилок 502 Bad Gateway під час деплою необхідне одночасне виконання 4 умов:
maxUnavailable: 0— не вимикати старі поди до підняття нових.- Надійна
readinessProbe— новий Spring Boot под починає отримувати трафік тільки після повного завантаження контексту. preStop: sleep 10— затримка передSIGTERMдля компенсації мережевого лагу оновленняiptablesагентамиkube-proxy.- Spring Boot Graceful Shutdown — параметр
server.shutdown: gracefulвapplication.yaml, щоб Tomcat коректно завершив активні транзакції перед зупинкою.
4 Tricky Questions
1. Чому використання тегу образу :latest (наприклад, image: my-app:latest) повністю ламає механізм автоматичного запуску Rolling Update в Kubernetes?
Відповідь:
Контролер Deployment відстежує зміни в маніфесті за хешем специфікації spec.template (поле pod-template-hash):
- Якщо ви зібрали новий Docker-образ, запушили його в реєстр під тим же ім’ям
my-app:latestі виконалиkubectl apply -f deployment.yaml, то з погляду API-сервера маніфест не змінився на жоден символ. - Контролер бачить колишній рядок
image: my-app:latest, не реєструє факту оновлення і взагалі не запускає процедуру Rolling Update. - Усі поди продовжать працювати на старому коді. Для коректної роботи завжди необхідно використовувати семантичні теги версій (
:1.4.2) або SHA256-хеш дайджесту образу (@sha256:...).
2. Що станеться з об’єктами ConfigMap та Secret, якщо виконати команду відкату ревізії kubectl rollout undo?
Відповідь: Вони НЕ відкотяться! Це критична пастка для DevOps-інженерів:
- Механізм ревізій
Deploymentта його дочірніхReplicaSetзберігає історію виключно специфікації самого пода (образи, змінні, порти, селектори). - Зовнішні об’єкти
ConfigMapтаSecretверсіонуються незалежно. - Якщо ви оновили конфіг у
ConfigMapі викотили нову версію, а потім виконалиrollout undo, под відкотиться на старий Docker-образ, але монтуватиме НОВИЙ, вже зміненийConfigMap! Це може призвести до несумісності та падіння старого бінарника. - Рішення: патерн Immutable ConfigMaps із додаванням хешу в ім’я конфігу (
app-config-v123) або використання інструментів GitOps (Helm / ArgoCD).
3. Для чого потрібен параметр spec.progressDeadlineSeconds, і що відбувається при його перевищенні під час збою деплою?
Відповідь:
progressDeadlineSeconds(за замовчуванням 600 секунд / 10 хвилин) задає максимальний час, протягом якого процес оновлення повинен демонструвати прогрес (створення нових подів, проходження readiness probe).- Якщо нові поди зависають у помилці (наприклад,
CrashLoopBackOffабоImagePullBackOff) і прогресу немає протягом цього періоду:- Контролер виставляє умові
ProgressingстатусFalseіз причиноюProgressDeadlineExceeded. - Автоматичного відкату (Rollback) Kubernetes НЕ виконує! Процес оновлення просто завмирає в поточній проміжній точці (частина трафіку на старих подах, частина завислих подів), сигналізуючи моніторингу або CI/CD пайплайну про необхідність аварійного втручання.
- Контролер виставляє умові
4. У чому полягає різниця між стратегіями оновлення RollingUpdate у Deployment та у StatefulSet?
Відповідь:
- У
Deployment: поди ефемерні, не мають стабільного мережевого імені та постійного диска. Вони можуть створюватися та видалятися пачками в довільному порядку з перевищенням ліміту (maxSurge). - У
StatefulSet:- Не підтримується концепція
maxSurge(не можна перевищувати бажану кількість реплік, оскільки кожен под прив’язаний до власного виділеногоPersistentVolume). - Оновлення відбувається строго по одному в строго зворотному порядковому номері: спочатку под
app-2, потімapp-1, потімapp-0. - Новий под
app-Nстворюється зі збереженням колишнього диска та мережевого DNS-імені тільки ПІСЛЯ того, як старий под із цим номером був повністю зупинений та відмонтований.
- Не підтримується концепція
🎯 Шпаргалка для інтерв’ю
Головне про Rolling Update
- Суть: плавне хвильове заміщення старих подів новими без зупинки сервісу.
maxSurge: скільки подів можна створити понад бажану кількість (запас потужності).maxUnavailable: скільки подів припустимо вивести з ладу під час процесу.- Формула Zero Downtime:
maxUnavailable: 0+readinessProbe+preStop: sleep 10+ Graceful Shutdown у Spring Boot. - Роль ReplicaSet: Deployment створює новий RS, нарощує його і зберігає старий із 0 реплік для миттєвого відкату (
rollout undo). - Еволюція БД: патерн Expand/Contract обов’язковий, оскільки v1 та v2 співіснують під час деплою.
- Антипатерн :latest: при використанні
:latestконтролер не бачить змін маніфесту і не запускає деплой.
Порівняння стратегій деплою в Kubernetes
| Стратегія | Downtime | Додаткові ресурси | Швидкість відкату | Особливості |
| :— | :—: | :—: | :—: | :— |
| RollingUpdate | 🟢 Zero | У межах maxSurge | Швидкий (rollout undo) | Дві версії працюють одночасно |
| Recreate | 🔴 Є | 0 (спочатку видаляє все) | Тривалий (перестворення) | Для баз даних і несумісних схем |
| Blue-Green | 🟢 Zero | +100% (подвоєння кластера) | Миттєвий (світч Ingress) | Ізоляція версій, дорого за ресурсами |
| Canary | 🟢 Zero | + відсоток на канарку | Миттєвий | Перевірка на 5–10% реальних користувачів |
Червоні прапорці на співбесіді (Чого говорити не можна)
- ❌ «Щоб оновити застосунок, ми використовуємо образ із тегом :latest» — Kubernetes не виявить змін і оновлення не запуститься.
- ❌ «При виконанні rollout undo база даних та секрети автоматично повертаються до старої версії» — ConfigMaps, Secrets та БД живуть окремо і не відкочуються.
- ❌ «Rolling Update гарантує, що дві версії застосунку ніколи не працюватимуть одночасно» — вони гарантовано працюють паралельно на етапі перемикання.