Стратегии деплоя в Kubernetes: Часть 1
Kubernetes — это уже новая реальность…! Он стал стандартом де-факто для оркестрации контейнеров. Сегодня разберём, какие механизмы предоставляет сам Kubernetes для разных стратегий деплоя. Всегда полезно понимать доступные варианты и как можно безболезненно выкатывать новые версии приложений. Правда, в реальном продакшене мы редко ограничиваемся только Kubernetes — обычно подключаем дополнительные инструменты из экосистемы.
Например, вы можете использовать Helm Charts для упаковки приложений или работать с OpenShift / Rancher, которые расширяют возможности «голого» Kubernetes. Но сегодня давайте без лишних усложнений — посмотрим, какие есть стратегии деплоя средствами самого Kubernetes.
Recreate
При стратегии Recreate старые pod’ы сначала останавливаются, а потом Kubernetes разворачивает новые экземпляры.
Например, если вы активно разрабатываете приложение и нужно быстро протестировать свежую версию, Recreate — самый простой способ быстро выкатить новый образ.
Плюсы:
- Просто. Завершаем старые инстансы и «пересоздаём» новые.
Минусы:
- Есть простой. Все pod’ы останавливаются, и приложение на время недоступно.
Rolling Updates
Rolling updates обновляют pod’ы постепенно, без простоя. Эта стратегия позволяет параллельно гасить старую версию и запускать новую.
Blue/Green Deployment
При Blue/Green деплое новая версия приложения (синяя — Blue) запускается параллельно с текущей стабильной (зелёной — Green).
Пользователи продолжают работать со стабильной версией, а новая используется для тестов и проверки.
Когда тестирование проходит успешно и все проверки здоровья пройдены, трафик перенаправляется на новую версию, и она становится «зелёной» — стабильной.
Плюсы:
- Быстрый откат.
- Нет простоя.
- Можно тестировать прямо в продакшене.
Минусы:
- Дополнительные ресурсы — приходится держать две версии одновременно.
- Kubernetes не ведёт версионность такого деплоя, так как новая версия — это полностью отдельный deployment.
Canary Deployment
Стратегия Canary позволяет «прокатить» новую версию приложения прямо в продакшене на ограниченном трафике.
Сначала поднимается небольшой набор pod’ов новой версии, и к ним направляется часть реального трафика для тестирования и мониторинга.
Когда проверка проходит успешно, количество реплик новой версии постепенно увеличивается, пока весь трафик не перейдёт на неё.
В «нативном» Kubernetes Canary-деплой реализуется с помощью Services.
Мы создаём новый deployment с теми же label’ами, что и у стабильной версии. Service будет распределять трафик между старыми и новыми pod’ами в зависимости от их количества.
Плюсы:
- Больше контроля над процессом выката.
- Можно использовать реальный трафик для проверки новых фич.
Минусы:
- Дополнительные ресурсы на параллельный запуск двух версий.
- Управлять трафиком сложно. В Kubernetes Service распределяет его просто по количеству pod’ов.
- Например, если у вас 5 pod’ов стабильной версии и вы хотите отправить 20% трафика на новую, придётся поднять 1 pod — но он получит 17% (1 из 6).
- Для более точного контроля придётся использовать service mesh, например Istio.
Практический пример
Настройка текущего окружения
Для простоты давайте считать, что наше продакшн-приложение — это веб-сервер Nginx, который раздаёт критически важный файл index.html.
1. Деплой webapp v1 через манифест my-webapp.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
spec:
selector:
matchLabels:
app: webapp
replicas: 2
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: yaiiteng/my-nginx:v1
ports:
- containerPort: 80
2. Создание сервиса для доступа к приложению извне
Чтобы упростить пример, используем NodePort-сервис.
В реальном продакшене, скорее всего, вы бы применили Ingress или LoadBalancer.
Создадим манифест my-webapp-services.yml:
apiVersion: v1
kind: Service
metadata:
name: webapp-service
labels:
app: webapp
spec:
selector:
app: webapp
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 32001
3. Применяем ресурсы через kubectl
kubectl apply -f my-webapp.yml kubectl apply -f my-webapp-services.yml
В реальных проектах обычно используют Helm Charts, чтобы упаковать и версионировать все манифесты.
На этом этапе у вас будут развернуты нужные ресурсы в кластере.
Доступ к Nginx можно получить по адресу:
http://<kubernetes-node>:32001

