Learning Platform
Глоссарий Troubleshooting
Урок 17.04 · 25 мин
Продвинутый
Blue-greenCanaryService selectorArgo RolloutsIstioProgressive delivery

Blue-green и canary через Services и labels

K8s native API не имеет “blue-green deploy” или “canary release” как первоклассные ресурсы. Нет kind: BlueGreenDeployment, нет kind: CanaryRelease. Эти стратегии реализуются вручную через комбинацию двух фундаментальных примитивов: двух Deployments с разными labels и одного Service с selector, который выбирает, какой Deployment получает трафик.

Понять это — значит понять, как K8s sticks to minimal API surface и оставляет complex deployment policies для дополнительных слоёв (Argo Rollouts, Flagger, Istio).


Протоколы ребалансировки Kafka: Eager vs Cooperative

Blue-green deployment

Идея: запустить параллельно две копии — blue (v1, production) и green (v2, new release). Тестировать green изолированно через temp Service. Когда уверен — переключить main Service selector с blue на green одной командой. Rollback — точно так же, в обратную сторону.

Шаг 1. Два Deployments с разными labels

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      version: blue
  template:
    metadata:
      labels:
        app: web
        version: blue
    spec:
      containers:
        - name: app
          image: my-app:v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      version: green
  template:
    metadata:
      labels:
        app: web
        version: green
    spec:
      containers:
        - name: app
          image: my-app:v2

Оба Deployments имеют label app: web, но отличаются по version. Это отдельные RS и Pod-ы.

Шаг 2. Main Service пока на blue

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
    version: blue   # ← главное: selector matches только blue Pods
  ports:
    - port: 80
      targetPort: 8080

Production-трафик идёт только на blue. Green Pods существуют, но Service их не “видит” — они не в endpoints.

Шаг 3. Тест green через temp Service

apiVersion: v1
kind: Service
metadata:
  name: web-canary-test   # отдельный временный Service
spec:
  selector:
    app: web
    version: green
  ports:
    - port: 80
      targetPort: 8080

Через этот Service можно тестировать green изолированно — например, прогнать smoke-tests, проверить метрики, выполнить нагрузочное тестирование.

Шаг 4. Switch

kubectl patch svc web -p '{"spec":{"selector":{"app":"web","version":"green"}}}'

Один patch — Service selector изменился. EndpointSlice контроллер пересчитывает endpoints — теперь там только green Pods. Трафик мгновенно переключается на green. Blue Pods остаются работающими, но без трафика.

Blue-green switch
before switchService web selector: app=web, version=blue. EndpointSlice содержит IPs только blue Pod-ов. kube-proxy / EndpointSlice controller балансирует трафик на blue. Green Pods работают, но изолированы — нет endpoints.
blue Pods3 Pod-а с label version=blue. Image my-app:v1. В endpoints Service web. Получают весь трафик.
green Pods3 Pod-а с label version=green. Image my-app:v2. НЕ в endpoints main Service web. Тестируются через temp Service web-canary-test или port-forward.
kubectl patch svc web (selector → green)
after switchEndpointSlice controller замечает изменение selector → пересчитывает endpoints. Теперь там IP только green Pod-ов. kube-proxy получает endpoint update через watch → обновляет iptables/IPVS rules → трафик уходит на green.
blue PodsPod-ы остаются работающими (replicas=3). Но эндпоинтов нет — трафик не идёт. Можно держать для quick rollback или удалить Deployment-blue.
green PodsПолучают весь production-трафик. Если что-то идёт не так — patch обратно на selector blue, мгновенный rollback.

Rollback и cleanup

# Если что-то пошло не так — обратный patch
kubectl patch svc web -p '{"spec":{"selector":{"app":"web","version":"blue"}}}'
# Трафик мгновенно вернулся на blue

# Если green ok — eventually удалить blue Deployment
kubectl delete deploy web-blue
TIP

Blue-green даёт instant rollback: один patch — и трафик вернулся. Это самое большое преимущество над RollingUpdate (где rollback — это новый rolling update). Цена: 2× ресурсов на время сосуществования blue и green.


Canary deployment

Идея: вместо полного switch, отдать новой версии малую часть трафика (10%, 25%). Мониторить метрики canary. Если ok — постепенно увеличивать canary replicas + уменьшать production. Если плохо — scale canary в 0 и rollback мгновенный.

Шаг 1. Production + canary Deployments

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-production
spec:
  replicas: 9
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        version: stable
    spec:
      containers:
        - name: app
          image: my-app:v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        version: canary
    spec:
      containers:
        - name: app
          image: my-app:v2

Ключевое отличие от blue-green: оба Deployments имеют label app: web, который соответствует Service selector. Pod template labels включают version=stable или version=canary для observability, но это не часть Service selector.

