Learning Platform
Глоссарий Troubleshooting
Урок 17.05 · 20 мин
Средний
Strategy comparisondecision treePodDisruptionBudgetHelm hooksschema migrationbest practices

Сравнение стратегий и выбор для production

Четыре стратегии (RollingUpdate, Recreate, Blue-green, Canary) — это не “лучше / хуже”. Каждая решает свой класс задач, и production-ready команда умеет выбрать правильную для конкретного сервиса. В этом уроке — decision tree, сравнительная таблица и production best practices, которые делают любой rollout безопасным.


L4 vs L7 load balancing: transport против application layer

Сравнительная таблица

StrategyDowntimeResource overheadRollback speedComplexityK8s native
RollingUpdateNone+maxSurge replicasSlow (новый rolling update)LowYes
RecreateYesNoneSlow (новый Recreate)LowestYes
Blue-greenNone2× (двойной)Instant (switch selector)MediumManual
CanaryNone+canary replicas (~10%)Adjust replicasMediumManual
Progressive (Argo Rollouts)NoneVariableAutomatic + analysisHighCRD

Расшифровка ключевых колонок:

  • Downtime: есть ли период когда 0 Pods Ready. Recreate — единственная с downtime.
  • Resource overhead: сколько extra Pods нужно во время rollout. Blue-green — самый дорогой (2×).
  • Rollback speed: насколько быстро можно откатиться. Blue-green с idle blue Pods — instant. RollingUpdate — нужно прогнать rolling update обратно.
  • Complexity: сколько ручной работы / extra инфраструктуры. Native K8s strategies — простые, blue-green/canary — требуют ручного управления Services, progressive — нужны CRD контроллеры.

Decision tree: какую выбрать

Выбор стратегии deploy
вопрос 1Если приложение НЕ выдерживает работу двух версий одновременно — это в первую очередь stateful или хранит in-memory invariants. Нельзя RollingUpdate / canary / blue-green (все они держат две версии живыми хоть на секунду).
даRecreate strategy. type=Recreate. Все старые Pods убиваются, потом все новые создаются. Downtime неизбежен, но atomicity гарантирована. Use case: schema migration, single-writer, RWO PVC с одним Pod.
нетМожно использовать любую no-downtime стратегию. Дальше выбор зависит от рисков release-а и доступных ресурсов.
вопрос 2: high-risk release?
high-risk + instant rollback criticalНапример, major version, breaking changes, новый стек. Нужна возможность мгновенного отката. Резервируем 2× ресурсов на blue + green. Главное преимущество blue-green: один patch для отката, не новый rolling update.
middle-risk, validate в prod trafficХотим увидеть как новая версия ведёт себя на реальных пользователях, но только на малой fraction. Canary через replicas ratio или Service Mesh weight. Постепенный shift с мониторингом.
low-risk, обычное обновлениеБольшинство deploy-ов. RollingUpdate с разумными maxSurge/maxUnavailable + readinessProbe. Никакого extra effort, K8s делает сам. Default для stateless services.
вопрос 3: automate с metrics-based gate?
да, нужны автоматические pauses + analysis + rollbackArgo Rollouts / Flagger. Декларативные шаги (setWeight 10 → wait → analysis → setWeight 25 → ...) + automatic abort при failed metrics. Требует install controller-а и обычно Service Mesh для precise traffic.

Schema migrations: специальный случай

Database schema migrations — самый частый источник deployment problems. Главный вопрос: backward-compatible ли изменение?

Backward-compatible изменения (типовое 80%)

  • Добавление nullable column
  • Добавление нового table
  • Добавление nullable index
  • Расширение type (VARCHAR(50)VARCHAR(100))

Эти изменения не ломают старую версию. Можно делать RollingUpdate:

# Helm chart с pre-upgrade migration
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration-v1.5
  annotations:
    helm.sh/hook: pre-upgrade
    helm.sh/hook-weight: "1"
    helm.sh/hook-delete-policy: hook-succeeded
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: my-app:v1.5
          command: ["./migrate", "up"]
      restartPolicy: OnFailure

Workflow:

  1. helm upgrade запускает pre-upgrade Job (migration). Schema меняется.
  2. После успеха Job — Helm обновляет Deployment (RollingUpdate).
  3. Старая версия работает с новой schema (backward-compatible).
  4. Новые Pods используют новые поля.

Non-backward-compatible изменения

  • Rename column (namefull_name)
  • Drop column
  • Change type incompatibly (VARCHARINT)
  • Drop table

Нельзя RollingUpdate — в момент рассогласования старая и новая версии обе ломаются. Варианты:

Вариант A: двухфазный deploy (правильный)

  1. Phase 1: deploy intermediate version, которая работает с обеими schemas (read both, write both)
  2. Run data migration (backfill new column from old)
  3. Deploy version that uses only new schema
  4. Drop old column в third phase

Вариант B: Recreate + migration job

  1. Pre-upgrade Job выполняет breaking migration
  2. Deployment.strategy=Recreate — все старые Pods убиваются ДО создания новых
  3. Новые Pods стартуют с новым кодом, новой schema
  4. Downtime 30s — несколько минут, но atomicity
WARNING

Если у тебя RollingUpdate Deployment + non-backward-compatible migration — это bug. В момент когда новые Pods Ready (и Service балансирует на них), старые Pods всё ещё работают на старой schema, но колонка уже переименована. Старые Pods 500-ят, пока их не убьют. Решение: либо A (двухфазный), либо B (Recreate).


PodDisruptionBudget: контроль над evictions

PodDisruptionBudget (PDB) — отдельный объект, который ограничивает сколько Pod-ов могут быть одновременно недоступными во время voluntary disruptions: node drain, autoscaler, kubectl evict, но НЕ во время rolling update (rolling update controls availability через own maxUnavailable).

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  minAvailable: 2     # или maxUnavailable: 1
  selector:
    matchLabels:
      app: web

Это значит: при node drain или admin eviction, kube-scheduler не позволит уйти больше чем (replicas - minAvailable) Pod-ам одновременно. Гарантирует SLA на доступность при инфраструктурных операциях.

NOTE

PDB и Deployment.strategy.maxUnavailable — это разные механизмы. PDB защищает от voluntary disruptions (node drain, autoscaler). maxUnavailable управляет rolling update. PDB не блокирует Deployment rolling update — Deployment controller считает свою собственную availability через ReplicaSets. Production-grade: ставить ОБА: PDB для инфраструктурных операций + maxUnavailable для controlled deployments.


Best practices: чек-лист для production deploy

1. Readiness probe — обязательно

Без readiness probe Phase=Running считается готовностью, и rolling update убивает старые Pods до того как новые реально готовы. Всегда:

readinessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

2. Resource requests — обязательно

Без requests scheduler может разместить Pod на overloaded ноду, где старт будет CPU-throttled. Это удлиняет initialDelaySeconds и может ломать readiness window.

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    memory: 256Mi

3. PodDisruptionBudget для multi-replica services

spec:
  minAvailable: 50%   # для 4 replicas — минимум 2 всегда доступны

Защищает от node drain не-вовремя.

4. progressDeadlineSeconds

spec:
  progressDeadlineSeconds: 300   # 5 минут на rollout

После этого срока Deployment.status.conditions[].type=Progressing помечается False. CI/CD должен абортировать deploy и rollback.

5. change-cause annotation для traceability

metadata:
  annotations:
    kubernetes.io/change-cause: "Bump nginx 1.27 -> 1.28 — CVE-2024-1234"

В production без этого не получится понять задним числом, что было в каждом rollout.

6. CI testing rolling updates на staging

Перед production:

  • Deploy на staging cluster
  • Wait для rolling update
  • Smoke test через curl / synthetic load
  • Только потом promote в production

7. terminationGracePeriodSeconds + preStop

Для приложений с активными connections:

spec:
  terminationGracePeriodSeconds: 60
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command: ["sh", "-c", "sleep 5 && /app/drain"]

PreStop runs до SIGTERM, sleep 5 даёт endpoint-controller время удалить Pod из Service (избегает trafic на shutting-down Pod), потом /app/drain делает graceful drain in-flight requests.


CKAD задание: choose + implement

Типовое CKAD задание:

“У вас есть PostgreSQL Deployment с 1 replica, RWO PVC. Изменить image на новую версию без deadlock.”

Анализ:

  • RWO PVC + 1 replica → RollingUpdate с maxSurge=1 даст Multi-Attach error если новый Pod schedulится на другую ноду
  • Решение: strategy.type=Recreate
kubectl patch deploy/postgres -p '{"spec":{"strategy":{"$retainKeys":["type"],"type":"Recreate"}}}'
kubectl set image deploy/postgres postgres=postgres:16
kubectl rollout status deploy/postgres

Другое задание:

“У вас 10 Pods nginx Deployment, нужно протестировать новую версию на 10% трафика.”

Анализ:

  • 10% трафика, разделить через replicas ratio
  • Canary через 2 Deployments + один Service

Реализация — стандартный canary YAML (см. урок 4).


