переключать продакшен-трафик атомарно с быстрым откатом
Blue-green развёртывание в Kubernetes: выкатка без простоя и лишней сложности
12 минут
При поэтапном rolling update старая и новая версии одновременно принимают трафик. Blue-green держит два полных стека, проверяет неактивный цвет через preview Service и переключает продакшен одним изменением селектора — откат тем же патчем назад.
Почему rolling update отдаёт пользователям новую версию раньше, чем вы успеваете среагировать
По умолчанию Kubernetes выкатывает релиз поэтапно — это удобно, но под старой и новой ревизией одновременно идёт боевой трафик. Сломанный API или утечка памяти уже бьют по клиентам, пока вы решаете прервать выкатку. Откат медленный: дождаться drain подов, подтянуть образы, дождаться readiness — на высокой нагрузке даже полминуты превращаются в потерянные платежи и обращения в поддержку. Миграции схемы усугубляют риск: откатить приложение нельзя вместе с уже применённой миграцией БД. Blue-green держит два полных стека — blue на текущем продакшене, green на кандидате — и ведёт пользователей через один Service. Green проверяют изолированно, затем переключают селектор. Если проверки провалились, продакшен остаётся на blue. Откат — один patch селектора назад, а не гонка с повторным деплоем.
Blue-green на чистом Kubernetes: два Deployment, preview Service и один боевой Service
Отдельного CRD blue-green в Kubernetes нет, но Deployment, Service и метки достаточны — service mesh не обязателен. Запустите app-blue и app-green с меткой version и одинаковым числом реплик в продакшене. myapp-service указывает на активный цвет. Добавьте myapp-green-preview и myapp-blue-preview — они всегда смотрят на свой цвет, чтобы пробные запросы шли в неактивный стек, не трогая продакшен. При промоушене обновляйте в селекторе и app, и version — если оставить только version, трафик может уйти в никуда. После переключения держите предыдущий цвет включённым заданное время для отката, затем масштабируйте вниз. Ingress подхватывает Endpoints за секунды; всё равно проверьте публичный health после switch. Стратегию blueGreen в Argo Rollouts можно использовать вместо скриптов, если нужен контроллер.
Выкатить green, проверить через preview, переключить атомарно
Примените или обновите green Deployment с неизменяемым тегом образа. Дождитесь rollout status, затем выполните curl к preview Service из пода в кластере — не обращайтесь к DNS, для которого нет Service. Patch боевого Service с обоими ключами селектора. Проверьте публичный health endpoint и оставьте blue работать два часа или пока не утихнут алерты. Скрипт промоушена чередует цвета, поэтому имена Deployment остаются постоянными от релиза к релизу.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-blue
labels:
app: myapp
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
template:
metadata:
labels:
app: myapp
version: blue
spec:
containers:
- name: app
image: myregistry/myapp:v1.4.2
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
version: blue
ports:
- port: 80
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: myapp-green-preview
spec:
selector:
app: myapp
version: green
ports:
- port: 8080
targetPort: 8080apiVersion: apps/v1
kind: Deployment
metadata:
name: app-green
labels:
app: myapp
version: green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
template:
metadata:
labels:
app: myapp
version: green
spec:
containers:
- name: app
image: myregistry/myapp:v1.5.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080kubectl apply -f app-green.yaml
kubectl rollout status deployment/app-green --timeout=120s
kubectl run smoke-green --rm -i --restart=Never --image=curlimages/curl:8.5.0 -- \
curl -sf http://myapp-green-preview.production.svc.cluster.local:8080/healthz
kubectl patch svc myapp-service --type=merge -p \
'{"spec":{"selector":{"app":"myapp","version":"green"}}}'
curl -sf https://myapp.example.com/healthz#!/usr/bin/env bash
set -euo pipefail
NAMESPACE=production
NEW_VERSION=${1:?usage: promote.sh <image-tag>}
CURRENT=$(kubectl get svc myapp-service -n "$NAMESPACE" -o jsonpath='{.spec.selector.version}')
if [[ "$CURRENT" == "blue" ]]; then NEW_COLOR=green; else NEW_COLOR=blue; fi
kubectl set image deployment/app-"$NEW_COLOR" app=myregistry/myapp:"$NEW_VERSION" -n "$NAMESPACE"
kubectl rollout status deployment/app-"$NEW_COLOR" -n "$NAMESPACE" --timeout=180s
kubectl run smoke-"$NEW_COLOR" --rm -i --restart=Never -n "$NAMESPACE" \
--image=curlimages/curl:8.5.0 -- \
curl -sf "http://myapp-${NEW_COLOR}-preview.${NAMESPACE}.svc.cluster.local:8080/healthz"
kubectl patch svc myapp-service -n "$NAMESPACE" --type=merge -p \
"{\"spec\":{\"selector\":{\"app\":\"myapp\",\"version\":\"$NEW_COLOR\"}}}"
echo "Active color: $NEW_COLOR. Previous color $CURRENT kept for rollback."Практика: ёмкость, проверки здоровья, данные и гибрид с canary
На время промоушена держите оба цвета на полном числе реплик — простаивающий под дешевле сорванного переключения и холодного старта. Фиксируйте digest или версионный тег образа; mutable latest на обоих стеках убивает детерминизм. Расширьте /healthz: не только «процесс жив», но и ping БД, прогрев кэша, доступность критичных зависимостей. Для компонентов с состоянием применяйте expand-and-contract миграции отдельным шагом «только вперёд» и держите код совместимым с обеими версиями схемы в окне перекрытия. Дашборды и алерты привязывайте к метке version, чтобы green был виден до приёма продакшен-трафика. На рискованных релизах совместите blue-green с короткой canary-фазой — пять процентов через вес Ingress или Argo Rollouts, проверка ошибок и задержки, затем полный switch селектора. Blue-green не универсален, но два Deployment, preview Service и одно атомарное переключение дают большинству команд выкатку без простоя и откат за секунды без mesh.
Если нужен постепенный перевод трафика и метрические гейты вместо мгновенного переключения, см. progressive delivery с canary и feature flags в Kubernetes.
Когда смена схемы БД должна быть совместима с обеими версиями, согласуйте порядок выкатки с миграциями схемы базы данных в CI/CD.