Отлично, теперь попробуем задеплоить версию v2.
Представим, что в ней произошли серьёзные изменения, и ваш CI-пайплайн уже собрал Docker-образ my-nginx:v2.
Дальше мы протестируем разные стратегии деплоя, чтобы обновить приложение с v1 до v2.
Rolling Update
Стратегия RollingUpdate — это стратегия деплоя по умолчанию в Kubernetes.
Мы не задавали никакой стратегии в нашем my-webapp.yml при создании, но Kubernetes автоматически добавил в раздел spec такие параметры:

spec.strategy.type: RollingUpdate— указывает, что деплой будет выполняться по стратегии rolling update.spec.strategy.rollingUpdate.maxSurge: 25%— максимум на 25% можно создавать pod’ов сверх нужного количества реплик во время обновления.spec.strategy.rollingUpdate.maxUnavailable: 25%— допускается, что до 25% pod’ов могут быть недоступны в процессе деплоя.
Чтобы задеплоить новую версию, всё, что нужно сделать — поменять тег образа в my-webapp.yml:
containers: - name: webapp image: yaiiteng/my-nginx:v2
и затем выполнить:
kubectl apply -f my-webapp.yml

После применения манифеста Kubernetes начнёт обновление:
старые pod’ы будут удаляться по одному, а на их место постепенно поднимутся новые с версией v2.
Так как у нас всего 2 реплики, процесс будет выглядеть примерно так:

Да, приложение обновлено до v2

Что происходит «под капотом»
Kubernetes уменьшает количество pod’ов в текущем ReplicaSet, создаёт новый ReplicaSet для версии v2 и постепенно увеличивает количество его реплик, пока не достигнет нужного числа.

Recreate
Чтобы использовать стратегию Recreate, достаточно в манифесте указать:
spec:
strategy:
type: Recreate
В этом случае Kubernetes одновременно завершит все существующие pod’ы и только после этого создаст новые.
Полный пример манифеста:
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
spec:
selector:
matchLabels:
app: webapp
replicas: 2
strategy:
type: Recreate
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: yaiiteng/my-nginx:v2
ports:
- containerPort: 80
После того как обновите YAML и выполните команду:
kubectl apply -f my-webapp.yml
Kubernetes сначала убьёт все старые pod’ы, а затем пересоздаст новые — в том же количестве реплик.

Минус очевиден: пока старые pod’ы удаляются и новые ещё не запустились, приложение полностью недоступно.
Но если вы работаете в тестовом окружении или нужно быстро накатить изменения без сложных сценариев, Recreate — простой и прямолинейный вариант.
Дополнительные советы
1.Обновлять образ в деплойменте можно и через команду set image. Она подтянет новый образ и обновит запущенный деплоймент, но манифест при этом не изменится. Если вам нужно зафиксировать изменения в коде инфраструктуры, правильнее обновить манифест и применить его через kubectl apply -f.
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
2.Посмотреть историю выката версий можно через kubectl rollout history:
kubernetes/deployment $ kubectl rollout history deploy webapp deployment.apps/webapp REVISION CHANGE-CAUSE 1 <none> 2 <none> kubernetes/deployment $
3.Откат делается опцией undo у команды rollout:
kubernetes/deployment $ kubectl rollout undo deploy/webapp deployment.apps/webapp rolled back kubernetes/deployment $
В следующей части посмотрим, как делать Canary Deployment и Blue/Green деплой.