Задача
Deployment на 4 реплики обновляется до новой версии. В новой версии баг: приложение стартует, но readiness probe не проходит.
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1Вопросы: сколько подов старой версии останется работать и что произойдёт с выкаткой дальше — откатится ли она сама?
Что кажется очевидным
«Kubernetes увидит, что новая версия не поднимается, и откатит обратно».
Автоматического отката нет. Это одно из самых опасных заблуждений при выкатке.
Как это работает на самом деле
Два параметра управляют тем, как заменяются поды:
maxUnavailable — сколько подов сверх нужного количества может быть недоступно. При replicas: 4 и maxUnavailable: 1 минимум 3 пода должны быть доступны в любой момент.
maxSurge — сколько подов можно создать сверх желаемого числа. При maxSurge: 1 всего в кластере одновременно может существовать до 5 подов.
Оба параметра принимают и проценты (25% — значение по умолчанию для обоих), которые округляются: maxUnavailable вниз, maxSurge вверх.
Что происходит в нашем сценарии
- Deployment создаёт 1 новый под (разрешено
maxSurge: 1). Всего подов 5: 4 старых + 1 новый. - Одновременно можно погасить один старый (разрешено
maxUnavailable: 1) — контроллер убирает старый под. Остаётся 3 старых + 1 новый. - Новый под не проходит readiness → он не считается доступным.
- Доступных подов сейчас 3 — это ровно минимум, который разрешает
maxUnavailable. Дальше двигаться нельзя. - Выкатка замирает в этом состоянии.
Итог: 3 пода старой версии продолжают обслуживать трафик, один новый крутится в цикле неготовности. Сервис жив, но работает с уменьшенной ёмкостью — и так может висеть часами, пока кто-нибудь не заметит.
Именно так и задумано: механизм не даёт сломанной версии вытеснить рабочую. Но и сам он не откатится.
progressDeadlineSeconds
Есть параметр, который хотя бы фиксирует проблему:
spec:
progressDeadlineSeconds: 600 # по умолчанию 10 минутЕсли за это время не было прогресса, Deployment получает условие Progressing: False с причиной ProgressDeadlineExceeded. Важно понимать: это только отметка о статусе, никакого автоотката не происходит. Зато на неё можно повесить алерт или проверку в CI/CD.
Ответ
Работать останутся 3 пода старой версии, а выкатка встанет и будет висеть бесконечно. Автоматического отката Kubernetes не делает — по истечении progressDeadlineSeconds он лишь пометит Deployment как не прогрессирующий.
Что с этим делать
Откат — вручную или из пайплайна
# Посмотреть, что происходит (зависнет на "Waiting for rollout to finish")
kubectl rollout status deployment/api
# Откатить
kubectl rollout undo deployment/api
# К конкретной ревизии
kubectl rollout history deployment/api
kubectl rollout undo deployment/api --to-revision=3
# Остановить и продолжить выкатку
kubectl rollout pause deployment/api
kubectl rollout resume deployment/apiПрактичный приём для CI/CD — сделать проверку блокирующей:
kubectl rollout status deployment/api --timeout=5m || kubectl rollout undo deployment/apiТак пайплайн сам откатит неудачную выкатку. --timeout здесь обязателен, иначе команда будет ждать вечно.
Выбор параметров под задачу
| Цель | Настройка | Поведение |
|---|---|---|
| Без потери ёмкости | maxUnavailable: 0, maxSurge: 1 | Сначала поднимается новый под, потом гасится старый. Нужен запас ресурсов |
| Быстро, экономно | maxUnavailable: 1, maxSurge: 0 | Сначала гасим, потом поднимаем. Ёмкость временно падает |
| Быстрая выкатка | maxSurge: 50% | Много подов сразу; требует ресурсов |
| Осторожно | maxSurge: 1, maxUnavailable: 0 + пауза | Ручной контроль |
Для продовых сервисов, чувствительных к ёмкости, стандарт — maxUnavailable: 0. Цена: во время выкатки нужен запас ресурсов на дополнительный под, иначе он повиснет в Pending и выкатка встанет по другой причине.
Почему readiness критичен
Вся механика rolling update опирается на readiness probe: под без readiness считается доступным сразу после старта. Это означает, что Kubernetes начнёт гасить старые поды, не убедившись, что новые способны обслуживать трафик, — и вы выкатите нерабочую версию на всю ёмкость. Без корректного readiness (см. задачу 7) rolling update превращается из защиты в способ уронить сервис.
Аналогично: без preStop и корректного завершения выкатка будет ронять запросы даже при исправной новой версии (см. задачу 2).
Когда rolling update не подходит
- Миграции БД с несовместимой схемой — во время выкатки одновременно работают обе версии. Нужны обратно совместимые миграции (expand/contract).
- Stateful-нагрузки — там своя стратегия у StatefulSet, с последовательным обновлением по порядковым номерам.
- Нужен мгновенный переход или canary — это blue-green и canary-выкатки, обычно через Argo Rollouts, Flagger или service mesh.