Шаг 2. Один Service на оба

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web   # ← matches и production, и canary
  ports:
    - port: 80
      targetPort: 8080

Service видит endpoints из ВСЕХ Pod-ов обоих Deployments — 9 production + 1 canary = 10 endpoints. kube-proxy балансирует через random/round-robin. Примерно 10% запросов идут на canary.

Canary через ratio of Pod replicas
Service webОдин Service с selector app=web. Видит endpoints обоих Deployments. EndpointSlice содержит 10 IP: 9 stable + 1 canary. kube-proxy не знает про version label — она для observability.
kube-proxy балансирует ~равномерно
9 stable Podsversion=stable, image v1. 9 endpoints из 10. Получают ~90% трафика. kube-proxy iptables/IPVS делает random selection из endpoints — статистически каждый Pod получает 10% от общего трафика.
1 canary Podversion=canary, image v2. 1 endpoint из 10. Получает ~10% трафика. Мониторим метрики этого Pod-а (latency, error rate, custom business metrics).
постоянная проверка: если canary metrics ok
scale up canarykubectl scale deploy web-canary --replicas=3. Теперь canary=3, stable=9, всего 12 endpoints, canary получает 25% трафика. Постепенно: 25% → 50% → 100%, параллельно scale down stable.

Шаг 3. Progressive shift

# 10% canary
kubectl scale deploy web-canary --replicas=1
kubectl scale deploy web-production --replicas=9

# 25% canary
kubectl scale deploy web-canary --replicas=3
kubectl scale deploy web-production --replicas=9

# 50% canary
kubectl scale deploy web-canary --replicas=5
kubectl scale deploy web-production --replicas=5

# 100% canary
kubectl scale deploy web-canary --replicas=10
kubectl scale deploy web-production --replicas=0

# Cleanup
kubectl delete deploy web-production
kubectl edit deploy web-canary   # rename to web-production for next round

Rollback

kubectl scale deploy web-canary --replicas=0
# Canary endpoints исчезают из Service. 100% трафика на stable. Rollback мгновенный.

Killer момент: ratio precision

kube-proxy не делает precise traffic splitting. Если endpoints = 9 stable + 1 canary:

  • iptables mode: random selection через -m statistic --mode random --probability. Каждый Pod статистически получает ~10% от общего трафика, но любой конкретный запрос — это бросок монетки. На малых RPS отклонение может быть 5-15%.
  • IPVS mode: round-robin (по умолчанию). Более равномерное распределение, но всё ещё на уровне Pod-ов, не запросов.

Это значит:

  • Нельзя сказать “9% canary, ни больше ни меньше”
  • Нельзя по-разному маршрутить запросы (например, header-based: x-user-id mod 10)
  • Нельзя плавно увеличить с 10% до 11% — нужно менять replicas (целые числа)
WARNING

Для точного traffic splitting нужен Service Mesh (Istio VirtualService с weight), или Ingress controller с traffic-splitting annotations (NGINX canary-weight), или Argo Rollouts с интеграцией одного из них. Native K8s — это только ratio через replicas.

Service Mesh: precise traffic split

# Istio VirtualService — splits traffic 90/10 точно
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: web
spec:
  hosts:
    - web
  http:
    - route:
        - destination:
            host: web
            subset: stable
          weight: 90
        - destination:
            host: web
            subset: canary
          weight: 10

Istio Envoy sidecar реализует precise weighted routing — 90 из 100 запросов идут на stable, 10 на canary, независимо от количества Pods. Это даёт настоящее canary с любыми percentages.


Argo Rollouts / Flagger: progressive delivery as CRD

Native K8s + service mesh — это всё ещё manual. Чтобы автоматизировать, существуют CRD-based progressive delivery controllers:

  • Argo Rollouts — заменяет kind: Deployment на kind: Rollout с canary/blue-green strategies в spec. Автоматическое progressive shift с pause-ами между шагами, integration с Prometheus для analysis, automated rollback при failed metrics.
  • Flagger — sidecar контроллер, который работает с обычным Deployment + Istio/Linkerd/AppMesh. Аналогичные возможности.
# Argo Rollouts: declarative canary
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: web
spec:
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: { duration: 5m }
        - setWeight: 25
        - pause: { duration: 5m }
        - setWeight: 50
        - analysis:
            templates:
              - templateName: success-rate
        - setWeight: 100

Controller автоматически проходит шаги: setWeight=10 → ждёт 5m → setWeight=25 → … → run analysis (например, проверить error rate в Prometheus) → если ok, setWeight=100. Если analysis fail — automatic rollback.

NOTE

