05 - ArgoCD (GitOps)
video: https://youtu.be/... no frontmatter da nota.ArgoCD (GitOps)
ArgoCD é o controlador declarativo de entrega contínua para Kubernetes que consolidou as práticas de GitOps em produção: o estado desejado da aplicação vive em um repositório Git, e o ArgoCD compara continuamente esse estado com o estado real do cluster, sincronizando o que divergir. A inversão de direção é o traço definidor; em vez de um pipeline que empurra mudanças para o cluster, o controlador dentro do cluster puxa do Git e corrige o mundo até igualar a fonte de verdade. Essa inversão produz propriedades que pipelines de push não oferecem, detecção de drift, autocorreção, rollback por revert de commit e trilha de auditoria completa. Em produção, o ArgoCD virou peça padrão de plataformas Kubernetes, porque resolve o problema crônico de saber o que está rodando, quem mudou e como voltar atrás com confiabilidade mecânica.
Conceito: GitOps e estado desejado
GitOps define que o Git contém a descrição completa e declarativa do estado desejado do sistema, e um controlador garante que a realidade convirja para essa descrição. No ArgoCD, a unidade de gestão é a Application, um recurso que aponta para um repositório, um caminho e um cluster, e que monitora a diferença entre o Git e os recursos vivos. Os três princípios operacionais do modelo:
- Estado declarativo: o repositório descreve o estado final, manifests, Helm charts ou Kustomize, nunca uma sequência de comandos a executar.
- Versionado e imutável: cada mudança de estado é um commit revisável, com autor, motivo e histórico completo para auditoria.
- Reconciliado automaticamente: um agente dentro do cluster compara desejado e real de forma contínua, sem depender de alguém lembrar de aplicar.
O resultado é que a operação do cluster ganha a mesma disciplina do código: pull request para mudar produção, review antes do merge e revert como rollback nativo.
Vale distinguir GitOps de automação simples de deploy. Um pipeline que aplica manifests ao final da execução continua sendo push, com credencial de escrita no cluster armazenada fora dele e sem nenhum laço de correção depois da aplicação. GitOps é o laço completo, desejado versionado, controlador observando e realidade convergindo, e é essa propriedade de convergência contínua que separa as duas abordagens em qualquer conversa séria de arquitetura de entrega.
O problema que resolve
O problema clássico que o ArgoCD elimina é a deriva silenciosa entre o que está versionado e o que está rodando. Em times que aplicam mudanças por kubectl ou por script de push, bastam semanas para que ninguém saiba o estado real: alguém aplicou um hotfix direto no cluster, um ajuste de emergência no repliche não voltou ao repositório, e o próximo deploy automático sobrescreve mudança que ninguém sabia que existia. Os sintomas são conhecidos, deploy que apaga configuração feita na mão, investigação que depende de memória das pessoas, rollback que não funciona porque ninguém sabe qual era o estado anterior. O controlador de GitOps ataca pela raiz: qualquer mudança fora do Git aparece como divergência visível em minutos e, com autoHeal ligado, é revertida automaticamente. O cluster volta a ter uma única verdade, e a pergunta o que está em produção passa a ter resposta mecânica.
Funcionamento interno: reconciliação e detecção de drift
O controlador opera em laço contínuo com três momentos. Primeiro, ele busca o estado desejado no Git, renderizando os manifests pela ferramenta declarada, Helm, Kustomize ou YAML puro. Depois, compara esse estado com os recursos vivos no cluster, campo por campo, ignorando os atributos que o próprio Kubernetes controla, como status e defaults aplicados pela API. Por fim, classifica o resultado em três estados, Synced quando a realidade iguala o Git, OutOfSync quando existe divergência, e Unknown quando a comparação falha, e expõe cada um na interface e na API. A comparação roda por padrão a cada três minutos, com webhooks do Git acelerando o ciclo quando o repositório muda. A detecção de drift é o mesmo mecanismo executado sem push recente, e é exatamente por isso que consegue captar mudanças feitas fora do fluxo normal, pois a divergência aparece na próxima varredura independentemente de quem a causou.
Sincronização automática, selfHeal e política de prune
A configuração da sincronização decide a agressividade do controlador, e é aqui que se concentram as decisões de produção. A política recomendada para serviços combinado sync automático com selfHeal, e prune controlado com revisão humana:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: pedidos-producao
namespace: argocd
spec:
project: plataforma
source:
repoURL: https://git.exemplo.com/plataforma/deploy-pedidos.git
targetRevision: main # revisão rastreada no repositório de deploy
path: overlays/producao # manifests do ambiente via Kustomize
destination:
server: https://kubernetes.prod.svc
namespace: pedidos
syncPolicy:
automated:
prune: false # prune automático exige decisão consciente
selfHeal: true # reverte mudança aplicada fora do Git
allowEmpty: false # bloqueia sync que apagaria tudo
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true # aplica apenas o que divergiu
retry:
limit: 5 # nova tentativa em conflito transitório
backoff:
duration: 20s
factor: 2
maxDuration: 5m
Cada chave carrega uma decisão que merece entendimento. O selfHeal true garante que mudança manual no cluster reverte para o Git, mantendo o repositório como fonte única; quem precisa de intervenção de emergência a faz por commit rápido, e o histórico registra quem, quando e por quê. O prune false é o padrão prudente: com ele ligado em true, o ArgoCD apaga qualquer recurso que não exista mais no Git, poderoso para limpeza e perigoso quando um refactor remove manifest por engano, e a prática consolidada é ligar prune com janelas de revisão ou por ambiente menos crítico primeiro. O allowEmpty false protege contra o erro catastrófico de um repositório vazio ou caminho errado apagar a aplicação inteira.
ApplicationSets para multi-cluster e multi-ambiente
A Application resolve um serviço em um ambiente; dezenas de serviços em múltiplos clusters multiplicariam arquivos repetitivos e propensos a deriva de configuração. O ApplicationSet resolve a escala gerando Applications a partir de templates e geradores, e consolidou-se como a peça padrão para multi-ambiente e multi-cluster:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: pedidos-ambientes
namespace: argocd
spec:
generators:
- list:
elements:
- ambiente: staging
cluster: https://kubernetes.staging.svc
- ambiente: producao
cluster: https://kubernetes.prod.svc
template:
metadata:
name: "pedidos-{{ambiente}}"
spec:
source:
repoURL: https://git.exemplo.com/plataforma/deploy-pedidos.git
targetRevision: main
path: "overlays/{{ambiente}}" # cada ambiente lê seu overlay
destination:
server: "{{cluster}}"
namespace: pedidos
syncPolicy:
automated:
selfHeal: true
Adicionar um cluster ou um ambiente passa a ser uma linha no gerador, e a mesma mudança de configuração se propaga para todas as Applications geradas na próxima reconciliação. O efeito em governança é direto: a divergência entre ambientes deixa de ser configuração espalhada e vira diferença explícita de overlay no repositório.
Além do gerador de lista, dois outros merecem nota pela adoção em plataformas. O gerador de diretórios Git cria uma Application para cada pasta do repositório, o que permite adicionar um serviço ao cluster com um diretório novo e nenhum toque no ArgoCD. O gerador de clusters descobre clusters registrados e gera Applications para cada um, padrão em organizações que espalham cargas por regiões e precisam de paridade de configuração entre elas.
Repositório de deploy separado
A prática consolidada do ecossistema separa o repositório de código do repositório de deploy. O pipeline de CI constrói e testa o código, publica a imagem com tag imutável e, na última etapa, atualiza o repositório de deploy, normalmente por pull request automático ou commit direto, substituindo a tag da imagem no manifesto. A separação produz três benefícios que justificam o custo de manter dois repositórios:
- Desacoplamento de ciclos: o código avança com centenas de commits por dia; o estado de produção muda em dezenas de commits revisados, e os ritmos não se contaminam.
- Segurança por mínimo privilégio: o ArgoCD precisa de acesso apenas ao repositório de deploy, nunca ao código-fonte, reduzindo o raio de acesso da credencial.
- Histórico limpo de produção: o log do repositório de deploy é a linha do tempo exata de mudanças em cada ambiente, sem ruído de refatoração e dependências.
O fluxo completo fica assim: commit no código dispara CI; CI valida e publica imagem; CI abre pull request no repositório de deploy com a nova tag; revisão humana aprova; merge dispara a reconciliação do ArgoCD, que aplica o estado no cluster.
Diff visual e rollback
A interface do ArgoCD mostra o diff em três camadas: diferença entre Git e cluster no momento presente, histórico de sincronizações com o manifesto exato aplicado em cada uma, e simulação do resultado de um sync antes de executá-lo. O rollback aproveita essa estrutura: como cada sincronização guarda o estado Git que a gerou, voltar é reimplantar o commit anterior, operação de segundos que não depende de reconstruir artefato. Em produção, isso muda a dinâmica de incidente, porque a reversão do estado do cluster é desacoplada da reversão do código, e ambos ficam registrados. Duas regras sustentam a prática:
- Rollback por Git, não pela interface: a reversão feita pela UI é sobreposta pelo selfHeal na próxima reconciliação; o caminho correto é revert do commit, que mantém o histórico coerente.
- Diff como alarme: divergência recorrente em um recurso indica configuração gerenciada fora do lugar, como mutação feita por controlador externo, e merece ajuste de comparação ou de propriedade ignorada.
Comparações: GitOps pull versus deploy por pipeline push
| Aspecto | GitOps com ArgoCD | Deploy por pipeline push |
|---|---|---|
| Direção da entrega | Controlador no cluster puxa do Git | Pipeline de fora empurra ao cluster |
| Credencial em produção | O cluster lê o repositório de deploy | O CI guarda acesso de escrita ao cluster |
| Detecção de drift | Contínua e automática | Inexistente sem camada extra |
| Rollback | Revert de commit reaplicado em segundos | Reexecução de pipeline ou script manual |
| Estado verdadeiro | Git reflete o cluster com correção automática | Cluster pode divergir sem aviso |
| Onboarding de novo cluster | Apontar a Application e reconciliar | Replicar pipeline e credenciais |
| Exigência de plataforma | Kubernetes com controlador instalado | Qualquer alvo suportado pela ferramenta |
A leitura objetiva: para cargas em Kubernetes, o modelo pull ganha em segurança, auditoria e autocorreção; o push permanece razoável para alvos que não são Kubernetes ou para times no início da jornada, onde adotar GitOps antes de dominar manifests declarativos adiciona complexidade sem retorno imediato.
Anti-padrões comuns e boas práticas
Os anti-padrões abaixo aparecem em adoções apressadas e têm correção conhecida:
- Manifests gerados por push manual escondido: time mantém ArgoCD, mas alguém ainda aplica mudança direta com kubectl em incidente sem registrar depois no Git; o procedimento de emergência precisa incluir o commit de reconciliação obrigatório.
- Prune automático ligado cedo demais: remoção de manifest por engano apaga recursos de produção; habilitar prune por ambiente, começando onde o erro custa menos.
- Repositório único de código e deploy: credencial ampla, histórico poluído e acoplamento de ciclos; a separação é o primeiro refactor recomendado na jornada GitOps.
- Segredos em texto puro no Git: manifest com senha versionada é incidente agendado; segredos vêm de cifras, como Sealed Secrets ou plugin SOPS, ou de integração com cofre externo.
- Application sem projeto nem limites: Applications criadas soltas, sem restrição de namespace, cluster ou repositório; o recurso de projects existe para impor esses limites e deve ser padrão.
- Atualização de tag da imagem fora do fluxo: script avulso que edita o manifesto de deploy contornando o CI elimina a rastreabilidade entre código e produção; a mudança de tag acontece por commit automatizado do próprio pipeline.
Entre as boas práticas que consolidam a operação, três se destacam. Tratar o repositório de deploy como produto da plataforma, com estrutura de overlays previsível, templates revisados e convenção documentada de mudança. Medir a saúde da reconciliação, com alerta para Applications presas em OutOfSync ou em erro de sync por mais tempo que o aceitável, porque divergência ignorada corrói a confiança na fonte de verdade. E exercitar o rollback em dias normais, com revert simulado em homologação, para que a reversão em incidente seja músculo treinado e não descoberta de emergência.