Como Fazer Deploy de uma Aplicação no Kubernetes: Guia Prático para Desenvolvedores
Aprenda a fazer o deploy de uma aplicação no Kubernetes de forma prática. Entenda a estrutura de manifestos YAML, configure health checks, exponha sua API e domine comandos essenciais do kubectl.
Se você já domina o ambiente de desenvolvimento local usando Docker, consegue rodar seus containers sem problemas e agora precisa dar o próximo passo rumo à produção, o Kubernetes é o caminho natural. No entanto, a transição do ambiente local para um cluster de orquestração costuma ser acompanhada de uma sopa de letrinhas e conceitos que parecem mais complexos do que realmente são.
Para o dia a dia de quem desenvolve software, você não precisa ser um especialista em infraestrutura ou dominar toda a arquitetura interna do control plane para colocar sua aplicação no ar de forma resiliente. Entender os conceitos de containers e orquestração e saber como estruturar seus arquivos de configuração é o suficiente para garantir que sua API rode com alta disponibilidade.
Neste guia prático, vamos desmistificar o processo de deploy no Kubernetes, analisando desde a diferença dos recursos básicos até a escrita de manifestos YAML e a execução de comandos essenciais de monitoramento e rollback.
Pod, Deployment e StatefulSet: Qual é a diferença na prática?
Antes de escrever qualquer linha de configuração, é fundamental entender os blocos de construção que o Kubernetes utiliza para gerenciar suas aplicações. Os três recursos mais comuns para lidar com workloads são:
- Pod: É a menor unidade executável no Kubernetes. Um Pod encapsula um ou mais containers (geralmente apenas um), compartilhando armazenamento e recursos de rede. Na prática, você nunca deve criar um Pod isolado diretamente em produção. Eles são efêmeros: se o nó onde o Pod está rodando falhar, o Pod morre e não é recriado automaticamente.
- Deployment: É o recurso ideal para aplicações stateless (que não guardam estado local, como APIs HTTP, microsserviços e frontends). O Kubernetes Deployment gerencia a criação, atualização e escalabilidade dos Pods de forma declarativa. Se um Pod cair, o Deployment garante que outro seja criado instantaneamente para substituí-lo.
- StatefulSet: Utilizado para aplicações stateful (que precisam manter um estado persistente e identidade única, como bancos de dados PostgreSQL, Redis ou sistemas de mensageria). Diferente do Deployment, onde os Pods são idênticos e intercambiáveis, no StatefulSet cada Pod possui um identificador persistente e um volume de disco vinculado que não se perde quando o Pod é reiniciado.
Para a maioria das aplicações web e APIs que desenvolvemos, o Deployment é a escolha padrão.
Anatomia de um Manifesto YAML: Estruturando o seu Deployment
No Kubernetes, tudo é definido de forma declarativa através de arquivos YAML. Em vez de rodar comandos para criar recursos, você descreve o estado desejado da sua aplicação e o Kubernetes se encarrega de convergir o estado atual para o estado descrito.
Antes de enviar a configuração para o cluster, o primeiro passo é empacotar sua aplicação com Docker e enviar a imagem para um registro público ou privado (como Docker Hub ou AWS ECR).
Abaixo, analisamos a estrutura básica de um manifesto de Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: minha-api
spec:
replicas: 3
selector:
matchLabels:
app: minha-api
template:
metadata:
labels:
app: minha-api
spec:
containers:
- name: api-container
image: meu-usuario/minha-api:v1.0.0
ports:
- containerPort: 8080
Entendendo os campos essenciais:
- apiVersion e kind: Definem qual recurso estamos criando e qual versão da API do Kubernetes estamos utilizando.
- metadata: Identifica o recurso no cluster, definindo seu nome (
api-deployment) e etiquetas (labels). - spec.replicas: O número de instâncias idênticas (Pods) que queremos rodando simultaneamente. Se definirmos
3, o Kubernetes garantirá que sempre existam três Pods ativos. - spec.selector: Diz ao Deployment quais Pods ele deve gerenciar. Ele busca por Pods que possuam a label correspondente (
app: minha-api). - spec.template: É o molde do Pod. Tudo o que estiver abaixo de
template.specdescreve como o container deve ser criado (nome, imagem do container, portas expostas, variáveis de ambiente, etc.).
Garantindo a Estabilidade: Configurando Liveness e Readiness Probes
Um dos erros mais comuns ao realizar um deploy no Kubernetes é assumir que o container está pronto para receber tráfego só porque o processo principal iniciou. Para evitar que requisições de usuários caiam em um container que ainda está inicializando ou que travou internamente, utilizamos os Health Checks através de probes.
Existem dois tipos principais de validações de saúde:
- Readiness Probe (Verificação de Prontidão): Determina se o container está pronto para receber tráfego de rede. Se a validação falhar, o Kubernetes temporariamente remove o Pod do balanceamento de carga, mas não reinicia o container.
- Liveness Probe (Verificação de Sobrevivência): Determina se o container está rodando corretamente. Se a validação falhar (por exemplo, a aplicação travou em um deadlock), o Kubernetes mata o container e inicia um novo para tentar recuperar o serviço.
Veja como configurar essas validações simulando uma rota de health check (/healthz) da sua aplicação:
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
- initialDelaySeconds: Tempo de espera antes de realizar a primeira verificação (útil para dar tempo da aplicação subir).
- periodSeconds: Intervalo de tempo entre cada verificação subsequente.
Expondo a Aplicação: Services (ClusterIP, NodePort, LoadBalancer) e Ingress
Por padrão, os Pods recebem IPs internos que mudam constantemente a cada reinicialização. Para expor sua aplicação de forma estável, você precisa de um Kubernetes Service.
Existem três tipos principais de Services:
- ClusterIP (Padrão): Expõe o serviço em um IP interno do cluster. Ideal para comunicação interna entre microsserviços (ex: sua API conversando com um banco de dados).
- NodePort: Expõe o serviço em uma porta estática em cada nó do cluster. Permite acesso externo básico, mas não é recomendado para produção devido à limitação de portas (faixa 30000-32767).
- LoadBalancer: Cria um balanceador de carga real no provedor de nuvem (AWS, GCP, Azure) que direciona o tráfego externo diretamente para o seu Service.
Para cenários complexos com múltiplos domínios e rotas HTTP, o ideal é utilizar um Ingress Controller (como o NGINX Ingress), que atua como um proxy reverso unificado na borda do cluster, distribuindo o tráfego externo para os Services internos do tipo ClusterIP.
Abaixo, apresentamos um exemplo de manifesto YAML unificado contendo o Deployment da API e um Service do tipo ClusterIP:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: minha-api
spec:
replicas: 2
selector:
matchLabels:
app: minha-api
template:
metadata:
labels:
app: minha-api
spec:
containers:
- name: api-container
image: meu-usuario/minha-api:v1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
type: ClusterIP
selector:
app: minha-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
Gerenciando o Deploy com kubectl: Comandos Essenciais para o Dia a Dia
Com os manifestos YAML prontos, você utilizará a ferramenta de linha de comando kubectl para interagir com o cluster. Aqui está o guia de sobrevivência com os comandos mais utilizados:
1. Aplicar configurações
Para criar ou atualizar qualquer recurso a partir de um arquivo YAML:
kubectl apply -f deployment.yaml
2. Monitorar o status dos recursos
Para listar seus Pods e verificar se estão rodando corretamente:
kubectl get pods
Para listar os Services ativos:
kubectl get svc
3. Debugar problemas
Se um Pod estiver com o status CrashLoopBackOff ou não iniciar, use o describe para ver o histórico de eventos do Kubernetes:
kubectl describe pod <nome-do-pod>
Para visualizar a saída de console (logs) da sua aplicação:
kubectl logs <nome-do-pod> --tail=100 -f
4. Executar comandos dentro do container
Se precisar inspecionar o ambiente interno do container (como testar uma conexão de rede):
kubectl exec -it <nome-do-pod> -- sh
Atualizações Sem Downtime: RollingUpdate e Como Fazer Rollback Rápido
Por padrão, o Kubernetes utiliza a estratégia de atualização chamada RollingUpdate. Quando você altera a versão da imagem no seu arquivo YAML e executa um kubectl apply, o Kubernetes não derruba todos os Pods antigos de uma vez.
Em vez disso, ele cria um novo Pod com a nova versão, aguarda que ele passe no teste do readinessProbe e, somente após a confirmação de que o novo Pod está saudável, ele remove um Pod antigo. Esse processo se repete gradualmente até que todos os Pods estejam atualizados, garantindo zero downtime durante o deploy.
Se você deseja automatizar esse fluxo de ponta a ponta, o ideal é implementar pipelines de CI/CD com Docker para que cada commit na branch principal gere uma nova imagem e atualize o manifesto no cluster.
O que fazer se o deploy falhar?
Se você subiu uma versão com bug ou erro de inicialização, o Kubernetes interromperá o processo de RollingUpdate ao perceber que os novos Pods estão falhando nas validações de saúde. Para reverter o deploy imediatamente para a versão anterior estável, execute:
kubectl rollout undo deployment/api-deployment
Esse comando desfaz a última alteração e retorna o cluster ao estado de funcionamento anterior em segundos, minimizando o impacto para os usuários finais.
Referências
- Documentação Oficial do Kubernetes - Deployments
- Documentação Oficial do Kubernetes - Services
- Documentação Oficial do Kubernetes - Referência do kubectl
Perguntas Frequentes (FAQ)
Qual a diferença prática entre ClusterIP, NodePort e LoadBalancer?
O ClusterIP expõe o serviço apenas internamente no cluster. O NodePort expõe o serviço em uma porta estática em cada nó do cluster, permitindo acesso externo básico. O LoadBalancer cria um balanceador de carga real no provedor de nuvem para direcionar o tráfego externo ao serviço.
O que acontece se o livenessProbe falhar?
Se o livenessProbe falhar, o Kubernetes entende que o container está travado ou em estado irrecuperável e reinicia o container automaticamente para tentar restabelecer a saúde da aplicação.
Como posso testar meus manifestos do Kubernetes localmente?
Você pode utilizar ferramentas leves como Minikube, Kind (Kubernetes in Docker) ou habilitar o Kubernetes integrado no Docker Desktop para rodar um cluster local e aplicar seus arquivos YAML de teste.
Sobre Marcos Costa
Desenvolvedor backend com foco em arquitetura de software, automação e produtos digitais.
Ver mais artigos