DevOps & CI/CD

Como Usar Estratégias de Deploy em Kubernetes: Rolling, Blue-Green e Canary em Produção

16 min de leitura

Como Usar Estratégias de Deploy em Kubernetes: Rolling, Blue-Green e Canary em Produção

Introdução: Por que Estratégias de Deploy Importam em Kubernetes Quando você trabalha com Kubernetes em produção, simplesmente fazer e rezar para que nada quebre não é uma opção viável. O desafio real está em atualizar suas aplicações sem interrupção de serviço, minimizando riscos e permitindo rollback rápido caso algo dê errado. É exatamente aí que estratégias de deploy bem definidas entram em cena. As três estratégias que vamos explorar neste artigo—Rolling, Blue-Green e Canary—representam diferentes abordagens para resolver este problema, cada uma com seus trade-offs de complexidade, tempo de deploy e segurança. Não existe uma estratégia universalmente superior; a escolha depende do seu contexto, tolerância a risco e infraestrutura disponível. Rolling Deployment: O Clássico Gradual O Conceito Fundamental Rolling Deployment é a estratégia padrão do Kubernetes. Ela funciona substituindo gradualmente as instâncias antigas por novas, mantendo sempre um número mínimo de replicas em execução. Enquanto você termina de escalar as novas versões, as antigas vão sendo drenadas e removidas. Imagina

<h2>Introdução: Por que Estratégias de Deploy Importam em Kubernetes</h2>

<p>Quando você trabalha com Kubernetes em produção, simplesmente fazer <code>kubectl apply</code> e rezar para que nada quebre não é uma opção viável. O desafio real está em <strong>atualizar suas aplicações sem interrupção de serviço, minimizando riscos e permitindo rollback rápido caso algo dê errado</strong>. É exatamente aí que estratégias de deploy bem definidas entram em cena.</p>

<p>As três estratégias que vamos explorar neste artigo—Rolling, Blue-Green e Canary—representam diferentes abordagens para resolver este problema, cada uma com seus trade-offs de complexidade, tempo de deploy e segurança. Não existe uma estratégia universalmente superior; a escolha depende do seu contexto, tolerância a risco e infraestrutura disponível.</p>

<h2>Rolling Deployment: O Clássico Gradual</h2>

<h3>O Conceito Fundamental</h3>

<p>Rolling Deployment é a estratégia padrão do Kubernetes. Ela funciona <strong>substituindo gradualmente as instâncias antigas por novas</strong>, mantendo sempre um número mínimo de replicas em execução. Enquanto você termina de escalar as novas versões, as antigas vão sendo drenadas e removidas.</p>

<p>Imagina que você tem 5 replicas em produção. O Kubernetes pode iniciar 1 nova replica com a versão nova, remover 1 antiga, depois repetir até que todas as 5 sejam da nova versão. Durante todo esse processo, o serviço continua respondendo requisições—nenhum downtime.</p>

<h3>Implementação Prática</h3>

<p>A maneira mais simples de fazer Rolling Deployment em Kubernetes é através da estratégia padrão de atualização de Deployment. Vamos criar um exemplo completo:</p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: app-web

namespace: producao

spec:

replicas: 5

strategy:

type: RollingUpdate

rollingUpdate:

maxSurge: 1

maxUnavailable: 1

selector:

matchLabels:

app: web

template:

metadata:

labels:

app: web

spec:

containers:

  • name: app

image: meu-registro.azurecr.io/app-web:v1.0.0

ports:

  • containerPort: 8080

livenessProbe:

httpGet:

path: /health

port: 8080

initialDelaySeconds: 10

periodSeconds: 5

readinessProbe:

httpGet:

path: /ready

port: 8080

initialDelaySeconds: 5

periodSeconds: 3

terminationGracePeriodSeconds: 30</code></pre>

<p>Os parâmetros <code>maxSurge</code> e <code>maxUnavailable</code> são críticos aqui. <code>maxSurge: 1</code> significa que o Kubernetes pode criar 1 pod a mais do que o especificado (6 pods total temporariamente). <code>maxUnavailable: 1</code> permite que no máximo 1 pod esteja indisponível durante o processo. Esses valores controlam a velocidade e o risco do deploy.</p>

