Blue-Green деплой
Два контура и один Service-переключатель: как получить мгновенный откат и чем за это платят.
Что такое Blue-Green
Blue-Green - стратегия деплоя без простоя с мгновенным откатом. В проде держат два независимых контура. Один контур называют blue, он принимает весь трафик. Второй называют green, он развёрнут и готов, но трафика не получает.
Когда green готов, трафик переключают на него. Если что-то сломалось, трафик переключают обратно на blue. Blue всё это время жив, поэтому откат происходит мгновенно.
В Kubernetes роль переключателя играет Service. Service - объект, который раздаёт трафик на набор Pod, отобранных по меткам. Метка (label) - пара ключ-значение на объекте. selector - набор меток, по которым Service выбирает Pod.
Меняешь selector с color=blue на color=green, и endpoints
перестраиваются. endpoints - список IP-адресов Pod, на которые
Service шлёт трафик. kube-proxy (компонент на каждой ноде, который
держит правила сети для Service) обновляет правила, и трафик
переезжает за секунду.
Главный плюс - откат идёт той же скоростью, что и выкатка. Один patch возвращает selector обратно. За это платишь ресурсами: в окне переключения в кластере живут обе версии сразу. Pod на 500 МБ RAM в 5 репликах держит лишние 5 ГБ. Для критичных сервисов страховка оправдана. Небольшим микросервисам с частой выкаткой такой расход ресурсов обходится дороже, чем стоит.
Минимальная конструкция
Нужны два Deployment с разными значениями метки color. Deployment -
объект, который держит нужное число одинаковых Pod.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-blue
spec:
selector:
matchLabels: {app: app, color: blue}
template:
metadata:
labels: {app: app, color: blue}
spec:
containers:
- name: app
image: nginxinc/nginx-unprivileged:1.21
Второй Deployment такой же, но с color: green и образом
nginxinc/nginx-unprivileged:1.25.
Один Service с явным color в selector:
apiVersion: v1
kind: Service
metadata:
name: app
spec:
selector:
app: app
color: blue # переключаем blue/green здесь
ports:
- port: 80
targetPort: 8080
Как переключают трафик
kubectl patch svc app \
-p '{"spec":{"selector":{"app":"app","color":"green"}}}'
kubectl patch записывает в spec.selector новый цвет. Контроллер
endpoints замечает изменение, перебирает Pod в namespace и
складывает в endpoints те, что подходят под новый selector.
kube-proxy на каждой ноде следит за изменением endpoints и обновляет
правила сети.
Если в selector Service нет ключа color, он поймает и blue, и green
сразу. Трафик размажется по обеим версиям, а переключать будет нечего.
Соединения, открытые до переключения, доживают на blue. Новые соединения идут на green.
Откат
kubectl patch svc app \
-p '{"spec":{"selector":{"app":"app","color":"blue"}}}'
Blue Deployment всё это время жив, его Pod готовы. Откат проходит за секунду.
Связанные команды
kubectl get deploy
kubectl get svc app -o jsonpath='{.spec.selector}'
kubectl get endpoints app
kubectl get pods -l color=green -o wide
kubectl rollout status deploy/app-green
Объект v1 Endpoints deprecated с 1.33, и kubectl get endpoints
печатает про это предупреждение. Тот же список адресов через актуальный
объект:
kubectl get endpointslice -l kubernetes.io/service-name=app
Что часто ломается
- Green ещё не Ready, а Service уже переключён. Пользователи ловят
502. Сначала
kubectl rollout statusдо конца, потом patch. - В
spec.selector.matchLabelsу Deployment забыли уникальныйcolor. Blue и green считают себя одним набором, Pod начинают переезжать между Deployment. - Blue удалили после переключения. Откат больше не мгновенный, придётся ждать раскатки blue заново. Старый цвет держат хотя бы до следующей выкатки.
Когда не подходит Blue-Green
- Stateful-нагрузка с одним томом в режиме RWO (ReadWriteOnce - том монтируется на запись только к одной ноде). Два цвета не держат такой том одновременно. Нужен RWX (ReadWriteMany - запись с нескольких нод) или другой подход.
- Очень дорогие Pod, где двойной расход не окупается. Тут берут rolling update.
- Нужна доля трафика на новую версию, например 10%. Это canary, а не Blue-Green.
Домашка
Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-blue-green # развернуть стартовое состояние
./run.sh verify k8s-blue-green # проверить текущий шаг
Коротко
- Два Deployment с меткой
color, один Service решает, кто получает трафик. - Переключение и откат - это один
kubectl patchпоspec.selector. - Blue нельзя удалять сразу: он и есть страховка для мгновенного отката.
- Selector Service обязан содержать
color, иначе трафик уходит на обе версии. - Цена подхода - двойной расход ресурсов в окне переключения.
- Долю трафика по процентам Blue-Green не даёт, для этого нужен canary.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс