
Meu primeiro deploy no Kubernetes — e os 3 dias que passei debugando
Documentação lida, tutoriais assistidos, teoria clara. E ainda assim, quando tentei subir minha aplicação no Kubernetes, nada funcionou. Aqui está o que aprendi debugando ao vivo.
Eu tinha lido a documentação. Tinha feito o tutorial do site oficial. Tinha assistido dois cursos diferentes. Conhecia os conceitos: Pod, Deployment, Service, Ingress. Sabia o que cada um fazia, na teoria.
E quando tentei fazer o primeiro deploy de verdade, nada funcionou.
O primeiro problema foi o ImagePullBackOff. Minha imagem Docker estava num registry privado. Kubernetes precisava de credenciais para fazer o pull. Eu não sabia que precisava criar um Secret do tipo docker-registry e referenciar ele no Pod. A mensagem de erro era genérica o suficiente para não deixar isso óbvio. Passei meio dia nisso.
Resolvi. O pod subiu. Durou trinta segundos e morreu. Status: CrashLoopBackOff.
CrashLoopBackOff é o estado mais desgastante do Kubernetes. Significa que o container está iniciando, falhando, sendo reiniciado, falhando de novo, e assim por diante com intervalos exponenciais. Para debugar, você precisa ver os logs do container antes de ele morrer — o que é difícil quando ele morre rápido.
O comando que salvou minha sanidade: kubectl logs pod/<nome> --previous. Pega os logs da execução anterior, não da atual. Foi ali que vi o erro real: minha aplicação estava tentando conectar num banco de dados e não encontrava a variável de ambiente com a connection string.
Eu tinha esquecido de criar o ConfigMap e referenciar ele no Deployment.
Metade do segundo dia foi entendendo como variáveis de ambiente funcionam no Kubernetes. Você pode definir inline no yaml, via ConfigMap para valores não-sensíveis, ou via Secret para valores sensíveis. Parece simples. Mas quando você vem de Docker Compose, onde tudo é um arquivo .env, a quantidade de recursos separados para fazer a mesma coisa parece excessiva.
É excessiva, no sentido de que Docker Compose resolve o mesmo problema com menos cerimônia. Kubernetes resolve isso de forma mais robusta, auditável, e escalável — mas cobra um preço em complexidade.
Com as variáveis no lugar, a aplicação subiu. E eu não conseguia acessá-la de fora do cluster.
O terceiro problema foi o Ingress. Kubernetes tem Service para expor pods dentro do cluster, e Ingress para expor para fora. Mas Ingress precisa de um Ingress Controller instalado no cluster — e o cluster de teste que eu estava usando não tinha.
Resolvi usando kubectl port-forward para testar, e depois instalei o nginx-ingress-controller. O que levou mais uma hora porque a versão do helm chart que eu tentei usar tinha um breaking change na configuração.
No final do terceiro dia, a aplicação estava rodando, acessível, com variáveis de ambiente corretas e imagem fazendo pull sem problemas. Levou setenta e duas horas para chegar num estado que Docker Compose teria resolvido em vinte minutos.
Isso não é argumento contra Kubernetes. É contexto sobre a curva de aprendizado.
A diferença é que com Docker Compose em produção, você tem um único ponto de falha: o servidor. Com Kubernetes, você tem redundância, autoscaling, rolling deployments, e um conjunto de primitivas que escalam com a complexidade do problema.
O custo de aprendizado é real. E vale a pena — mas precisava entrar com olhos abertos sobre o que estava pagando.
O que eu faria diferente: teria começado com um cluster gerenciado (EKS, GKE, ou AKS) em vez de tentar entender cluster management e Kubernetes ao mesmo tempo. Teria também isolado os problemas: primeiro faz a imagem funcionar localmente com Docker, depois sobe no Kubernetes. Não tenta resolver tudo junto.
Essa semana: se você está aprendendo Kubernetes, usa kubectl describe pod/<nome> e kubectl logs pod/<nome> --previous como primeiro reflexo quando algo dá errado. Noventa por cento dos problemas de iniciante estão ali.