K8s em Exemplos: Canary Deployments

Canary deployments liberam novas versões para um pequeno subconjunto de tráfego primeiro. Se o canary estiver saudável, aumente gradualmente o tráfego até o rollout completo. Se problemas ocorrerem, faça rollback com impacto mínimo. Use para: mitigação de risco, testes A/B, validação de features, requisitos de compliance.

canary-basic.yaml

Canary básico com dois Deployments compartilhando um Service. Ambos têm a mesma label app então o Service roteia para ambos. Ajuste contagem de réplicas para controlar divisão de tráfego (9 stable + 1 canary = 10% tráfego canary).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-stable
spec:
  replicas: 9
  selector:
    matchLabels:
      app: my-app
      version: stable
  template:
    metadata:
      labels:
        app: my-app
        version: stable
    spec:
      containers:
        - name: app
          image: my-app:v1.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
      version: canary
  template:
    metadata:
      labels:
        app: my-app
        version: canary
    spec:
      containers:
        - name: app
          image: my-app:v1.1.0
canary-service.yaml

O Service seleciona Pods apenas pela label app, roteando para ambas versões stable e canary. Distribuição de tráfego é proporcional à contagem de réplicas. Para controle preciso, use Ingress ou service mesh.

apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 8080
canary-ingress.yaml

Canary baseado em Ingress com annotations nginx-ingress. A annotation canary-weight envia uma porcentagem do tráfego para o backend canary. Mais preciso que divisão baseada em réplicas.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-stable
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-stable
                port:
                  number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-canary
                port:
                  number: 80
canary-header.yaml

Roteamento canary baseado em header. Apenas requisições com headers específicos vão para o canary. Útil para testes internos antes do rollout público. Combine com weight para rollout gradual.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-canary-header
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-canary
                port:
                  number: 80
terminal

Para canary automatizado com análise, instale Argo Rollouts. Ele fornece o CRD Rollout que substitui Deployment e adiciona estratégias canary/blue-green com promoção e rollback automáticos.

$ kubectl apply -n argo-rollouts --create-namespace -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
namespace/argo-rollouts created
customresourcedefinition.apiextensions.k8s.io/rollouts.argoproj.io created
serviceaccount/argo-rollouts created
clusterrole.rbac.authorization.k8s.io/argo-rollouts created
deployment.apps/argo-rollouts created
canary-analysis.yaml

Argo Rollouts fornece análise automática de canary. Defina métricas para verificar (taxa de erro, latência) e thresholds. O rollout automaticamente progride ou faz rollback baseado nos resultados da análise.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
spec:
  replicas: 10
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: my-app:v1.1.0
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: {duration: 5m}
        - setWeight: 30
        - pause: {duration: 5m}
        - setWeight: 50
        - pause: {duration: 5m}
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 1
analysis-template.yaml

AnalysisTemplate define como medir saúde do canary. Consulte Prometheus para taxas de erro, compare contra thresholds. Se a análise falhar, o rollout automaticamente aborta.

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result[0] >= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.monitoring.svc:9090
          query: |
            sum(rate(http_requests_total{
              app="my-app",
              status=~"2.."
            }[5m])) /
            sum(rate(http_requests_total{
              app="my-app"
            }[5m]))
terminal

Monitore progresso do canary com kubectl ou Argo Rollouts CLI. Acompanhe mudança de tráfego, resultados de análise e status do rollout. Promova ou aborte manualmente se necessário.

$ kubectl argo rollouts get rollout my-app -w
Name:            my-app
Status: Paused
Strategy:        Canary
  Step:          2/6
  SetWeight:     30
  ActualWeight:  30

$ kubectl argo rollouts promote my-app

$ kubectl argo rollouts abort my-app

$ kubectl get pods -l app=my-app --show-labels
NAME                        LABELS
my-app-stable-7d8f9-abc12   app=my-app,version=stable
my-app-canary-5f6g7-xyz34   app=my-app,version=canary

Índice | GitHub | Use as setas do teclado para navegar |