Killer-моменты

  • Default стратегия — RollingUpdate. Recreate, blue-green, canary — это исключения для специфических кейсов.
  • Schema migration + RollingUpdate non-backward-compatible = bug. Либо двухфазный deploy, либо Recreate с pre-upgrade Job.
  • PDB и Deployment.maxUnavailable — независимые. PDB защищает от voluntary disruptions, Deployment.maxUnavailable управляет rolling update.
  • Best practice чек-лист: readinessProbe + resource requests + PDB + progressDeadlineSeconds + change-cause + preStop drain.
  • CI testing на staging — единственный способ отловить проблемы rolling update до production (медленный startup, неправильные probes, resource starvation).

Проверка знанийKnowledge check
PostgreSQL Deployment, replicas=1, RWO PVC. Тебе сказали 'обнови image, не оставляй кластер в broken state'. Какая стратегия и почему именно эта?
ОтветAnswer
Recreate. Почему не RollingUpdate: при maxSurge>=1 controller хочет создать новый Pod до убийства старого. RWO PVC может быть смонтирован только на одной ноде. Если scheduler разместит новый Pod на ДРУГОЙ ноде — Multi-Attach error, новый Pod в Pending, старый держит PVC, rollout висит. С maxSurge=0 + maxUnavailable=1 это работает, но это эквивалент Recreate с дополнительной задержкой. Чистое решение: strategy.type=Recreate. Старый Pod убит → PVC detach → новый Pod создаётся, монтирует PVC. Downtime ~30s, но детерминированный. На CKAD это типовое задание про RWO + Deployment.
Проверка знанийKnowledge check
Чем PodDisruptionBudget отличается от spec.strategy.rollingUpdate.maxUnavailable и почему оба нужны?
ОтветAnswer
(1) Scope: PDB защищает от VOLUNTARY DISRUPTIONS — node drain (kubectl drain), cluster autoscaler scale-down, kubectl evict. Эти операции уважают PDB и блокируются если выселение нарушит minAvailable. (2) maxUnavailable управляет ТОЛЬКО RollingUpdate Deployment-а — сколько старых Pods могут одновременно быть unavailable во время rollout. Этот параметр для PDB irrelevant. (3) PDB не блокирует rolling update — он не часть рассмотрения для Deployment controller. Production: оба нужны, потому что они защищают разные риски. PDB защищает SLA при инфраструктурных операциях. maxUnavailable — при code-deploys. Например: PDB minAvailable=2 + Deployment maxUnavailable=1 даёт защиту что во время drain ноды и одновременно во время rolling update минимум 2 Pods всегда работают.
Проверка знанийKnowledge check
Helm chart с RollingUpdate Deployment + breaking schema migration (renamed column). Что произойдёт во время helm upgrade и как починить?
ОтветAnswer
Сценарий: pre-upgrade Job переименовывает column в DB. Helm запускает rolling update Deployment. В момент рассогласования: старые Pods (старый код, ожидают старое имя column) и новые Pods (новый код) сосуществуют ~30 секунд. Старые Pods 500-ят (column не найдена), новые работают ok. Service балансирует на оба — половина запросов 500. Решения: (1) Двухфазный deploy — сначала v1.5 которая работает с обоими именами, потом migration, потом v2 которая только новое имя. (2) Изменить Deployment.strategy=Recreate в chart — все старые Pods убиваются до создания новых, нет рассогласования, но downtime 30s-2min. (3) Использовать Argo Rollouts с проверкой metrics — но не решит fundamental issue, два кода не могут сосуществовать. На production: либо A, либо B, в зависимости от tolerated downtime.
Проверка знанийKnowledge check
Сравни blue-green и canary по двум осям: ресурсы и rollback speed. Какие use cases для каждой?
ОтветAnswer
Blue-green: ресурсы 2x (полная копия green + blue одновременно), rollback INSTANT (один kubectl patch svc selector обратно). Use case: high-risk releases (major version, big refactor), где critical иметь instant rollback. Если что-то сломалось — за секунду вернулись на blue. Цена: двойной footprint в Pods/CPU/memory всё время сосуществования. Canary: ресурсы +10-25% (canary Deployment маленький относительно production), rollback быстрый (scale canary to 0 — endpoints исчезают). Use case: validate новую версию на реальном трафике, медленный rollout с мониторингом. Цена: complexity управления через 2 Deployments + shared Service + progressive scale. Истина: на практике для большинства deploy-ов используется RollingUpdate (no overhead), blue-green/canary применяются для critical releases.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Чем PodDisruptionBudget принципиально отличается от Deployment.spec.strategy.rollingUpdate.maxUnavailable?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5