← Voltar para o blog

william@devops:~$ cat ./laboratorio/gitops-do-zero.md

GitOps do zero no EKS:
nenhum kubectl apply.

Em uma tarde, subi um cluster EKS, instalei o Argo CD por Terraform e vi uma API entrar no ar sozinha, lida direto do Git. Conto o passo a passo real, inclusive as partes em que eu travei.

DE ONDE VEIO

Isso aconteceu no meu laboratório de estudo em 6 de outubro de 2026. Os prints são reais; IDs de conta e e-mail foram borrados.

01 / O OBJETIVO

O pipeline não deveria tocar no cluster.

Eu já tinha a esteira da API funcionando até o ECR. Faltava a última parte: colocar a imagem no Kubernetes. O jeito mais rápido seria dar ao pipeline uma credencial do cluster e rodarkubectl apply. Funciona, mas o pipeline vira dono do cluster, e ninguém sabe ao certo o que está rodando lá dentro.

A REGRA QUE EU SEGUI

O Git diz o que deve rodar. Quem aplica é o Argo CD, de dentro do cluster.

02 / O DESENHO

Três peças, cada uma com o seu papel.

01

Stack do EKS

Rede, cluster e nós. Terraform, como sempre.

02

Stack do Argo CD

Separada, com state próprio. Instala o Argo CD por Helm, com versão fixa.

03

Repositório GitOps

Manifests da API (base + overlay por ambiente) e um ApplicationSet.

04

Pipeline da API

Testa, faz o build, publica no ECR e muda só a tag da imagem no repositório GitOps.

Por que o Argo CD numa stack separada? Porque o provider do Helm precisa falar com o cluster. Criar o cluster e instalar coisas nele no mesmo apply é frágil: no primeiro plan o cluster ainda nem existe. Separando, cada um tem a sua vez.

03 / SUBINDO

O cluster subiu. O kubectl, não.

Terraform plan da stack do EKS com 68 recursos para criar
O plan do EKS: 68 recursos para criar, nenhum para mudar ou destruir. Uns 15 minutos de apply.

Com o cluster no ar, rodei kubectl get nodes e recebi um no such host. Fiquei uns segundos olhando para a tela até entender: eu tinha só impresso o comando do kubeconfig, sem executar. O kubectl ainda apontava para o cluster que eu tinha destruído dias antes.

PowerShellDICA
# imprime o comando (não executa)
terraform output -raw kubeconfig_command

# executa direto o que o Terraform imprime
Invoke-Expression (terraform output -raw kubeconfig_command)
kubectl get nodes   # 2 nodes Ready

Depois, o Argo CD em si foi a parte mais tranquila: um plan com 2 recursos e uns 2 minutos de apply.

Terraform plan da stack do Argo CD com dois releases Helm
O plan do Argo CD: o chart argo-cd e o argocd-apps, que cria os projetos e a Application raiz.
01

Projetos que limitam o estrago

Criei dois projetos no Argo CD. O plataforma só pode criar ApplicationSets. O estudo, onde ficam os apps, só lê o repositório GitOps e só entra em namespaces terminados em -dev. Se alguém errar um manifest, o estrago fica contido.

04 / O ACESSO AO GIT

O repositório é privado. O Argo CD precisava de uma chave.

Escolhi uma deploy key somente leitura: o Argo CD só precisa ler. Aí vieram dois tropeços:

  1. 01

    Deploy keys desligadas na organização

    A própria organização bloqueava deploy keys por política. Precisei liberar nas configurações da org.

  2. 02

    Quase com permissão de escrita

    Na primeira tentativa a caixa "Allow write access" ficou marcada. Apaguei e cadastrei de novo, só leitura.

  3. 03

    A chave fora do Git

    A chave privada foi direto para o cluster com um comando. Não passa pelo Git nem pelo state do Terraform.

PowerShellUMA VEZ POR CLUSTER
kubectl -n argocd create secret generic repo-gitops-estudo `
  --from-literal=type=git `
  --from-literal=url=git@github.com:minha-org/gitops-estudo.git `
  --from-file=sshPrivateKey="$HOME\.ssh\argocd-gitops-estudo"
kubectl -n argocd label secret repo-gitops-estudo argocd.argoproj.io/secret-type=repository

A Application raiz continuou Unknown: ela tinha tentado ler o repositório antes de a chave existir e estava esperando para tentar de novo. Um refresh forçado resolveu na hora.

PowerShellREFRESH
kubectl -n argocd annotate application root-develop argocd.argoproj.io/refresh=hard --overwrite

05 / FUNCIONOU

A API apareceu sozinha.

Segundos depois do refresh, o ApplicationSet leu a pasta apps/ e criou o app da API sozinho. Ninguém rodou kubectl apply.

Argo CD com root-develop e app-piloto-api-dev, ambos Healthy e Synced
root-develop (a raiz) e app-piloto-api-dev (criado pelo ApplicationSet), os dois Healthy e Synced.
Árvore do app no Argo CD com Service, ServiceAccount, Deployment, ReplicaSet e dois pods
Tudo que o Argo CD criou a partir do Git, sincronizado com o commit da develop.

E o log do pod confirma a versão: o SHA do commit foi gravado na imagem no build, e o ambiente dev veio do overlay do GitOps.

Log do pod com servidor iniciado, versão igual ao SHA do commit e ambiente dev
O pod dizendo exatamente qual commit está rodando.

06 / NA MÃO x COMO CÓDIGO

A primeira vez que fiz GitOps foi na mão.

Num projeto anterior, montei o Argo CD quase todo na mão, e o token de acesso ao repositório acabou commitado num arquivo. Funcionava, mas recriar o ambiente era lembrar de cada passo. Desta vez:

✓

Argo CD como código terraform apply, versão fixa, mudança por PR.

✓

Acesso ao Git deploy key só leitura, aplicada direto no cluster.

✓

Acesso ao cluster role com token temporário gerado na hora.

✓

Permissões projetos separados, cada um no seu quadrado.

✓

Recriar do zero dois applies e um kubectl. Mais nada.

07 / APRENDIZADOS

O que eu levo dessa.

GitOps não é instalar o Argo CD. É decidir quem pode mudar o que roda e deixar isso escrito. A ferramenta só obedece.

O próximo passo já está desenhado: o pipeline da API fazendo o commit da tag nova sozinho, e a troca do token por um GitHub App, sem dono pessoal. Fica para o próximo artigo.

william@devops:~$ echo $LESSON_LEARNED

"Se não está no Git, não deveria estar rodando."
COMPARTILHAR IDEIAS

Quer trocar uma ideia sobre Cloud ou DevOps?

Mandar um e-mail ↗