Kubernetes básico: Pod, Deployment e Service
1. Visão geral
Kubernetes tem dezenas de tipos de recursos, mas 80% do trabalho diário gira em torno de três conceitos: Pod, Deployment, Service. Este artigo o ajuda a entender a natureza de cada recurso, como eles se conectam e como escrever um conjunto de manifestos YAML para implantar uma aplicação que realmente funcione no cluster.
Depois de ler, você será capaz de fazer deploy de uma aplicação Spring Boot no Kubernetes, escalá-la em múltiplas réplicas e expô-la para fora através de um Service - tudo apenas usando kubectl e alguns arquivos YAML.
Nota: Este artigo assume que você já tem um cluster (Minikube, Kind, ou na nuvem) e
kubectljá está apontando para o contexto correto.
2. Pod - A menor unidade de implantação
2.1. O que é um Pod
Um Pod é um grupo de um ou mais containers que compartilham o namespace de rede (mesmo IP, mesmo espaço de portas) e volumes. Na prática, a maioria dos Pods contém apenas um container de aplicação.
apiVersion: v1
kind: Pod
metadata:
name: order-service-pod
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Explicação:
metadata.labelsanexa o rótuloapp: order-service- é assim que o Kubernetes “identifica” Pods; Service e Deployment usam este rótulo para selecionar os objetos associados.resources.requestssão os recursos mínimos que o scheduler precisa para colocar o Pod em um nó;limitsé o limite máximo - exceder isso causará throttle (CPU) ou encerramento forçado (memória - OOMKilled).containerPort: 8080é apenas uma declaração informativa, não abre automaticamente a porta para fora.
Aplicar e verificar:
kubectl apply -f order-service-pod.yaml
kubectl get pods
NAME READY STATUS RESTARTS AGE
order-service-pod 1/1 Running 0 5s
2.2. Por que não criar Pods diretamente
Pods criados “nus” como acima têm um grande problema: se o Nó que contém o Pod morrer ou o Pod falhar, ninguém o recria automaticamente. Pod não tem mecanismo de self-healing ou scaling.
Nota: Em ambientes de produção, quase nunca crie Pods diretamente. Sempre use Deployment (ou StatefulSet, Job) para gerenciar Pods.
3. Deployment - Gerenciamento do ciclo de vida do Pod
3.1. Declarando um Deployment
Deployment cria e gerencia um conjunto de Pods através de ReplicaSet, garantindo que sempre há o número correto de réplicas rodando, e suporta rolling update sem downtime.
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
Explicação:
replicas: 3instrui o Deployment a manter sempre 3 Pods rodando simultaneamente - se um Pod morrer, o Deployment cria automaticamente um novo para substituí-lo.selector.matchLabelsdeve corresponder atemplate.metadata.labels. Esta é a ligação obrigatória entre o Deployment e os Pods que ele gerencia.readinessProbedetermina se o Pod deve receber tráfego (usado pelo Service);livenessProbedetermina se o Pod precisa ser reiniciado. Confundir essas duas probes é um erro muito comum para quem está começando com Kubernetes.
Aplicar e observar:
kubectl apply -f order-service-deployment.yaml
kubectl get deployments
kubectl get pods -l app=order-service
NAME READY UP-TO-DATE AVAILABLE AGE
order-service 3/3 3 3 12s
NAME READY STATUS RESTARTS AGE
order-service-7d4f9c8b6d-2kx9p 1/1 Running 0 12s
order-service-7d4f9c8b6d-7h2mn 1/1 Running 0 12s
order-service-7d4f9c8b6d-xq1lw 1/1 Running 0 12s
3.2. Scaling e rolling update
Escale aumentando/diminuindo o número de réplicas sem precisar editar o YAML:
kubectl scale deployment order-service --replicas=5
Rolling update quando muda a imagem - o Deployment substitui automaticamente Pods antigos por novos seguindo uma estratégia de atualização gradual, sem downtime:
kubectl set image deployment/order-service order-service=nonladev/order-service:1.1
kubectl rollout status deployment/order-service
Waiting for deployment "order-service" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "order-service" successfully rolled out
Se a nova versão tem um bug, faça rollback para a versão anterior imediatamente:
kubectl rollout undo deployment/order-service
3.3. Configurando a estratégia de rolling update
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
maxUnavailable: 1 permite que no máximo 1 Pod fique “indisponível” durante a atualização; maxSurge: 1 permite criar no máximo 1 Pod adicional além do número de réplicas declaradas. Com replicas: 3, o cluster terá entre 2-4 Pods durante a transição, mas nunca menos de 2.
4. Service - Expor Pods de forma estável
4.1. Por que precisamos de um Service
Pods têm seu próprio IP, mas este IP muda toda vez que o Pod é recriado (crash, rolling update, scaling). Service fornece um endereço estável (ClusterIP + nome DNS) na frente do grupo de Pods, balanceando automaticamente o tráfego com base no seletor de rótulo - não importa quantas vezes os Pods abaixo mudem.
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
Explicação:
selector.app: order-servicecorresponde ao rótulo nos Pods (colocado pelo Deployment emtemplate.metadata.labels) - o Service encontra e monitora automaticamente esses Pods através de um objeto intermediário chamado Endpoints.port: 80é a porta que o Service escuta dentro do cluster;targetPort: 8080é a porta que o container realmente expõe. Esses dois números não precisam ser idênticos.type: ClusterIP(padrão) é acessível apenas de dentro do cluster - adequado para serviços internos entre microsserviços.
Verificar Service e Endpoints:
kubectl apply -f order-service-service.yaml
kubectl get svc order-service
kubectl get endpoints order-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
order-service ClusterIP 10.96.142.201 <none> 80/TCP 4s
NAME ENDPOINTS AGE
order-service 10.244.1.5:8080,10.244.1.6:8080,+1 more 4s
4.2. Os tipos de Service
| Type | Escopo de acesso | Quando usar |
|---|---|---|
ClusterIP |
Apenas dentro do cluster | Comunicação entre microsserviços internos |
NodePort |
Abre uma porta fixa (30000-32767) em todos os Nós | Teste rápido, ambiente de desenvolvimento/on-premise |
LoadBalancer |
Fornece um IP público através do provedor de nuvem | Expor o serviço para a Internet na nuvem |
Exemplo de exposição para teste rápido no Minikube:
apiVersion: v1
kind: Service
metadata:
name: order-service-external
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
nodePort: 30080
type: NodePort
minikube service order-service-external --url
Nota: Usar
NodePortem produção é um anti-pattern - faixa de porta limitada, sem terminação TLS ou roteamento baseado em saúde como Ingress. Para produção na nuvem, priorizeLoadBalancerou Ingress Controller.
5. Combinando os três em uma aplicação real
Todo o pipeline: cliente chama o Service → o Service balanceia a carga para os Pods gerenciados pelo Deployment.
Cliente
│
▼
Service (order-service, ClusterIP 10.96.142.201:80)
│ (seletor de rótulo: app=order-service)
▼
┌─────────────┬─────────────┬─────────────┐
│ Pod #1 │ Pod #2 │ Pod #3 │
│ :8080 │ :8080 │ :8080 │
└─────────────┴─────────────┴─────────────┘
▲ gerenciado por
Deployment (order-service, replicas: 3)
Para facilitar a implantação de uma vez, você pode combinar tanto Deployment quanto Service em um único arquivo, separados por ---:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
kubectl apply -f order-service-all.yaml
6. Escrever teste para o endpoint de readiness antes do deploy
Antes de a probe do Kubernetes confiar em /actuator/health/readiness, você deve garantir que este endpoint retorne o estado correto no código do Spring Boot.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management.endpoint.health.probes.enabled=true
management.health.readiness-state.enabled=true
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderServiceHealthTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void readinessProbe_shouldReturnUp() {
ResponseEntity<String> response =
restTemplate.getForEntity("/actuator/health/readiness", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("\"status\":\"UP\"");
}
}
Este teste chama TestRestTemplate no endpoint de readiness real, confirmando HTTP 200 e que o body contém UP. Este é exatamente o endpoint que readinessProbe no Deployment chamará periodicamente - se o teste falhar aqui, o Pod também nunca ficará “Ready” no cluster.
7. Erros comuns
- Seletor não corresponde ao rótulo: Service ou Deployment não encontra nenhum Pod (Endpoints vazio) porque
selectorelabelsforam escritos incorretamente ou diferem. Sempre usekubectl get endpoints <svc-name>para confirmar. - Falta de readinessProbe: Service ainda roteia tráfego para Pods que não completaram a inicialização da aplicação, causando erros 502/503 logo após o deploy.
- Resource requests/limits ausentes: O Pod pode ser colocado incorretamente no nó pelo scheduler, ou ser OOMKilled inesperadamente quando o tráfego aumenta.
- Usar Pod simples em produção: sem self-healing, perder um Pod é perder permanentemente, precisa ser recriado manualmente.
- Tag de imagem
latest: rolling update não percebe mudanças, Kubernetes pensa que a imagem não mudou e não faz pull novamente. Sempre use uma tag de versão específica.
8. Conclusão
Pod é a unidade de execução de container mais pequena, Deployment gerencia o ciclo de vida e scaling do conjunto de Pods, enquanto Service fornece um endereço estável para acessá-los mesmo que os Pods abaixo mudem continuamente. Dominar esses três pilares é a base para você avançar para Ingress, ConfigMap/Secret, ou Helm charts depois. O próximo passo deve ser: fazer deploy de uma aplicação real em Spring Boot, observar o rolling update, e tentar matar um Pod manualmente para ver como o Deployment se recupera.