Deployment, Service, ConfigMap e Secret
Objetivos desta aula
- Escrever manifests corretos
- Injetar configuração e segredo
- Expor a aplicação internamente
Deployment gerencia ReplicaSets, que gerenciam pods, e é o que permite rollout gradual e rollback. Service dá um nome estável e balanceamento para um conjunto de pods selecionado por labels: ClusterIP para uso interno, NodePort para acesso direto em laboratório, LoadBalancer para provisionar balanceador na nuvem.
Configuração vem de ConfigMap; dado sensível, de Secret. Importante: Secret padrão é apenas base64, não criptografia — o que protege é RBAC, criptografia em repouso no etcd e não versionar o valor. Para GitOps, use Sealed Secrets, SOPS ou External Secrets Operator.
Labels e selectors são a cola de tudo. Selector do Service que não casa com as labels do pod produz o clássico 'Service sem endpoints', em que a aplicação está de pé mas nada chega nela.
1. Pod: a menor unidade
Um Pod é um ou mais contêineres que compartilham rede (mesmo IP) e volumes. Pods são descartáveis: nunca crie Pods soltos em produção, crie um controller que os recria.
2. Deployment e ReplicaSet
O Deployment gerencia ReplicaSets, que gerenciam Pods. Ao trocar a imagem, o Deployment cria um novo ReplicaSet e faz rolling update: sobe Pods novos e derruba antigos aos poucos, controlado por maxSurge e maxUnavailable.
3. Labels e selectors: a cola de tudo
Deployment encontra seus Pods por labels; Service encontra para onde mandar tráfego por labels. Se o selector não bate com as labels do template, nada funciona — é a primeira coisa a conferir.
4. Service: endereço estável
- ClusterIP: IP interno e nome DNS (
api.cloudshop.svc.cluster.local) - NodePort: porta em todos os nós (uso raro)
- LoadBalancer: pede um balanceador à nuvem
O Service mantém uma lista de endpoints com os IPs dos Pods prontos.
5. ConfigMap e Secret
Configuração fica fora da imagem: ConfigMap para dados comuns, Secret para sensíveis. Atenção: Secret é só base64, não criptografia — habilite criptografia do etcd e restrinja com RBAC. Injete como variáveis (envFrom) ou arquivos (volume).
6. Rollout na prática
kubectl rollout status acompanha, rollout history mostra versões e rollout undo volta. Mudar só um ConfigMap não reinicia Pods; use um hash da config como anotação (Helm faz isso fácil).
Na prática
Manifests da API do CloudShop
yaml
apiVersion: v1
kind: ConfigMap
metadata: { name: cloudshop-api-config }
data:
NODE_ENV: production
DATABASE_HOST: cloudshop-db
DATABASE_PORT: "5432"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloudshop-api
labels: { app: cloudshop, component: api }
spec:
replicas: 2
revisionHistoryLimit: 5
strategy:
type: RollingUpdate
rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
selector:
matchLabels: { app: cloudshop, component: api }
template:
metadata:
labels: { app: cloudshop, component: api }
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
containers:
- name: api
image: ghcr.io/sua-org/cloudshop/api:v1.2.0
ports: [{ containerPort: 3000, name: http }]
envFrom:
- configMapRef: { name: cloudshop-api-config }
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef: { name: cloudshop-db, key: password }
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 256Mi }
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: { drop: ["ALL"] }
---
apiVersion: v1
kind: Service
metadata: { name: cloudshop-api }
spec:
type: ClusterIP
selector: { app: cloudshop, component: api }
ports: [{ port: 80, targetPort: http }]Nota de segurança: Nunca versione Secret com valor em base64 no Git. Use External Secrets ou SOPS com chave gerenciada.
Aplicar e depurar
bash
kubectl apply -f k8s/
kubectl get deploy,rs,pod,svc
kubectl describe deploy cloudshop-api | tail -20
kubectl get endpoints cloudshop-api # vazio = selector nao casa
kubectl logs deploy/cloudshop-api --tail=50
kubectl port-forward svc/cloudshop-api 8080:80
kubectl run tmp --rm -it --image=curlimages/curl -- sh -c 'curl -s cloudshop-api/health'API do CloudShop: Deployment + Service + ConfigMap
yaml
apiVersion: v1
kind: ConfigMap
metadata: { name: api-config, namespace: cloudshop }
data:
LOG_LEVEL: info
DB_HOST: postgres.cloudshop.svc.cluster.local
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: api, namespace: cloudshop }
spec:
replicas: 3
strategy:
rollingUpdate: { maxSurge: 1, maxUnavailable: 0 } # nunca fica abaixo de 3
selector: { matchLabels: { app: api } }
template:
metadata: { labels: { app: api } } # precisa bater com o selector
spec:
containers:
- name: api
image: ghcr.io/cloudshop/api:1.4.2 # tag fixa, nunca latest
ports: [{ containerPort: 3000 }]
envFrom:
- configMapRef: { name: api-config }
- secretRef: { name: api-db } # senha do banco
---
apiVersion: v1
kind: Service
metadata: { name: api, namespace: cloudshop }
spec:
selector: { app: api }
ports: [{ port: 80, targetPort: 3000 }]Atualizar e voltar versão
bash
kubectl -n cloudshop set image deploy/api api=ghcr.io/cloudshop/api:1.5.0
kubectl -n cloudshop rollout status deploy/api
kubectl -n cloudshop get endpoints api # IPs dos Pods prontos
kubectl -n cloudshop rollout undo deploy/api # volta para a versão anteriorPor que isso importa
Estes quatro objetos cobrem 80% do trabalho diário com Kubernetes.
Erro comum
Selector do Service divergente das labels do pod, gerando Service sem endpoints.
Dica de produção
maxUnavailable: 0 garante deploy sem janela de indisponibilidade quando há réplicas suficientes.
Alerta de segurança
runAsNonRoot, readOnlyRootFilesystem e drop de capabilities devem ser o padrão, não a exceção.
Pergunta de entrevista
Service existe, pods rodando, mas nada responde. O que você verifica?
Glossário
- selector
- Regra de labels que define quais pods pertencem a um Service ou controller.
- envFrom
- Forma de injetar todas as chaves de um ConfigMap como variáveis de ambiente.
- ReplicaSet
- Garante um número fixo de Pods iguais; é gerenciado pelo Deployment.
- Rolling update
- Troca gradual de Pods antigos por novos sem indisponibilidade.
- Endpoints
- Lista de IPs de Pods prontos para os quais o Service envia tráfego.
Conexão com o CloudShop
Traduzir os serviços do Compose em Deployments e Services do CloudShop.
Quiz da aula
1. Service sem endpoints normalmente indica:
2. O Service não entrega tráfego e 'kubectl get endpoints' está vazio. Causa mais provável?
3. Um Secret do Kubernetes, por padrão, é:
Minhas anotações
Salvo automaticamente neste navegador.