<p>Para atualizar a imagem e disparar um novo Rolling Deployment:</p>

<pre><code class="language-bash">kubectl set image deployment/app-web app=meu-registro.azurecr.io/app-web:v1.1.0 \

--namespace=producao \

--record</code></pre>

<p>Você pode monitorar o progresso em tempo real:</p>

<pre><code class="language-bash">kubectl rollout status deployment/app-web -n producao

kubectl rollout history deployment/app-web -n producao</code></pre>

<p>Se algo der errado durante o processo, faça rollback instantâneo:</p>

<pre><code class="language-bash">kubectl rollout undo deployment/app-web -n producao</code></pre>

<h3>Vantagens e Desvantagens</h3>

<p><strong>Vantagens:</strong> Simplicidade, suporte nativo do Kubernetes, não requer infraestrutura adicional, rollback automático se health checks falharem. <strong>Desvantagens:</strong> Tempo de deploy pode ser longo para muitas replicas, período de &quot;versão mista&quot; onde v1 e v2 rodam simultaneamente (pode quebrar se as APIs são incompatíveis), dificuldade em controlar qual percentual de tráfego vai para nova versão.</p>

<h2>Blue-Green Deployment: Dois Mundos Paralelos</h2>

<h3>O Conceito Fundamental</h3>

<p>Blue-Green é uma abordagem onde você mantém <strong>duas versões completas e idênticas de sua aplicação rodando em paralelo</strong>: o ambiente &quot;Blue&quot; (atual) e o &quot;Green&quot; (novo). Todo o tráfego vai para o Blue. Quando você quer fazer deploy, sobe o Green com a nova versão, testa completamente, e então <strong>muda o roteador para direcionar todo o tráfego do Blue para o Green em uma operação atômica</strong>.</p>

<p>O grande benefício? Rollback é trivial: basta voltar o roteador para apontar para o Blue. Se algo der errado, você já tem a versão anterior funcionando perfeitamente. Não há versão mista, não há downtime durante a transição.</p>

<h3>Implementação Prática</h3>

<p>Vou mostrar uma implementação real usando dois Deployments e um Service:</p>

<pre><code class="language-yaml">---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app-blue

spec:

replicas: 3

selector:

matchLabels:

app: meu-app

versao: blue

template:

metadata:

labels:

app: meu-app

versao: blue

spec:

containers:

  • name: app

image: meu-registro.azurecr.io/app:v1.0.0

ports:

  • containerPort: 8080

resources:

requests:

memory: &quot;256Mi&quot;

cpu: &quot;250m&quot;

limits:

memory: &quot;512Mi&quot;

cpu: &quot;500m&quot;

livenessProbe:

httpGet:

path: /health

port: 8080

initialDelaySeconds: 15

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

initialDelaySeconds: 5

periodSeconds: 5

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app-green

spec:

replicas: 3

selector:

matchLabels:

app: meu-app

versao: green

template:

metadata:

labels:

app: meu-app

versao: green

spec:

containers:

  • name: app

image: meu-registro.azurecr.io/app:v1.1.0

ports:

  • containerPort: 8080

resources:

requests:

memory: &quot;256Mi&quot;

cpu: &quot;250m&quot;

limits:

memory: &quot;512Mi&quot;

cpu: &quot;500m&quot;

livenessProbe:

httpGet:

path: /health

port: 8080

initialDelaySeconds: 15

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

initialDelaySeconds: 5

periodSeconds: 5

---

apiVersion: v1

kind: Service

metadata:

name: app-service

spec:

selector:

app: meu-app

versao: blue # Atualmente apontando para blue

ports:

  • protocol: TCP

port: 80

targetPort: 8080</code></pre>

<p>O truque está no selector do Service. Ele aponta para <code>versao: blue</code>, então todo o tráfego vai para o Blue Deployment. Quando você quer fazer o deploy da versão 1.1.0 no Green, você sobe completamente, testa em uma URL privada, e depois muda o selector do Service:</p>