CKAD scope — знать концепции blue-green и canary, реализовать через Deployments + labels + Services. Argo Rollouts — это уже CKA/SRE territory, но обязательно знать про существование (вопросы в multiple-choice часто).


Killer-моменты

  • K8s native API НЕ имеет blue-green/canary — это паттерны на основе двух Deployments и Service selector.
  • Blue-green: 2 Deployments с разными labels, switch через kubectl patch svc. Instant rollback, 2× ресурсов.
  • Canary: 2 Deployments с одинаковой label, один Service видит оба. Traffic ratio = replicas ratio.
  • Ratio precision — kube-proxy не точный, статистически близко к ratio replicas, но не exact. Для exact — Service Mesh.
  • Service Mesh (Istio) — weight в VirtualService, Envoy sidecar реализует precise split.
  • Argo Rollouts / Flagger — CRD-based progressive delivery с automatic analysis и rollback.

Проверка знанийKnowledge check
Blue-green: главный Service web имеет selector app=web и version=blue. Существуют Deployments web-blue (3 Pods, version=blue) и web-green (3 Pods, version=green). Что произойдёт после kubectl patch svc web с указанием в спецификации selector только version=green без указания app=web?
ОтветAnswer
Selector переписывается полностью на version=green — старая часть app=web уходит. EndpointSlice controller выбирает все Pods с label version=green в текущем namespace из всех Deployments. Если другой Deployment в этом namespace имеет label version=green (даже с app=other), эти Pods тоже попадут в endpoints. Service может начать балансировать на неправильные Pods. Правильный patch указывает оба label — и app=web, и version=green. На CKAD: внимательно с strategic merge — selector это map, и patch его перезаписывает целиком, не merge.
Проверка знанийKnowledge check
Canary через 9 stable Pods + 1 canary Pod за одним Service. Производственный трафик 1000 req/s. Сколько примерно req/s получает canary и почему НЕ точно 100?
ОтветAnswer
Примерно 100 req/s (10%), но фактически может быть 80-120 req/s в любую секунду. Причина: kube-proxy в iptables mode выбирает endpoint случайно для каждого запроса через `-m statistic --mode random --probability 0.1`. Это статистическое распределение — на 1000 запросов в среднем 100 попадают на canary, но это random walk с дисперсией ~10 req/s. В IPVS mode round-robin даст более равномерное распределение, но всё ещё на уровне Pod-ов, не запросов. Кроме того, sticky sessions (через sessionAffinity=ClientIP) могут сделать распределение очень неравномерным — если 10 клиентов делают 100 req/s каждый и один из них stuck на canary, canary получает 100 req/s от одного клиента. Для precise splits — Istio VirtualService weights через Envoy.
Проверка знанийKnowledge check
Почему canary через Deployment replicas ratio нельзя плавно изменить с 10% на 11% — а через Istio VirtualService weight можно?
ОтветAnswer
Replicas — целое число. Чтобы canary получал 11% трафика через replicas: nstable + ncanary такой что ncanary/(ncanary+nstable) ≈ 0.11. Минимум 9 canary + 73 stable = 11.0%. Это огромный footprint в Pod-ах. На малых replicas (1+9=10) шаги дискретные: 10%, 20%, 25%, 33%. Через Istio: VirtualService.http.route с weights — например weight: 89 для stable и weight: 11 для canary. Envoy sidecar реализует weighted load balancing на уровне запроса. Можно постепенно менять с 10→11→12% без изменения количества Pods. Это разные слои: native K8s балансирует на Pod-уровне, Service Mesh — на request-level с фракционными weights.
Проверка знанийKnowledge check
Blue-green через два Deployments — есть момент проблем со stateful: shared database. Что произойдёт во время switch если schema несовместима между v1 (blue) и v2 (green)?
ОтветAnswer
Если schema несовместима — обе версии работают одновременно во время switch, и обе ломаются. Сценарий: blue в production, green подняли с новой версией, которая требует новый column. В этот момент: blue читает старый schema => ok, green читает новый column (которого нет) => 500. Тестировать green изолированно (через temp Service) тоже ломается. Решение: schema migrations должны быть backward-compatible — добавлять column как nullable, не удалять старые столбцы сразу. Двухфазный deploy: (1) Add column => deploy v1.5 которая пишет в обе schema => migrate data => (2) Deploy v2 которая использует только новый column => удалить старый. Альтернатива — Recreate strategy (без двух версий одновременно) и pre-upgrade migration job.

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

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Blue-green: главный Service web имеет selector {app: web, version: blue}. Deployments web-blue (version: blue) и web-green (version: green) запущены. Что произойдёт после kubectl patch svc web -p '{"spec":{"selector":{"version":"green"}}}' БЕЗ указания app=web?

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

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

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

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