23 de setembro de 2026 · 5 min de leitura
Ensaie desastres antes que a produção faça isso por você
Um runbook prático de GitOps: minikube, Terraform, Argo CD em app-of-apps e três ensaios de desastre antes de uma migração real.
O problema com runbooks nunca testados
Toda equipe tem um documento de disaster recovery em algum lugar — uma página de wiki, um RUNBOOK.md que ninguém abre fora do onboarding. Ele diz o que fazer quando um deploy quebra ou o scaling se comporta mal. Ninguém nunca o executou. Antes de migrar a infraestrutura de produção de um cliente para um novo cluster, montei um setup local descartável especificamente para quebrar de propósito. Segue o passo a passo — roube isso antes da sua próxima migração, não durante ela.
O que você precisa
minikube,kubectl,terraform, a CLIargocd- Um repositório git que você controla (um repo descartável no GitHub serve)
Passo 1 — Suba um cluster descartável
minikube start --cpus=4 --memory=8192 --driver=docker
kubectl get nodes
Passo 2 — Instale o Argo CD com Terraform
Use Terraform em vez de um manifesto cru — é provavelmente a mesma ferramenta que você vai usar para provisionar os recursos de suporte do cluster real, então rastrear o estado da infra começa aqui.
# main.tf
terraform {
required_providers {
kubernetes = { source = "hashicorp/kubernetes", version = "~> 2.27" }
helm = { source = "hashicorp/helm", version = "~> 2.12" }
}
}
provider "kubernetes" { config_path = "~/.kube/config" }
provider "helm" {
kubernetes { config_path = "~/.kube/config" }
}
resource "kubernetes_namespace" "argocd" {
metadata { name = "argocd" }
}
resource "helm_release" "argocd" {
name = "argocd"
repository = "https://argoproj.github.io/argo-helm"
chart = "argo-cd"
namespace = kubernetes_namespace.argocd.metadata[0].name
version = "6.7.3"
}
terraform init
terraform apply -auto-approve
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
kubectl -n argocd port-forward svc/argocd-argocd-server 8080:443 &
argocd login localhost:8080 --username admin --password <senha> --insecure
Passo 3 — Estruture o deployment como app-of-apps
Estrutura no repositório git:
apps/
root-app.yaml
weather/
argocd-app.yaml
deployment.yaml
service.yaml
apps/root-app.yaml — uma Application que gerencia o resto a partir do Git:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/<voce>/gitops-sandbox.git
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
apps/weather/argocd-app.yaml — a app filha:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: weather-api
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/<voce>/gitops-sandbox.git
targetRevision: main
path: apps/weather
destination:
server: https://kubernetes.default.svc
namespace: weather
syncPolicy:
automated:
prune: true
selfHeal: true
kubectl create namespace weather
kubectl apply -f apps/root-app.yaml
argocd app list
Passo 4 — Implante algo descartável
O app não importa — uma API de clima trivial serve. O que importa é que ele tenha réplicas, uma estratégia de rollout e uma política de sync real, para falhar do jeito que um deployment de produção falha.
# apps/weather/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: weather-api
namespace: weather
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate: { maxUnavailable: 1, maxSurge: 1 }
selector: { matchLabels: { app: weather-api } }
template:
metadata: { labels: { app: weather-api } }
spec:
containers:
- name: weather-api
image: ghcr.io/example/weather-api:1.0.0
ports: [{ containerPort: 8080 }]
git add . && git commit -m "deploy weather-api" && git push
argocd app sync weather-api
kubectl -n weather get pods -w
Ensaio 1 — Correção manual vs. self-heal
Com selfHeal: true, o GitOps reconcilia continuamente. Isso também significa que uma correção manual de emergência é desfeita silenciosamente.
# Scale-down de emergência direto no cluster
kubectl -n weather scale deployment weather-api --replicas=0
# O Argo CD nota o drift e reverte em segundos
kubectl -n weather get pods -w
Agora desative o self-heal de propósito e repita:
argocd app set weather-api --self-heal=false
kubectl -n weather scale deployment weather-api --replicas=0
kubectl -n weather get pods
# desta vez, permanece
# retome a operação normal
argocd app set weather-api --self-heal=true
argocd app sync weather-api
Saber qual flag alternar, e lembrar de voltá-la depois, não é óbvio na primeira vez. Fica óbvio na segunda, se a primeira foi um ensaio.
Ensaio 2 — Revertendo uma mudança de scaling ruim
Suba uma contagem de réplicas ruim pelo Git, do jeito que uma mudança real chegaria:
sed -i '' 's/replicas: 2/replicas: 0/' apps/weather/deployment.yaml
git commit -am "oops" && git push
argocd app sync weather-api
kubectl -n weather get pods
Reverta pelo caminho correto — via Git, para que o estado desejado continue verdadeiro:
git revert HEAD --no-edit && git push
argocd app sync weather-api
Depois, cronometre o caminho rápido-mas-errado para comparação:
kubectl -n weather scale deployment weather-api --replicas=2
O comando manual é mais rápido no momento e é apagado pelo próximo sync. Saber dessa troca antes de um incidente muda para onde sua equipe se volta sob pressão.
Ensaio 3 — Rollback de um deployment ruim
Quebre a tag da imagem de propósito:
sed -i '' 's/1.0.0/does-not-exist/' apps/weather/deployment.yaml
git commit -am "broken release" && git push
argocd app sync weather-api
kubectl -n weather get pods
# ImagePullBackOff
Reverta usando o histórico do próprio Argo CD:
argocd app history weather-api
argocd app rollback weather-api <REVISION_ID>
Ou, como caminho de emergência quando não dá para esperar o Git ou o CI:
kubectl -n weather rollout undo deployment/weather-api
Cronometre os dois. Se o rollback pelo Argo CD leva dez minutos num sandbox sem nada em jogo, ele não vai magicamente levar dois durante um fim de semana de migração real.
Transformando os ensaios em runbook
Escreva os comandos exatos que você acabou de rodar — incluindo as flags que precisou procurar — num RUNBOOK.md ao lado dos manifestos do app-of-apps. Não a teoria. Os comandos, na ordem que funcionou.
Foram exatamente esses ensaios que moldaram decisões na migração real que veio depois: autoscaling orientado a eventos apoiado numa fila de mensagens em vez de contagens estáticas de réplicas (a reversão manual de scaling foi o ensaio mais desajeitado), uma instância Postgres gerenciada em vez de armazenamento dentro do cluster, um engine de workflow dedicado em vez de jobs improvisados, e um backend remoto de estado do Terraform definido desde o início em vez de um detalhe posterior. Nada disso veio de um quadro branco — veio de observar o que era desajeitado de recuperar no sandbox.
O que isso custa
Um cluster local e um app descartável custam uma tarde. Um rollback que falha sob pressão durante uma migração real custa muito mais — em downtime, e em explicar depois por que o procedimento documentado não funcionou quando importava. Rode os ensaios num sistema sem nada a perder, antes que a produção os rode por você num cronograma que ela controla.
Conheça meu trabalho
Se isto foi útil, veja as plataformas que construí ou fale comigo sobre um projeto.