<pre><code class="language-bash"># Verificar que Green está pronto

kubectl get pods -l app=meu-app,versao=green

Quando tudo estiver ok, fazer a troca

kubectl patch service app-service -p &#039;{&quot;spec&quot;:{&quot;selector&quot;:{&quot;versao&quot;:&quot;green&quot;}}}&#039;

Se precisar voltar

kubectl patch service app-service -p &#039;{&quot;spec&quot;:{&quot;selector&quot;:{&quot;versao&quot;:&quot;blue&quot;}}}&#039;</code></pre>

<p>Para automatizar isso um pouco mais, você pode criar um script:</p>

<pre><code class="language-bash">#!/bin/bash

CURRENT_VERSION=$(kubectl get service app-service -o jsonpath=&#039;{.spec.selector.versao}&#039;)

NEXT_VERSION=$([[ &quot;$CURRENT_VERSION&quot; == &quot;blue&quot; ]] &amp;&amp; echo &quot;green&quot; || echo &quot;blue&quot;)

echo &quot;Versão atual: $CURRENT_VERSION&quot;

echo &quot;Alternando para: $NEXT_VERSION&quot;

kubectl patch service app-service -p &quot;{\&quot;spec\&quot;:{\&quot;selector\&quot;:{\&quot;versao\&quot;:\&quot;$NEXT_VERSION\&quot;}}}&quot;

echo &quot;Deploy concluído! Pressione Enter para fazer rollback se necessário...&quot;

read -r

kubectl patch service app-service -p &quot;{\&quot;spec\&quot;:{\&quot;selector\&quot;:{\&quot;versao\&quot;:\&quot;$CURRENT_VERSION\&quot;}}}&quot;</code></pre>

<h3>Vantagens e Desvantagens</h3>

<p><strong>Vantagens:</strong> Transição instantânea entre versões, rollback trivial, zero downtime, fácil de testar completamente antes de expor ao público. <strong>Desvantagens:</strong> Requer o dobro de recursos (duas stacks completas rodando), deploy é mais lento porque você precisa aguardar a startup completa do Green, gerenciamento manual de qual versão é qual (pode ficar confuso).</p>

<h2>Canary Deployment: O Experimento Controlado</h2>

<h3>O Conceito Fundamental</h3>

<p>Canary Deployment é inspirado na prática histórica de mineiros levar canários às minas como detector de gás tóxico. A ideia é <strong>fazer deploy da nova versão para um pequeno percentual de usuários reais (5-10%), monitorar métricas de erro e performance, e apenas se tudo estiver bem, aumentar gradualmente até 100%</strong>.</p>

<p>É um meio termo entre Rolling e Blue-Green: você obtém a segurança de testar com tráfego real, mas com risco limitado. Se algo der errado, apenas uma fração de usuários é impactada. Ferramentas como Istio e Flagger tornaram isso prático.</p>

<h3>Implementação com Istio</h3>

<p>Istio é um service mesh que fornece controle fino sobre como o tráfego é roteado entre versões. Vou mostrar uma implementação prática:</p>

<pre><code class="language-yaml">---

apiVersion: v1

kind: Service

metadata:

name: app-canary

spec:

ports:

  • port: 8080

name: http

selector:

app: app-canary

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app-canary-v1

spec:

replicas: 3

selector:

matchLabels:

app: app-canary

version: v1

template:

metadata:

labels:

app: app-canary

version: v1

spec:

containers:

  • name: app

image: meu-registro.azurecr.io/app-canary:v1.0.0

ports:

  • containerPort: 8080

livenessProbe:

httpGet:

path: /health

port: 8080

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

periodSeconds: 5

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: app-canary-v2

spec:

replicas: 1 # Começando com apenas 1 réplica para canary

selector:

matchLabels:

app: app-canary

version: v2

template:

metadata:

labels:

app: app-canary

version: v2

spec:

containers:

  • name: app

image: meu-registro.azurecr.io/app-canary:v2.0.0

ports:

  • containerPort: 8080

livenessProbe:

httpGet:

path: /health

port: 8080

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: 8080

periodSeconds: 5

---

apiVersion: networking.istio.io/v1beta1

kind: VirtualService

metadata:

name: app-canary

spec:

hosts:

  • app-canary

http:

  • match:
  • uri:

prefix: &quot;/&quot;

route:

  • destination:

host: app-canary

subset: v1

weight: 90

  • destination:

host: app-canary

subset: v2

weight: 10 # 10% do tráfego para canary

---

apiVersion: networking.istio.io/v1beta1

kind: DestinationRule

metadata:

name: app-canary

spec:

host: app-canary

trafficPolicy:

connectionPool:

tcp:

maxConnections: 1000

http:

http1MaxPendingRequests: 100

h2UpgradePolicy: UPGRADE

subsets:

  • name: v1

labels:

version: v1

  • name: v2

labels:

version: v2</code></pre>

<p>Para aumentar gradualmente o tráfego para v2, você atualiza o VirtualService:</p>

<pre><code class="language-bash"># Fase 1: 10% (já está assim no YAML acima)

kubectl apply -f canary-10.yaml

Monitore por alguns minutos/horas

Verifique métricas no Prometheus/Grafana

Fase 2: 25% se tudo estiver ok

kubectl patch virtualservice app-canary --type merge -p \

&#039;{&quot;spec&quot;:{&quot;http&quot;:[{&quot;match&quot;:[{&quot;uri&quot;:{&quot;prefix&quot;:&quot;/&quot;}}],&quot;route&quot;:[{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v1&quot;},&quot;weight&quot;:75},{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v2&quot;},&quot;weight&quot;:25}]}]}}&#039;

Fase 3: 50%

kubectl patch virtualservice app-canary --type merge -p \

&#039;{&quot;spec&quot;:{&quot;http&quot;:[{&quot;match&quot;:[{&quot;uri&quot;:{&quot;prefix&quot;:&quot;/&quot;}}],&quot;route&quot;:[{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v1&quot;},&quot;weight&quot;:50},{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v2&quot;},&quot;weight&quot;:50}]}]}}&#039;

Fase 4: 100% (completo)

kubectl patch virtualservice app-canary --type merge -p \

&#039;{&quot;spec&quot;:{&quot;http&quot;:[{&quot;match&quot;:[{&quot;uri&quot;:{&quot;prefix&quot;:&quot;/&quot;}}],&quot;route&quot;:[{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v1&quot;},&quot;weight&quot;:0},{&quot;destination&quot;:{&quot;host&quot;:&quot;app-canary&quot;,&quot;subset&quot;:&quot;v2&quot;},&quot;weight&quot;:100}]}]}}&#039;</code></pre>

<h3>Automação com Flagger</h3>

<p>Flagger é uma ferramenta que automatiza esse processo. Ela monitora métricas e promove a canary automaticamente:</p>

<pre><code class="language-yaml">apiVersion: flagger.app/v1beta1

kind: Canary

metadata:

name: app-canary

spec:

targetRef:

apiVersion: apps/v1

kind: Deployment

name: app-canary

progressDeadlineSeconds: 300

service:

port: 8080

analysis:

interval: 1m

threshold: 5

maxWeight: 50

stepWeight: 10

metrics:

  • name: request-success-rate

thresholdRange:

min: 99

interval: 1m

  • name: request-duration

thresholdRange:

max: 500

interval: 1m</code></pre>

<p>Com este Canary Resource, o Flagger automaticamente:</p>

<ul>

<li>Começa com 10% do tráfego para v2</li>

<li>A cada 1 minuto, verifica as métricas (taxa de sucesso &gt; 99%, latência &lt; 500ms)</li>

<li>Se as métricas estiverem ok, incrementa 10% mais</li>

<li>Se alguma métrica falhar, para o processo e faz rollback</li>

</ul>

<h3>Vantagens e Desvantagens</h3>

<p><strong>Vantagens:</strong> Validação com tráfego real, risco muito reduzido, fácil monitorar diferenças entre versões, pode ser totalmente automatizado. <strong>Desvantagens:</strong> Requer infraestrutura de observabilidade (Prometheus, etc), mais complexo de configurar, &quot;versão mista&quot; por um tempo (compatibilidade de dados/APIs importante).</p>

<h2>Guia de Decisão: Qual Usar?</h2>

<p>A escolha entre essas três estratégias não é arbitrária. Considere estes fatores:</p>

<p><strong>Use Rolling Deployment se:</strong> você tem uma aplicação simples ou monolítica, deploy é frequente (CI/CD agressivo), você confia em seus testes automatizados, e a compatibilidade entre versões é garantida. É a opção mais simples e geralmente a padrão.</p>

<p><strong>Use Blue-Green se:</strong> mudanças de versão são pouco frequentes mas críticas, você precisa de rollback instantâneo, tem budget para rodar duas stacks, ou quer testar completamente antes de expor aos usuários. Ideal para sistemas financeiros ou de saúde.</p>

<p><strong>Use Canary se:</strong> você quer máxima segurança com mínimo downtime, tem infraestrutura de observabilidade madura, deploy frequente com mudanças significativas, ou quer detectar problemas no mundo real antes de afetar todos os usuários.</p>

<p>A realidade é que muitas empresas usam Rolling para deploy automatizado de features, Blue-Green para releases maiores, e Canary com Flagger para feature flags e experimentos A/B.</p>

<h2>Conclusão</h2>

<p>Aprendemos que <strong>a estratégia de deploy não é apenas &quot;como colocar código em produção&quot;, mas uma decisão arquitetural que afeta disponibilidade, tempo de deploy, complexidade operacional e capacidade de rollback</strong>. Rolling Deployment oferece simplicidade com trade-offs aceitáveis para a maioria dos casos. Blue-Green fornece a máxima segurança quando você pode investir em infraestrutura duplicada. Canary é a escolha moderna quando você quer experimental evidence de que a nova versão está segura, não apenas hopes and prayers.</p>

<p><strong>O ponto crítico que muitos iniciantes perdem:</strong> independentemente da estratégia escolhida, sua aplicação precisa suportar mudanças. Implementar health checks robustos, liveness e readiness probes corretos, e tentar manter compatibilidade de APIs entre versões consecutivas são pré-requisitos para qualquer deploy seguro. A estratégia escolhida é apenas o orquestrador disso tudo.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" target="_blank" rel="noopener noreferrer">Kubernetes Documentation - Deployments</a></li>

<li><a href="https://istio.io/latest/docs/tasks/traffic-management/traffic-shifting/canary/" target="_blank" rel="noopener noreferrer">Istio Documentation - Traffic Management</a></li>

<li><a href="https://flagger.app/" target="_blank" rel="noopener noreferrer">Flagger - Progressive Delivery Operator for Kubernetes</a></li>

<li><a href="https://docs.aws.amazon.com/whitepapers/latest/blue-green-deployments/" target="_blank" rel="noopener noreferrer">Blue Green Deployments on AWS</a></li>

<li><a href="https://cloud.google.com/architecture/patterns-for-deploying-kubernetes-applications" target="_blank" rel="noopener noreferrer">Google Cloud - Deployment Strategies</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

Container Registry: Docker Hub, GHCR e Registry Privado com Harbor: Do Básico ao Avançado
Container Registry: Docker Hub, GHCR e Registry Privado com Harbor: Do Básico ao Avançado

O que é um Container Registry Um Container Registry é um repositório centrali...

Como Usar GCP para DevOps: GKE, Cloud Run, Cloud SQL e IAM em Produção
Como Usar GCP para DevOps: GKE, Cloud Run, Cloud SQL e IAM em Produção

Google Cloud Platform para DevOps: Uma Introdução Prática Bem-vindo a este gu...

Como Usar Segurança em Containers Docker: Rootless, Capabilities e Scanning em Produção
Como Usar Segurança em Containers Docker: Rootless, Capabilities e Scanning em Produção

Segurança em Containers Docker: Rootless, Capabilities e Scanning Quando fala...