Padrões Kubernetes
Padrões do Kubernetes de nível de produção para implantar, gerenciar e depurar cargas de trabalho de forma confiável.
Quando Ativar
- Escrevendo manifestos do Kubernetes (Deployments, Services, Ingress, Jobs)
- Configurando solicitações/limites de recursos, sondas de viabilidade/prontidão
- Configurando RBAC, namespaces ou ServiceAccounts
- Gerenciando configuração e secrets no K8s
- Depurando CrashLoopBackOff, OOMKilled, pods pendentes ou erros de pull de imagem
- Configurando HPA (Horizontal Pod Autoscaler) ou PodDisruptionBudgets
- Revisando YAML do K8s para segurança ou correção
Quando Usar
O mesmo que Quando Ativar acima. Este alias atende às convenções de formato de skill do repositório. Use esta skill sempre que estiver escrevendo, revisando ou depurando workloads e YAML do Kubernetes.
Como Funciona
Esta skill fornece padrões YAML copiáveis e prontos para produção e comandos de depuração kubectl organizados por tarefa:
- Modelo de Deployment — Um
Deploymentde produção totalmente configurado com contexto de segurança, estratégia de atualização contínua, todos os três tipos de sonda, limites de recursos e injeção de ambiente do ConfigMap/Secret. - Sondas — Tabela de decisão para inicialização vs. viabilidade vs. prontidão, com o cálculo correto de
failureThreshold × periodSeconds. - Services e Ingress — Padrões de ClusterIP, LoadBalancer e Ingress com TLS e anotações do cert-manager.
- ConfigMaps e Secrets — Orientação sobre
envFrom, montagem de arquivo e secrets externos. - Gerenciamento de recursos — Regras práticas de solicitações vs. limites por tipo de workload (web API, JVM, worker, sidecar).
- RBAC — Cadeia de privilégios mínimos: ServiceAccount → Role → RoleBinding.
- HPA e PDB — Configurações de autoescalonamento e segurança para drenagem de nós.
- Jobs e CronJobs — Padrões de cargas de trabalho únicas e agendadas com
restartPolicycorreta. - Folha de dicas kubectl — Comandos para logs, exec, rollback, port-forward, dry-run e diagnóstico de erros comuns.
- Antipadrões e lista de verificação — O que NÃO fazer e uma lista de verificação de segurança/confiabilidade/observabilidade.
Exemplos
Veja as seções abaixo para exemplos completos e executáveis. Referências rápidas:
| Tarefa | Ir para |
|---|---|
| YAML completo de Deployment de produção | Padrões Principais de Carga de Trabalho |
| Configuração de sonda | Sondas |
| Configuração RBAC com privilégios mínimos | RBAC |
| Depurar um CrashLoopBackOff | Folha de Dicas de Depuração kubectl |
| Autoescalonamento | HPA |
Padrões Principais de Carga de Trabalho
Deployment — Modelo de Produção
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-namespace
labels:
app: my-app
version: "1.0.0"
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Permitir 1 pod extra durante a atualização
maxUnavailable: 0 # Nunca reduzir abaixo da contagem desejada
template:
metadata:
labels:
app: my-app
version: "1.0.0"
spec:
# Contexto de segurança no nível do pod
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
# Desligamento gracioso
terminationGracePeriodSeconds: 30
containers:
- name: my-app
image: ghcr.io/org/my-app:1.0.0 # Nunca use :latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
# Solicitações E limites de recursos são ambos necessários
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# Contexto de segurança do contêiner
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Sondas (veja a seção Sondas abaixo)
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 0
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2
# Ambiente do ConfigMap e Secret
envFrom:
- configMapRef:
name: my-app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secrets
key: db-password
# Diretório tmp gravável quando readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Sondas — Viabilidade, Prontidão, Inicialização
Entender quando usar cada sonda é crítico:
| Sonda | Ação em Caso de Falha | Uso para |
|---|---|---|
startupProbe | Mata o container se for lento para iniciar | Apps de inicialização lenta (JVM, Python) |
livenessProbe | Reinicia o container | Detecção de deadlock / processo travado |
readinessProbe | Remove dos endpoints do Service | Indisponibilidade temporária (reconexão DB) |
# Padrão correto: startupProbe cobre inicialização lenta,
# então liveness/readiness assumem o controle
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30 # 30 * 5s = 150s de tempo máximo de inicialização
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 30
failureThreshold: 3 # 3 * 30s = 90s antes de reiniciar
readinessProbe:
httpGet:
path: /ready # Endpoint separado: verifica DB, cache, etc.
port: 8080
periodSeconds: 10
failureThreshold: 2
# ERRADO: initialDelaySeconds sem startupProbe
# Se o app leva 60s para iniciar, defina uma startupProbe
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60 # RUIM: Espera arbitrária, condição de corrida
Services e Ingress
Tipos de Service
# ClusterIP (padrão) — apenas interno
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-namespace
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
# LoadBalancer — tráfego externo (provedores de nuvem)
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
Ingress com TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
ConfigMaps e Secrets
ConfigMap — Configuração não sensível
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
namespace: my-namespace
data:
LOG_LEVEL: "info"
APP_ENV: "production"
MAX_CONNECTIONS: "100"
# Montar como arquivo para configuração complexa
app.yaml: |
server:
port: 8080
timeout: 30s
# Montar ConfigMap como arquivo
volumes:
- name: config
configMap:
name: my-app-config
items:
- key: app.yaml
path: app.yaml
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
Secrets — Dados sensíveis
# Criar secret a partir de literal (CLI, depois armazenar em Vault/SOPS)
kubectl create secret generic my-app-secrets \
--from-literal=db-password='s3cr3t' \
--namespace=my-namespace \
--dry-run=client -o yaml | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: my-namespace
type: Opaque
# Os valores são codificados em base64 (NÃO criptografados — use Sealed Secrets ou ESO para criptografia real)
data:
db-password: czNjcjN0 # base64 de 's3cr3t'
Importante: Secrets brutos do Kubernetes são apenas codificados em base64, não criptografados em repouso, a menos que seu cluster tenha criptografia configurada. Use Sealed Secrets ou External Secrets Operator para produção.
Solicitações e Limites de Recursos
resources:
requests: # O agendador usa isso para posicionar o pod
cpu: "100m" # 100 millicores = 0,1 CPU
memory: "128Mi"
limits: # O container é morto/acelerado acima disso
cpu: "500m"
memory: "256Mi"
Regras práticas:
| Tipo de Carga de Trabalho | Solicitação de CPU | Solicitação de Memória | Observações |
|---|---|---|---|
| Web API | 100–250m | 128–256Mi | Definir limites 2-4x as solicitações |
| Worker/consumidor | 250–500m | 256–512Mi | Limite de memória = solicitação para previsibilidade |
| App JVM | 500m–1 | 512Mi–2Gi | Permitir folga acima de -Xmx para sobrecarga da JVM |
| Sidecar | 10–50m | 32–64Mi | Manter o mínimo |
# ERRADO: Sem solicitações ou limites — agendamento imprevisível, remoções OOM
containers:
- name: app
image: myapp:latest
# Faltando resources: {} — isso é perigoso em produção
# ERRADO: Limites sem solicitações — solicitações padrão são os limites, super-reserva capacidade
resources:
limits:
cpu: "2"
memory: "1Gi"
# faltando requests — assumirá os valores dos limites
RBAC — Roles e ServiceAccounts
Princípio do Menor Privilégio
Dois padrões dependendo se o app chama a API do Kubernetes:
Padrão A — App NÃO precisa da API do Kubernetes (a maioria dos apps)
Desabilitar a montagem automática de token no ServiceAccount. Role/RoleBinding não são necessários.
# ServiceAccount com token desabilitado — padrão mais seguro
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: false # Nenhum token da API K8s é injetado nos pods
# Referência no Deployment — sem token, sem acesso à API
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false # Cinto e suspensórios: também definido no nível do pod
Padrão B — App PRECISA da API do Kubernetes (operadores, controladores, observadores de configuração)
Habilitar o token e conceder apenas as permissões realmente necessárias.
# 1. ServiceAccount — habilitar token para esta SA
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: true # Token necessário: app chama a API K8s
# 2. Role — conceder apenas o que o app precisa (escopo do namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"] # Somente leitura, recurso específico
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["my-app-secrets"] # Restringir a secret específico por nome
verbs: ["get"]
# 3. Vincular Role ao ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: my-namespace
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: my-app-role
# 4. Referenciar SA no Deployment
spec:
template:
spec:
serviceAccountName: my-app-sa
# automountServiceAccountToken assume true da SA — token é injetado
Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-namespace
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2 # Sempre pelo menos 2 para HA
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Escalar quando CPU média > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
HPA requer que
resources.requestsseja definido em todos os contêineres — ele calcula a utilização comocurrent / request.
PodDisruptionBudget (PDB)
Evitar que muitos pods caiam durante drenagem de nós ou atualizações contínuas:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: my-namespace
spec:
minAvailable: 2 # OU use maxUnavailable: 1
selector:
matchLabels:
app: my-app
Namespaces e Multitenência
# Criar namespace com cotas de recursos
kubectl create namespace my-namespace
# Aplicar ResourceQuota para limitar o consumo do namespace
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: my-namespace-quota
namespace: my-namespace
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "20"
EOF
Jobs e CronJobs
# Job único (migração de DB, processamento de dados)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: my-namespace
spec:
backoffLimit: 3 # Tentar novamente até 3 vezes em caso de falha
ttlSecondsAfterFinished: 3600 # Auto-excluir após 1h
template:
spec:
restartPolicy: OnFailure # Never para Jobs (não Always)
containers:
- name: migrate
image: ghcr.io/org/my-app:1.0.0
command: ["python", "manage.py", "migrate"]
resources:
…
[truncated for translation]