<h2>O que é Progressive Delivery?</h2>
<p>Progressive Delivery é um modelo de implantação que permite liberar alterações de software para produção de forma gradual e controlada, minimizando riscos e permitindo validação em tempo real. Diferente da entrega contínua tradicional (onde você implanta tudo de uma vez), a progressive delivery segmenta o acesso a novas versões, observa comportamento, coleta métricas e decide automaticamente se continua a migração ou faz rollback.</p>
<p>A principal vantagem é reduzir o impacto de bugs ou problemas de performance. Se você descobre que a versão nova consome mais memória ou tem latência mais alta, você não perdeu 100% dos seus usuários. Você pode parar a migração, investigar, corrigir e tentar novamente. Isso é especialmente crítico em sistemas de missão crítica onde indisponibilidade ou degradação custa dinheiro em tempo real.</p>
<h2>Argo Rollouts: Orquestração de Progressive Delivery no Kubernetes</h2>
<h3>O que é Argo Rollouts?</h3>
<p>Argo Rollouts é uma extensão do Kubernetes mantida pela CNCF que traz estratégias sofisticadas de implantação além do Deployment padrão. Enquanto o Deployment do Kubernetes oferece apenas Rolling Updates ou Recreate, Argo Rollouts implementa nativamente Canary, Blue-Green, e A/B Testing com suporte automático a análise de métricas.</p>
<p>Argo Rollouts funciona através de um recurso customizado chamado <code>Rollout</code>. Você define seu aplicativo como um Rollout em vez de um Deployment, e o controller do Argo Rollouts gerencia a transição entre versões conforme regras de tráfego e critérios de análise que você especifica. Isso é poderoso porque toda a lógica de decisão (continuar ou reverter) é declarativa, versionável e repetível.</p>
<h3>Instalando Argo Rollouts</h3>
<p>Antes de criar seu primeiro Rollout, você precisa instalar o controller no cluster. Argo Rollouts roda como um deployment no namespace <code>argo-rollouts</code>:</p>
<pre><code class="language-bash">kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml</code></pre>
<p>Após a instalação, verifique se o controller está rodando:</p>
<pre><code class="language-bash">kubectl get pods -n argo-rollouts</code></pre>
<p>Você deve ver um pod com nome <code>argo-rollouts-*</code> em estado <code>Running</code>. Se estiver em <code>CrashLoopBackOff</code>, verifique os logs com <code>kubectl logs -n argo-rollouts <pod-name></code>.</p>
<h2>Estratégia Canary: Implantação Gradual com Validação Automática</h2>
<h3>Conceito e Fluxo</h3>
<p>Canary é uma estratégia onde você envia a nova versão para um pequeno percentual de usuários (por exemplo, 5%) e observa métricas como taxa de erro, latência e uso de recursos. Se tudo estiver bem, você aumenta gradualmente o percentual até que todos os usuários estejam na nova versão. Se algo der errado, você reverte para a versão anterior automaticamente.</p>
<p>O nome "canary" vem da metáfora do canário na mina de carvão: os mineiros levavam canários porque eles morriam quando havia gás tóxico, servindo como alarme. Aqui, o canário é seu pequeno grupo de usuários que "avisa" se a nova versão tem problemas.</p>
<h3>Exemplo Prático: Canary com Análise Automática</h3>
<p>Vamos criar um Rollout que faz implantação canary automática. Suponha que você tem uma API simples em Go:</p>
<pre><code class="language-go">package main
import (
"fmt"
"net/http"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
version := os.Getenv("APP_VERSION")
if version == "" {
version = "v1"
}
fmt.Fprintf(w, "Hello from %s\n", version)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}</code></pre>
<p>Você conteirizará isso em uma imagem Docker chamada <code>meu-app:v1</code> e depois <code>meu-app:v2</code> com <code>APP_VERSION=v2</code>.</p>
<p>Agora crie um Rollout que faz canary automático:</p>
<pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: meu-app
spec:
replicas: 4
selector:
matchLabels:
app: meu-app
template:
metadata:
labels:
app: meu-app
spec:
containers:
- name: meu-app
image: meu-app:v1
ports:
- containerPort: 8080
env:
- name: APP_VERSION
value: "v1"
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 5m}
- setWeight: 100
revisionHistoryLimit: 2</code></pre>
<p>Neste exemplo, o Rollout começa com 20% do tráfego na nova versão, aguarda 5 minutos (tempo para coletar métricas), aumenta para 50%, aguarda novamente, e finalmente coloca 100%. Se nenhuma análise falhar nesse tempo, a versão nova é promovida.</p>
<p>Para atualizar para a versão v2, você muda a imagem:</p>
<pre><code class="language-bash">kubectl patch rollout meu-app --type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"meu-app:v2"}]'</code></pre>
<p>Ou edite o YAML diretamente com <code>kubectl edit rollout meu-app</code>.</p>
<h3>Integração com Análise (Prometheus)</h3>
<p>Para que o Rollout realmente interrompa a migração em caso de problemas, você precisa definir regras de análise. Isso requer um recurso chamado <code>AnalysisTemplate</code>. Vamos supor que você tem Prometheus rodando no cluster:</p>
<pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: meu-app-analysis
spec:
metrics:
- name: error-rate
interval: 60s
successCriteria: "{{ result <= 0.05 }}"
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{job="meu-app",status=~"5.."}[5m])) /
sum(rate(http_requests_total{job="meu-app"}[5m]))
- name: response-latency
interval: 60s
successCriteria: "{{ result < 500 }}"
provider:
prometheus:
address: http://prometheus:9090
query: |
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="meu-app"}[5m])) by (le))</code></pre>
<p>Agora modifique seu Rollout para usar essa análise:</p>
<pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: meu-app
spec:
replicas: 4
selector:
matchLabels:
app: meu-app
template:
metadata:
labels:
app: meu-app
spec:
containers:
- name: meu-app
image: meu-app:v1
ports:
- containerPort: 8080
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 5m}
- analysis:
templates:
- name: meu-app-analysis
- setWeight: 50
- pause: {duration: 5m}
- setWeight: 100</code></pre>
<p>Agora, após 5 minutos na versão canary (20%), o Argo Rollouts executa a análise. Se a taxa de erro estiver acima de 5% ou a latência acima de 500ms, a análise falha e a migração é revertida automaticamente.</p>
<h2>Estratégia Blue-Green: Troca Instantânea com Validação Offline</h2>
<h3>Conceito e Fluxo</h3>
<p>Blue-Green é radicalmente diferente de Canary. Em vez de gradualmente migrar tráfego, você mantém dois ambientes completos: Blue (atual) e Green (nova versão). O Green é preparado completamente em paralelo, testado offline, e depois você faz uma mudança instantânea de tráfego de Blue para Green. Se algo der errado, você volta para Blue imediatamente.</p>
<p>Blue-Green é mais apropriado para aplicações onde você quer validação completa antes de qualquer usuário ver a nova versão, ou quando suas métricas levam tempo para estabilizar (você não quer esperar 30 minutos em Canary). A desvantagem é que você precisa do dobro de recursos durante a transição.</p>
<h3>Exemplo Prático: Blue-Green com Validação Manual</h3>
<pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: meu-app-bg
spec:
replicas: 3
selector:
matchLabels:
app: meu-app-bg
template:
metadata:
labels:
app: meu-app-bg
spec:
containers:
- name: meu-app
image: meu-app:v1
ports:
- containerPort: 8080
strategy:
blueGreen:
activeSlotSelector: blue
prePromotionAnalysis:
templates:
- name: meu-app-analysis
autoPromotionEnabled: false
autoPromotionSeconds: 0</code></pre>
<p>Neste Rollout Blue-Green:</p>
<ul>
<li><code>activeSlotSelector: blue</code> significa que atualmente o slot "blue" (v1) está recebendo tráfego.</li>
<li>Quando você atualiza a imagem para <code>meu-app:v2</code>, o Argo cria pods novos no slot "green" sem mudar tráfego.</li>
<li><code>prePromotionAnalysis</code> roda testes antes de promover green para ativo. Você pode fazer chamadas HTTP, verificar logs, etc.</li>
<li><code>autoPromotionEnabled: false</code> significa que você decide manualmente quando fazer a troca. Para promover, você executa:</li>
</ul>
<pre><code class="language-bash">kubectl argo rollouts promote meu-app-bg</code></pre>
<p>Para reverter se algo der errado:</p>
<pre><code class="language-bash">kubectl argo rollouts abort meu-app-bg</code></pre>
<h3>Blue-Green Totalmente Automatizado</h3>
<p>Se você quer automação total, ative <code>autoPromotionEnabled</code>:</p>
<pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: meu-app-bg-auto
spec:
replicas: 3
selector:
matchLabels:
app: meu-app-bg-auto
template:
metadata:
labels:
app: meu-app-bg-auto
spec:
containers:
- name: meu-app
image: meu-app:v1
ports:
- containerPort: 8080
strategy:
blueGreen:
activeSlotSelector: blue
prePromotionAnalysis:
templates:
- name: meu-app-analysis
autoPromotionEnabled: true
autoPromotionSeconds: 300</code></pre>
<p>Com isso:</p>
<ol>
<li>Você atualiza a imagem.</li>
<li>Green é criado e testado com a análise.</li>
<li>Se a análise passar, após 300 segundos (5 minutos) o tráfego é automaticamente movido para green.</li>
<li>Blue permanece rodando e pode ser rapidamente reativado se necessário.</li>
</ol>
<h2>Monitoramento e Troubleshooting de Rollouts</h2>
<h3>Inspecionando o Status do Rollout</h3>
<p>Para ver o progresso de um Rollout em tempo real:</p>
<pre><code class="language-bash">kubectl get rollouts -w</code></pre>
<p>Para detalhes completos sobre o status atual:</p>
<pre><code class="language-bash">kubectl describe rollout meu-app</code></pre>
<p>Para ver o histórico de análises executadas:</p>
<pre><code class="language-bash">kubectl get analysisruns
kubectl describe analysisrun <nome-do-run></code></pre>
<h3>Logs e Debugging</h3>
<p>Se uma análise falhar ou um step pausar indefinidamente, verifique os logs do controller:</p>
<pre><code class="language-bash">kubectl logs -n argo-rollouts -l app=argo-rollouts -f</code></pre>
<p>Verifique também se o recurso de Rollout está bem formado:</p>
<pre><code class="language-bash">kubectl get rollout meu-app -o yaml</code></pre>
<p>Se você tem múltiplas versões de um aplicativo e quer comparar:</p>
<pre><code class="language-bash">kubectl get rs -l app=meu-app</code></pre>
<p>Isso mostra os ReplicaSets (versões antigas e novas) que o Rollout criou.</p>
<h3>Revogando um Rollout em Andamento</h3>
<p>Se você detectar um problema durante a migração canary:</p>
<pre><code class="language-bash">kubectl argo rollouts abort meu-app</code></pre>
<p>Isso para imediatamente o rollout e mantém a versão anterior. Para saber qual versão está ativa:</p>
<pre><code class="language-bash">kubectl argo rollouts status meu-app</code></pre>
<h2>Conclusão</h2>
<p>Você aprendeu que <strong>Progressive Delivery com Argo Rollouts elimina a falsa dicotomia entre velocidade e segurança</strong>: você pode liberar múltiplas vezes ao dia para produção sem arriscar seus usuários. Canary funciona melhor quando suas métricas estabilizam rápido e você quer medir impacto em tempo real; Blue-Green é superior quando você precisa de validação offline completa ou quando quer uma janela de rollback instantâneo. Ambas as estratégias, quando acopladas a análises automáticas com Prometheus, transformam o deployment de um processo nervoso em uma atividade rotineira e confiável, com capacidade de decisão totalmente codificada e observável.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://argoproj.github.io/argo-rollouts/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Argo Rollouts</a></li>
<li><a href="https://github.com/argoproj/argo-rollouts/tree/master/examples" target="_blank" rel="noopener noreferrer">Argo Rollouts Examples no GitHub</a></li>
<li><a href="https://www.cncf.io/blog/" target="_blank" rel="noopener noreferrer">Progressive Delivery with Flagger and Argo Rollouts - CNCF Blog</a></li>
<li><a href="https://cloud.google.com/kubernetes-engine/docs/concepts/deployment-patterns" target="_blank" rel="noopener noreferrer">Kubernetes Best Practices: Progressive Rollouts - Google Cloud</a></li>
<li><a href="https://www.deployhub.com/continuous-delivery-handbook" target="_blank" rel="noopener noreferrer">The Continuous Delivery Handbook - DeployHub</a></li>
</ul>
<p><!-- FIM --></p>