Зачем нужны стратегии обновления в Kubernetes
Обновление подов «на лету» без стратегии - прямой путь к простоям и неконсистентному состоянию сервиса. Kubernetes предоставляет встроенные механизмы и поддерживает продвинутые паттерны, которые позволяют контролировать процесс замены контейнеров и минимизировать риски для production-среды.
Три базовые стратегии - Rolling Update, Blue-Green и Canary - решают разные задачи. Rolling Update постепенно заменяет поды с сохранением доступности. Blue-Green создаёт отдельную среду и мгновенно переключает трафик. Canary направляет часть пользователей на новую версию для проверки на реальной нагрузке. Выбор стратегии зависит от критичности сервиса, доступных ресурсов и требуемой скорости отката.
В этом руководстве разобраны практические команды, YAML-конфигурации и метрики для Grafana по каждой стратегии. Материал ориентирован на DevOps-инженеров и системных администраторов, которые хотят обновлять приложения без ночных дежурств и инцидентов на продакшене. Если вы ищете готовые production-манифесты для веб-приложений и микросервисов, обратите внимание на руководство по настройке Deployment в Kubernetes.
Сравнение стратегий: как выбрать подходящую
Критерии выбора сводятся к четырём параметрам: допустимое время простоя, потребление ресурсов, сложность настройки и скорость отката. Таблица ниже помогает сопоставить стратегии по этим параметрам.
| Параметр | Rolling Update | Blue-Green | Canary |
|---|---|---|---|
| Время простоя | Нулевое | Нулевое | Нулевое |
| Потребление ресурсов | Минимальное (+maxSurge подов) | Удвоенное (два полных окружения) | Пропорционально доле трафика |
| Сложность настройки | Низкая (встроен в Deployment) | Средняя (требует управления Service/Ingress) | Высокая (требует Service Mesh или Ingress-аннотаций) |
| Скорость отката | Постепенный (rollout undo) | Мгновенный (переключение Service) | Мгновенный (изменение веса трафика) |
| Подходит для stateful-приложений | Ограниченно (требует StatefulSet с особыми настройками) | Да (при клонировании PVC) | Да (при разделении данных по версиям) |
Типовые сценарии выбора:
- Обычное обновление микросервиса - Rolling Update. Достаточно изменить образ в Deployment и дать Kubernetes постепенно заменить поды.
- Критичный сервис с нулевым RTO - Blue-Green. Новая версия разворачивается параллельно, проверяется и принимает трафик мгновенно.
- Мультитенантная среда с проверкой на части пользователей - Canary. Трафик переключается постепенно, метрики сравниваются в Grafana, при аномалиях откат происходит за секунды.
Рекомендация: начните с Rolling Update. Для высоконагруженных систем с жёсткими требованиями к доступности рассмотрите Blue-Green. Canary внедряйте, когда нужен контроль над распределением трафика и проверка гипотез на подмножестве пользователей. Детальный разбор продвинутых сценариев с YAML-манифестами есть в статье про продвинутые стратегии развертывания в Kubernetes.
Rolling Update: обновление с нулевым простоем по умолчанию
Rolling Update - стратегия по умолчанию для ресурса Deployment. Kubernetes постепенно заменяет старые поды новыми, опираясь на readiness probes для определения момента, когда новый под готов принимать трафик. Процесс идёт без остановки сервиса: пока часть подов обновляется, оставшиеся продолжают обрабатывать запросы.
Механизм работает так: контроллер Deployment создаёт новые поды с обновлённой спецификацией и одновременно удаляет старые. Скорость замены регулируется двумя параметрами - maxSurge и maxUnavailable. Readiness-пробы гарантируют, что трафик пойдёт только на поды, прошедшие проверку готовности. Подробнее о настройке проб и ограничениях ресурсов читайте в руководстве по Deployment.
Настройка стратегии Rolling Update в Deployment
Ключевые параметры в поле spec.strategy.rollingUpdate:
- maxSurge - количество подов, которое можно создать сверх желаемого числа реплик. Может быть абсолютным числом или процентом. Значение 25% при 4 репликах означает, что во время обновления допускается один дополнительный под.
- maxUnavailable - количество подов, которое может быть недоступно в процессе обновления. При 25% и 4 репликах один под может находиться в состоянии пересоздания.
Пример манифеста для production-сервиса с четырьмя репликами:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
version: v1.2.0
spec:
containers:
- name: api-gateway
image: registry.example.com/api-gateway:v1.2.0
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Параметр maxUnavailable: 0 гарантирует, что ни один под не будет удалён, пока новый не пройдёт readiness probe. Это критично для сервисов, обрабатывающих платёжные транзакции или чувствительные к потере соединений. Параметр maxSurge: 1 разрешает создать один дополнительный под сверх лимита - убедитесь, что в кластере достаточно ресурсов.
Для stateless-микросервисов с высоким уровнем репликации можно использовать процентные значения: maxSurge: 25% и maxUnavailable: 25%. Это ускоряет обновление ценой кратковременного снижения общей ёмкости. Детальные сценарии настройки этих параметров с YAML-примерами для production, тестов и Canary разобраны в гайде по настройке maxSurge и maxUnavailable.
Контроль процесса: kubectl rollout и мониторинг
Базовые команды для управления обновлением:
# Запуск обновления (изменение образа)
kubectl set image deployment/api-gateway api-gateway=registry.example.com/api-gateway:v1.3.0
# Отслеживание статуса
kubectl rollout status deployment/api-gateway
# Приостановка обновления (если заметили аномалию)
kubectl rollout pause deployment/api-gateway
# Возобновление после проверки
kubectl rollout resume deployment/api-gateway
# Просмотр истории ревизий
kubectl rollout history deployment/api-gateway
# Откат к предыдущей версии
kubectl rollout undo deployment/api-gateway
# Откат к конкретной ревизии
kubectl rollout undo deployment/api-gateway --to-revision=3
Для мониторинга в Prometheus и Grafana отслеживайте следующие метрики:
kube_deployment_status_replicas_available- количество доступных реплик. Значение должно оставаться равнымkube_deployment_spec_replicasна протяжении всего обновления.kube_deployment_status_replicas_updated- количество обновлённых реплик. Растёт по мере продвижения rollout.rate(kube_pod_container_status_restarts_total[5m])- скорость перезапусков контейнеров. Всплеск указывает на проблемный образ.
PromQL-запрос для алерта на долгое обновление (более 10 минут):
time() - kube_deployment_status_observed_generation > 600
and
kube_deployment_status_replicas_updated < kube_deployment_spec_replicas
Настройте панель Grafana с графиком количества реплик по версиям и алертом в Slack или Telegram при отклонении времени обновления от нормы. Это даст сигнал дежурному инженеру до того, как проблема затронет пользователей.
Blue-Green: мгновенное переключение на новую версию
Стратегия Blue-Green предполагает поддержку двух идентичных сред: Blue - текущая production-версия, Green - новая версия. Green разворачивается параллельно, проходит проверку, после чего трафик переключается на неё целиком. Откат выполняется обратным переключением.
Главное преимущество - мгновенное переключение и такой же мгновенный откат. Нет промежуточных состояний, когда часть пользователей получает старую версию, а часть - новую. Недостаток - удвоенное потребление ресурсов на время развёртывания Green-среды. Для крупных кластеров с десятками микросервисов это может быть существенно.
Blue-Green подходит для критичных систем, где даже кратковременная деградация недопустима: платёжные шлюзы, системы аутентификации, API с жёсткими SLA. Если вы планируете миграцию приложений между кластерами с минимальным простоем, посмотрите руководство по миграции приложений в Kubernetes.
Реализация Blue-Green через Namespace и Service
Пошаговая инструкция с командами:
- Разверните Green-версию в отдельном Namespace. Скопируйте манифесты текущего приложения, измените образ и Namespace.
kubectl create namespace app-green kubectl apply -f deployment-green.yaml -n app-green kubectl apply -f service-green.yaml -n app-green - Проверьте работоспособность Green. Используйте port-forward для прямого доступа к Green-сервису и прогоните smoke-тесты.
kubectl port-forward svc/api-service-green 8081:8080 -n app-green curl http://localhost:8081/healthz - Переключите production Service на Green. Измените селектор в Service так, чтобы он указывал на поды Green-версии.
kubectl patch service api-service -p '{"spec":{"selector":{"app":"api","version":"green"}}}' - Удалите старую Blue-среду после подтверждения стабильной работы Green.
kubectl delete namespace app-blue
Пример Service с внешним именем для тестового доступа к Green до переключения:
apiVersion: v1
kind: Service
metadata:
name: api-service-green-test
spec:
type: ClusterIP
selector:
app: api
version: green
ports:
- port: 80
targetPort: 8080
Автоматизация переключения с помощью Ingress
Ingress-контроллер даёт более гибкое управление трафиком. Вместо изменения селектора Service вы переключаете бэкенд в Ingress. Это позволяет сделать плавный переход, направляя часть трафика на Green через канареечные аннотации.
Пример Ingress с двумя бэкендами для Nginx Ingress Controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "100"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-green
port:
number: 80
При значении canary-weight: 100 весь трафик идёт на Green. Для плавного перехода уменьшайте вес с 0 до 100 с шагом 20-30%, отслеживая метрики ошибок на каждом шаге. Это даёт преимущества Canary-подхода внутри Blue-Green схемы.
Canary: постепенное переключение трафика на новую версию
Canary-развертывание направляет небольшой процент трафика на новую версию приложения. Вы начинаете с 5%, мониторите метрики, увеличиваете долю до 25%, 50%, 100%. При росте ошибок или задержек откат выполняется изменением веса до нуля - быстро и без пересоздания подов.
Стратегия незаменима для мультитенантных систем, где ошибка в новой версии затрагивает только часть пользователей. Она также используется для A/B-тестирования: две версии работают параллельно, и вы сравниваете бизнес-метрики - конверсию, retention, средний чек. Реализация возможна через Service Mesh (Istio, Linkerd) или через аннотации Nginx Ingress Controller.
Настройка Canary с помощью Istio
Istio управляет трафиком на уровне sidecar-прокси, что даёт тонкий контроль без изменения кода приложения. Базовая настройка включает DestinationRule для определения подмножеств версий и VirtualService для распределения трафика.
DestinationRule определяет версии:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: api-dr
spec:
host: api-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
VirtualService распределяет трафик: 90% на v1, 10% на v2.
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-vs
spec:
hosts:
- api-service
http:
- route:
- destination:
host: api-service
subset: v1
weight: 90
- destination:
host: api-service
subset: v2
weight: 10
Постепенно увеличивайте вес v2: 10% → 30% → 50% → 100%. На каждом шаге сравнивайте latency и error rate между версиями в Grafana. Istio автоматически экспортирует метрики с тегами версий, что упрощает настройку дашбордов.
Canary через Nginx Ingress Controller
Без Service Mesh можно использовать канареечные аннотации Nginx Ingress. Создайте основной Ingress для стабильной версии и канареечный Ingress для новой.
Основной Ingress (v1):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-v1
port:
number: 80
Канареечный Ingress (v2) с 5% трафика:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "5"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service-v2
port:
number: 80
Для отката удалите канареечный Ingress или измените canary-weight на 0. Этот подход проще в настройке, чем Istio, но даёт меньше возможностей для маршрутизации по заголовкам или сессиям.
Мониторинг обновлений в Grafana: ключевые метрики и дашборды
Без мониторинга любая стратегия обновления - это гадание. Prometheus собирает метрики из kube-state-metrics и cAdvisor, Grafana визуализирует их в реальном времени. Настройте дашборд до первого обновления, чтобы иметь baseline для сравнения.
Метрики для Rolling Update
Контролируйте три показателя:
- Доступность реплик:
kube_deployment_status_replicas_availableне должна падать нижеkube_deployment_spec_replicasминусmaxUnavailable. - Прогресс обновления:
kube_deployment_status_replicas_updatedрастёт до значенияkube_deployment_spec_replicas. - Перезапуски контейнеров:
rate(kube_pod_container_status_restarts_total{container="api-gateway"}[5m])- нулевое значение в норме.
Алерт на затянувшееся обновление:
kube_deployment_status_replicas_updated < kube_deployment_spec_replicas
and
(time() - kube_deployment_status_updated_time) > 600
Метрики для Canary-релизов
Сравнивайте версии по двум ключевым сигналам:
- Error rate:
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])с разбивкой по лейблуversion. - Latency p99:
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))по версиям.
Панель Grafana для Canary должна содержать два графика - error rate и latency - с наложенными линиями для v1 и v2. Если линия v2 стабильно выше v1 по ошибкам или задержкам, откатывайте канареечный релиз.
Для быстрого старта создайте дашборд с панелями: «Доступные реплики», «Прогресс обновления», «Error Rate по версиям», «Latency p99 по версиям». Экспортируйте JSON-модель и храните в Git рядом с манифестами - это часть Infrastructure as Code.
Откат обновлений: как быстро восстановить сервис
Процедура отката зависит от стратегии. Храните предыдущие манифесты в Git - это страховка на случай, когда kubectl rollout undo недостаточно.
Rolling Update:
kubectl rollout undo deployment/api-gateway
Откат запускает обратный Rolling Update: старые поды возвращаются постепенно. Время восстановления равно времени прямого обновления. Для ускорения настройте revisionHistoryLimit в Deployment - по умолчанию хранится 10 ревизий.
Blue-Green:
kubectl patch service api-service -p '{"spec":{"selector":{"app":"api","version":"blue"}}}'
Переключение происходит мгновенно - все новые соединения идут на Blue. Активные соединения с Green разрываются по таймауту, поэтому учитывайте этот фактор для long-lived соединений.
Canary:
kubectl delete ingress api-ingress-canary
Или измените вес до нуля. Трафик мгновенно возвращается к стабильной версии.
Рекомендация: тестируйте процедуру отката на staging-среде при каждом релизе. Инцидент на продакшене - не время для первой проверки. Реальные сценарии откатов и настройки мониторинга разобраны в статье про обновления и отказоустойчивость.
Заключение: выбор стратегии и дальнейшие шаги
Rolling Update покрывает 80% сценариев обновления stateless-приложений. Настройте maxSurge и maxUnavailable под доступные ресурсы кластера, добавьте readiness probes и мониторинг в Grafana - это база, с которой стоит начать.
Blue-Green применяйте для критичных систем, где даже минутная деградация неприемлема. Удвоенное потребление ресурсов окупается мгновенным откатом и возможностью полноценного тестирования Green-среды до переключения трафика.
Canary внедряйте, когда нужен постепенный контроль над распространением новой версии. Начните с аннотаций Nginx Ingress, а при росте сложности мигрируйте на Istio или Linkerd.
Следующий шаг - автоматизация обновлений через GitOps. Инструменты вроде ArgoCD и Flux интегрируются со всеми тремя стратегиями и позволяют запускать обновления по git push с автоматическим откатом при неудачных проверках.