Задача 12. Rolling update: maxSurge и maxUnavailable

Выкатка новой версии останавливается на половине и висит часами, откат не помогает. Разбираем, как считаются maxSurge и maxUnavailable, при чём тут readiness и почему progressDeadlineSeconds важнее, чем кажется.
Опубликовано:

Задача

Deployment на 4 реплики обновляется до новой версии. В новой версии баг: приложение стартует, но readiness probe не проходит.

YAML
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 вверх.

Что происходит в нашем сценарии

  1. Deployment создаёт 1 новый под (разрешено maxSurge: 1). Всего подов 5: 4 старых + 1 новый.
  2. Одновременно можно погасить один старый (разрешено maxUnavailable: 1) — контроллер убирает старый под. Остаётся 3 старых + 1 новый.
  3. Новый под не проходит readiness → он не считается доступным.
  4. Доступных подов сейчас 3 — это ровно минимум, который разрешает maxUnavailable. Дальше двигаться нельзя.
  5. Выкатка замирает в этом состоянии.

Итог: 3 пода старой версии продолжают обслуживать трафик, один новый крутится в цикле неготовности. Сервис жив, но работает с уменьшенной ёмкостью — и так может висеть часами, пока кто-нибудь не заметит.

Именно так и задумано: механизм не даёт сломанной версии вытеснить рабочую. Но и сам он не откатится.

progressDeadlineSeconds

Есть параметр, который хотя бы фиксирует проблему:

YAML
spec:
  progressDeadlineSeconds: 600 # по умолчанию 10 минут
Нажмите, чтобы развернуть и увидеть больше

Если за это время не было прогресса, Deployment получает условие Progressing: False с причиной ProgressDeadlineExceeded. Важно понимать: это только отметка о статусе, никакого автоотката не происходит. Зато на неё можно повесить алерт или проверку в CI/CD.

Ответ

Работать останутся 3 пода старой версии, а выкатка встанет и будет висеть бесконечно. Автоматического отката Kubernetes не делает — по истечении progressDeadlineSeconds он лишь пометит Deployment как не прогрессирующий.

Что с этим делать

Откат — вручную или из пайплайна

BASH
# Посмотреть, что происходит (зависнет на "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 — сделать проверку блокирующей:

BASH
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 не подходит


Дальше: Задача 13. Когда под увидит новый ConfigMap.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша