MÓDULO 12 · CONCEITO 03 DE 12

Kubernetes em Produção — além do kubectl apply

Resources e limites, HPA/VPA, PodDisruptionBudget, probes com semântica correta, NetworkPolicies, RBAC de cluster, NodeAffinity. Por que Kubernetes falha em produção — e como prevenir cada modo de falha.

Tempo de leitura ~24 min Pré-requisito 02 · IaC · Módulo 01 · containers e orquestração Próximo 04 · CI/CD Pipelines →

A maioria dos tutoriais de Kubernetes ensina o suficiente para criar um Deployment que funciona no laptop. Produção é diferente: o que não está configurado vai falhar de formas que um tutorial nunca cobre. Este conceito não é introdução ao Kubernetes — é o que falta depois que você já sabe criar Deployments, Services, e ConfigMaps.

Resources e limites — a base de tudo

Kubernetes gerencia recursos de dois tipos: CPU (compressível) e memória (não compressível). Essa distinção é fundamental:

Resources em Kubernetes tem duas dimensões: request (o que o scheduler garante que estará disponível) e limit (o máximo que o container pode usar):

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"    # 250 milicores = 0.25 core
  limits:
    memory: "512Mi"
    cpu: "500m"

O scheduler do Kubernetes usa os requests para decidir em qual nó colocar um Pod — ele garante que o nó tem ao menos aquela quantidade disponível. Os limits são aplicados pelo cgroup do container. O erro clássico é não definir limites: um container sem limits.memory pode consumir toda a memória do nó e causar OOM em outros containers.

modo de falha comum

Containers sem limits são a causa mais comum de cascata de falhas em clusters Kubernetes de produção. Um leak de memória em uma aplicação consome toda a RAM do nó, o nó remove pods por OOM, os pods vão para outros nós, os outros nós ficam sobrecarregados — e o cluster fica indisponível em cascata. Sempre defina limits. Use LimitRange no namespace para forçar um default se os times esquecerem.

A escolha de valores corretos para requests/limits requer métricas históricas: meça o consumo real em produção por alguns dias, defina requests em ~75% do percentil 95, e limits em 2x o request. Ajuste baseado em alertas de throttling de CPU ou OOMKills.

HPA — Horizontal Pod Autoscaler

HPA escala o número de réplicas de um Deployment (ou StatefulSet) baseado em métricas. A configuração mais simples usa CPU:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: meu-servico-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: meu-servico
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70   # escala quando CPU média > 70% do request
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

HPA pode também usar métricas customizadas (via Prometheus Adapter) — escalar por número de mensagens na fila, latência p99, ou qualquer métrica que você expõe. O padrão de "escalar por tamanho de fila" é particularmente útil para workloads de processamento assíncrono.

O problema mais sutil do HPA é o período de cooldown: por padrão, Kubernetes não reduz o número de réplicas por 5 minutos após um scale-down. Se seu tráfego tem picos muito curtos (bursts de 30 segundos), o HPA pode não responder rápido o suficiente. Ajuste behavior.scaleDown.stabilizationWindowSeconds.

VPA — Vertical Pod Autoscaler

Enquanto HPA escala horizontalmente (mais réplicas), VPA ajusta requests de um Pod individualmente. Útil para workloads que não escalam horizontalmente (bancos de dados com estado) ou para calibrar requests de forma contínua:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: meu-servico-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: meu-servico
  updatePolicy:
    updateMode: "Off"   # Off = apenas recomenda, não aplica automaticamente

O modo Off (ou Initial) é o mais seguro em produção: o VPA analisa o consumo histórico e recomenda requests ideais, mas não reinicia pods automaticamente. Use kubectl get vpa meu-servico-vpa para ver as recomendações e ajuste manualmente. VPA com updateMode: Auto reinicia pods quando as recomendações mudam — pode causar instabilidade em serviços com estado ou tráfego constante.

HPA + VPA juntos

Usar HPA e VPA simultaneamente no mesmo Deployment é possível mas requer cuidado: não use VPA em modo Auto com HPA baseado em CPU — eles competem. O padrão seguro: HPA em CPU/custom metrics, VPA em modo Off para calibrar os requests que o HPA usa como base de cálculo.

PodDisruptionBudget — disponibilidade durante manutenções

PDB (PodDisruptionBudget) define quantos pods de um Deployment podem ser indisponíveis simultaneamente durante interrupções voluntárias: node drain (manutenção de nó), rolling update de nó, ou operações do cluster como upgrades de versão do Kubernetes.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: meu-servico-pdb
spec:
  minAvailable: 2        # ou maxUnavailable: 1 — mas não os dois
  selector:
    matchLabels:
      app: meu-servico

Sem PDB, um kubectl drain node-1 pode remover todos os pods de um Deployment de um nó se todas as réplicas estiverem no mesmo nó. Com minAvailable: 2, o drain aguarda que pelo menos 2 réplicas estejam disponíveis antes de remover cada pod — evitando downtime durante manutenção planejada.

PDB protege apenas contra interrupções voluntárias. Se um nó morrer abruptamente (falha de hardware), o PDB não se aplica — os pods são terminados sem respeito ao budget. Para proteção real, distribua réplicas por múltiplos nós com PodAntiAffinity.

Probes — semântica correta é crítica

Kubernetes tem três tipos de probe, cada um com semântica distinta:

Liveness probe: "o container está vivo?" — se falhar, Kubernetes reinicia o container. Use para detectar deadlocks ou estados irrecuperáveis. Nunca teste dependências externas na liveness probe: se seu banco de dados estiver down e todos os containers falharem na liveness probe, o Kubernetes vai reiniciar todos eles simultaneamente — piorando o problema.

Readiness probe: "o container está pronto para receber tráfego?" — se falhar, o pod é removido do Service Endpoint (não recebe tráfego novo), mas não é reiniciado. Use para sinalizar que o container está aquecendo (loading caches, aguardando conexão ao banco), ou que está temporariamente sobrecarregado. Dependências externas podem e devem ser testadas aqui.

Startup probe: "o container completou a inicialização?" — enquanto falhar, as liveness e readiness probes são desabilitadas. Use para containers com inicialização lenta (JVM, aplicações com warmup de cache). Evita que a liveness probe mate um container que ainda está inicializando.

livenessProbe:
  httpGet:
    path: /healthz       # responde 200 se o processo está funcional
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 10
  failureThreshold: 3    # reinicia após 3 falhas consecutivas

readinessProbe:
  httpGet:
    path: /ready         # responde 200 se pode receber tráfego (inclui deps)
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30   # até 30 * 10s = 5 min para inicializar
  periodSeconds: 10

O endpoint /healthz deve responder apenas "o processo está vivo" — sem verificar banco, cache, ou qualquer coisa externa. O endpoint /ready pode verificar dependências essenciais, mas com timeout curto para não bloquear o probe.

NetworkPolicies — segmentação de rede no cluster

Por padrão, todos os pods em um cluster Kubernetes podem se comunicar livremente entre si — incluindo entre namespaces diferentes. NetworkPolicy é o recurso que define quem pode falar com quem, como firewalls dentro do cluster.

O baseline recomendado é deny-all + allow explícito:

# 1. Negar todo tráfego de entrada e saída no namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: producao
spec:
  podSelector: {}    # aplica a todos os pods
  policyTypes:
    - Ingress
    - Egress

---
# 2. Permitir explicitamente o que é necessário
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-db
  namespace: producao
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api-server
      ports:
        - protocol: TCP
          port: 5432

NetworkPolicies requerem um CNI plugin que as implemente: Calico, Cilium, ou Weave. O CNI padrão do EKS (AWS VPC CNI) não implementa NetworkPolicy — você precisa instalar Calico ou migrar para Cilium. GKE e AKS têm suporte nativo quando ativado explicitamente.

RBAC de cluster — princípio do menor privilégio

O RBAC do Kubernetes controla quais usuários e service accounts podem fazer o quê no cluster. Os conceitos são:

# Role para um serviço que só precisa ler Secrets no próprio namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: meu-servico
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list"]
    resourceNames: ["db-credentials", "api-key"]   # restringir a secrets específicos

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: meu-servico-reads-secrets
  namespace: meu-servico
subjects:
  - kind: ServiceAccount
    name: meu-servico-sa
    namespace: meu-servico
roleRef:
  kind: Role
  apiGroup: rbac.authorization.k8s.io
  name: secret-reader

Nunca use cluster-admin para service accounts de aplicação. Prefira roles namespace-scoped com o mínimo de permissões necessárias. Valide periodicamente com kubectl auth can-i --list --as=system:serviceaccount:meu-servico:meu-servico-sa.

NodeAffinity e PodAntiAffinity

NodeAffinity controla em quais nós um pod pode ser agendado. PodAntiAffinity garante que pods de um Deployment sejam distribuídos por nós ou zonas diferentes:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/arch
              operator: In
              values: [amd64]      # só nós x86-64 (não ARM)
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          topologyKey: topology.kubernetes.io/zone   # prefere nós em zonas diferentes
          labelSelector:
            matchLabels:
              app: meu-servico

A distinção entre required e preferred é crítica: required faz o pod ficar pendente se não houver nó compatível (pode causar indisponibilidade). preferred é uma preferência que o scheduler tenta satisfazer mas ignora se não for possível. Para anti-afinidade de zona, use preferred exceto quando a distribuição por zona é um requisito hard de disponibilidade.

Por que Kubernetes falha em produção — checklist

Os modos de falha mais comuns em clusters Kubernetes em produção:

  1. Sem resource limits: um container sem limits.memory consome memória do nó → OOM → cascata. Mitigação: LimitRange no namespace com defaults.
  2. Probes mal configuradas: liveness probe dependendo de banco → reinício em cascata quando banco fica lento. Mitigação: separar liveness de readiness.
  3. Sem PDB: upgrade do cluster drena nó e derruba todas as réplicas. Mitigação: PDB para todo Deployment com mais de 1 réplica.
  4. Réplicas no mesmo nó: 3 réplicas no mesmo nó perdem todas quando o nó falha. Mitigação: PodAntiAffinity por nó e zona.
  5. Sem NetworkPolicy: comprometimento de um pod permite movimento lateral para todos os outros. Mitigação: default-deny-all + allow explícito.
  6. Image pull sem digest: a tag :latest pode apontar para imagens diferentes em diferentes nodes. Mitigação: sempre use SHA digest em produção (image: minha-app@sha256:abc123).
  7. Sem requests definidos: o scheduler não tem informação para fazer bin-packing eficiente → nós subdimensionados ou superdimensionados.
  8. RBAC muito permissivo: service account com cluster-admin comprometido dá controle total do cluster. Mitigação: principle of least privilege.
managed vs self-managed Kubernetes

EKS, GKE, e AKS delegam a operação do control plane ao provider: você não opera etcd, não faz upgrade do API server, não se preocupa com HA do scheduler. O custo é de ~$70–150/mês por cluster e alguma perda de controle na configuração do control plane. Para a maioria das equipes com menos de 10 clusters, managed Kubernetes paga o investimento. A exceção: requisitos de air-gap, compliance que exige hardware específico, ou clusters em edge computing.

Decisões de engenharia

HPA vs VPA — quando usar qual autoscaler

HPA (mais réplicas) é a escolha padrão para serviços stateless que respondem bem à escala horizontal — APIs, workers assíncronos. Escala rápido (segundos) e não causa interrupção de tráfego. VPA (mais recursos por pod) é adequado para workloads que não escalam horizontalmente (um pod de banco, jobs batch de ML com uso de memória crescente) ou para calibrar requests periodicamente com updateMode: Off. Nunca use HPA em CPU simultaneamente com VPA em Auto — eles competem: VPA sobe o request de CPU, HPA acha que CPU está alta e cria mais réplicas, VPA recalibra, loop infinito. O padrão seguro é HPA para escalabilidade + VPA em Off para recomendações de rightsizing.

LimitRange vs ResourceQuota — controle de recursos por namespace

LimitRange define defaults e máximos por container — se um Deployment não especifica resources, o LimitRange injeta os defaults automaticamente. É proteção contra containers sem limits que podem consumir o nó inteiro. ResourceQuota controla o consumo agregado do namespace — "esse namespace pode usar no máximo 20 cores e 40Gi de memória no total". Use ambos juntos: LimitRange garante que cada workload tem limites definidos; ResourceQuota garante que a soma dos workloads não explode o cluster. Em clusters multi-tenant (múltiplos times compartilhando o mesmo cluster), ResourceQuota por namespace é o mecanismo de isolamento de cotas entre times.

O que testar em liveness vs readiness probe

Liveness deve testar apenas que o processo está vivo e capaz de processar — sem dependências externas. Um endpoint /healthz que retorna 200 se o event loop (Node.js), thread pool (Java), ou runtime (Go) está responsivo. Se a liveness depende do banco e o banco fica lento, Kubernetes reinicia todos os pods simultaneamente — amplificando o incidente. Readiness deve testar que o pod está pronto para receber tráfego — inclui dependências críticas (conexão ao banco estabelecida, cache aquecido, feature flags carregadas). Se a readiness falha, o pod sai do load balancer mas não morre — pode se recuperar quando o banco voltar, sem restart. A separação semântica é: liveness = matar e recriar vai ajudar? readiness = devo enviar tráfego agora?

Managed Kubernetes (EKS/GKE/AKS) vs self-managed (kubeadm/K3s)

Managed é a escolha correta para a maioria dos casos: control plane altamente disponível sem operação (etcd, API server, scheduler gerenciados pelo provider), upgrades de versão com um comando, integração nativa com IAM, load balancers, e storage do provider. Custo: $70–150/mês por cluster + custo dos nós. Self-managed (kubeadm, K3s, RKE2) faz sentido para: ambientes air-gapped sem acesso à internet, edge computing em hardware específico, clusters de CI temporários onde o custo do managed cluster soma, ou requisitos de compliance que exigem controle total da versão de todos os componentes. K3s especificamente é adequado para clusters pequenos (IoT, edge) por ter footprint menor. Para equipes sem especialista dedicado em Kubernetes, managed elimina a categoria inteira de incidentes de control plane.

Perguntas de entrevista

Por que liveness probe nunca deve testar dependências externas como banco de dados?

A semântica da liveness probe é "reiniciar este container vai resolver o problema?". Se a liveness falha, Kubernetes mata e recria o container. Isso faz sentido para deadlocks e estados internos irrecuperáveis — reiniciar resolve. Mas se a liveness testa o banco de dados e o banco fica temporariamente lento ou indisponível, todos os pods do Deployment começam a falhar na liveness probe simultaneamente. O Kubernetes reinicia todos eles ao mesmo tempo — o que piora o problema por três razões: (1) o reinício não resolve a indisponibilidade do banco; (2) pods em reinício não recebem tráfego, amplificando o impacto; (3) o padrão de "restart em loop" consume recursos e pode colocar o node em pressão.

A solução é separar semântica: liveness testa apenas o processo interno (event loop, goroutines, thread pool). Readiness testa dependências — quando a readiness falha por indisponibilidade do banco, o pod sai do load balancer (não recebe tráfego novo) mas permanece vivo. Quando o banco volta, a readiness passa, o pod volta ao load balancer. Sem restart, sem amplificação do incidente.

O que acontece sem PodDisruptionBudget durante um node drain e por que isso causa downtime?

Sem PDB, kubectl drain node-1 remove imediatamente todos os pods do nó — sem verificar quantas réplicas estão disponíveis em outros nós. Se todas as 3 réplicas de um Deployment estiverem no node-1 (o que acontece quando o scheduler não tem PodAntiAffinity configurado), o drain remove todas as 3 simultaneamente. O Deployment fica com 0 réplicas durante o tempo que o scheduler recria os pods em outros nós — tipicamente 30–60 segundos de downtime completo.

Com minAvailable: 2 no PDB, o drain torna-se um processo respeitoso: antes de remover cada pod, o Kubernetes verifica que pelo menos 2 réplicas estão disponíveis e healthy em outros nós. Se apenas 2 réplicas estão disponíveis, o drain aguarda antes de remover a terceira. O resultado é zero downtime durante manutenção planejada — que inclui upgrades de versão do Kubernetes (que drain os nós um por um). PDB é obrigatório para qualquer serviço que precisa de disponibilidade contínua e passa por upgrades regulares do cluster.

Qual a diferença entre required e preferred em affinity rules, e quando cada uma pode causar problemas?

requiredDuringSchedulingIgnoredDuringExecution: o scheduler só coloca o pod em nós que satisfazem a regra. Se nenhum nó satisfaz, o pod fica no estado Pending indefinidamente. "IgnoredDuringExecution" significa que se um nó já rodando o pod deixar de satisfazer a regra (ex: uma label foi removida do nó), o pod não é evictado — a regra só se aplica no momento do scheduling.

preferredDuringSchedulingIgnoredDuringExecution: o scheduler tenta satisfazer a regra mas coloca o pod em qualquer nó disponível se a preferência não puder ser satisfeita. Tem um weight (1–100) que permite priorizar entre múltiplas preferências.

O problema com required: PodAntiAffinity required por nó em um cluster com 3 nós e 4 réplicas faz o 4° pod ficar pendente para sempre — não há nó que não tenha já um pod da mesma app. Use preferred para anti-afinidade de zona (se só houver 2 AZs para 3 réplicas, você quer que 2 fiquem numa AZ em vez de nenhuma ser criada). Use required apenas quando a regra de scheduling é realmente um requisito hard — como "só nós com GPU" para workloads de ML.

Por que o networking padrão do Kubernetes é inseguro e o que NetworkPolicy resolve?

Por padrão, Kubernetes implementa um modelo de rede flat: qualquer pod pode se comunicar com qualquer outro pod em qualquer namespace usando o IP interno do pod. Um pod comprometido no namespace frontend pode fazer requests diretos ao pod de banco no namespace database, ao serviço de pagamentos no namespace billing, e a qualquer outro serviço — sem nenhuma restrição de rede. Isso viola o princípio de defense in depth: comprometer um componente de baixo privilégio dá acesso à rede interna inteira.

NetworkPolicy resolve criando firewalls declarativos no nível de pod/namespace. O padrão de segurança é deny-all como baseline: uma NetworkPolicy com podSelector: {} e sem regras de ingress/egress bloqueia todo tráfego por padrão. Então você adiciona políticas explícitas de allow para os fluxos necessários: "frontend pode falar com api na porta 8080", "api pode falar com postgres na porta 5432". Qualquer movimento lateral não explicitamente autorizado é bloqueado. O custo operacional é manter as políticas atualizadas conforme a topologia de serviços evolui — motivo pelo qual Cilium com visualização de network flow é útil: você vê quais conexões estão sendo feitas e quais estão sendo bloqueadas.

Como o scheduler do Kubernetes usa requests (e não limits) para tomar decisões de placement?

O scheduler do Kubernetes não conhece o consumo real de um pod — ele usa os requests declarados como representação do que o pod vai usar. O algoritmo de scheduling funciona assim: para cada pod pendente, o scheduler lista os nós viáveis (aqueles com recursos disponíveis suficientes para os requests do pod), aplica predicates (NodeAffinity, Taints/Tolerations, PodAntiAffinity), e então scores os nós viáveis para escolher o melhor (geralmente o que tem mais recursos disponíveis, para espalhar a carga).

"Recursos disponíveis" no nó = capacidade do nó − soma dos requests de todos os pods rodando nele. Os limits são irrelevantes para o scheduler — eles são aplicados pelos cgroups em runtime. Isso tem implicações importantes: (1) se requests são muito menores que o uso real, o scheduler vai empilhar pods em nós que parecem ter capacidade mas não têm — resultando em OOM; (2) se requests são muito maiores que o uso real, os nós aparecem "cheios" mesmo com CPU/memória ociosa — desperdício de recursos. A calibração correta de requests (via VPA em modo Off ou análise de Prometheus) é o que torna o cluster eficiente.

Como praticar

  1. Configurar resources, probes e PDB para um Deployment existente. Pegue um Deployment em qualquer cluster (Kind local ou Minikube) sem resources e probes configurados. Adicione requests/limits baseados no consumo observado (kubectl top pod), implemente os três tipos de probe com endpoints corretos na aplicação, e adicione um PDB com minAvailable: 1.
    Critério: kubectl describe pod deve mostrar Requests e Limits definidos. Simular falha da dependência externa (parar o banco) deve fazer a readiness probe falhar sem que o pod seja reiniciado (liveness não deve ser afetada). kubectl drain de um nó com o PDB configurado deve respeitar o budget — aguardando antes de remover o pod se minAvailable não estiver satisfeito.
  2. Implementar NetworkPolicy de deny-all + allow explícito em um namespace. Em um cluster Kind com Calico ou Cilium como CNI, crie dois Deployments (api e db) no mesmo namespace. Verifique que eles se comunicam. Adicione a NetworkPolicy de deny-all e verifique que a comunicação é bloqueada. Adicione a política de allow explícito e verifique que apenas o fluxo autorizado funciona.
    Critério: Antes da NetworkPolicy, kubectl exec api-pod -- curl db-service:5432 deve funcionar. Após deny-all, deve retornar connection refused ou timeout. Após allow explícito, a comunicação api→db deve funcionar mas db→api (fluxo reverso não autorizado) deve continuar bloqueado.
  3. Configurar HPA com métricas de CPU e observar comportamento de scale. Crie um Deployment com HPA configurado para escalar entre 2 e 10 réplicas com target de 50% de CPU. Use uma ferramenta de stress (como stress-ng em um container de teste) para aumentar a carga e observe o HPA escalar. Monitore com kubectl get hpa -w e kubectl get pods -w.
    Critério: Sob carga, o HPA deve aumentar o número de réplicas até reduzir a CPU média para próximo do target (50%). Após remover a carga, aguardar o período de cooldown (padrão 5 min) e verificar que o HPA escala down. Documentar o tempo de resposta do scale-up: quantos segundos entre a carga aumentar e os novos pods estarem ready.
  4. Configurar PodAntiAffinity por zona e verificar distribuição. Em um cluster com nós em múltiplas zonas (ou simular com labels em Kind), configure um Deployment com preferredDuringScheduling PodAntiAffinity usando topologyKey: topology.kubernetes.io/zone. Escale para 6 réplicas e verifique a distribuição por zona.
    Critério: kubectl get pods -o wide deve mostrar réplicas distribuídas entre as zonas disponíveis, não concentradas em uma única zona. Adicionar uma réplica quando já existe uma distribuição balanceada deve colocá-la na zona com menor contagem. Verificar com kubectl describe pod que a affinity rule está sendo aplicada.
  5. Auditar o RBAC de um namespace e aplicar least privilege. Em um cluster existente (ou Kind), liste os ClusterRoleBindings e RoleBindings do namespace com kubectl get rolebindings,clusterrolebindings -A. Identifique service accounts com cluster-admin ou roles excessivamente permissivos. Para um service account específico, crie um Role mínimo com apenas os verbs e resources necessários e valide com kubectl auth can-i.
    Critério: kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa> deve mostrar apenas as permissões explicitamente concedidas no novo Role. Tentar uma operação não autorizada (ex: kubectl get secrets --as=system:serviceaccount:<ns>:<sa> para um secret não incluído no Role) deve retornar "forbidden".

Referências para aprofundar

  1. book Kubernetes: Up and Running (3rd ed.) — Brendan Burns et al. (O'Reilly, 2022). Referência abrangente de Kubernetes cobrindo desde conceitos até patterns de produção — HPA, PDB, RBAC, NetworkPolicies, e operações de cluster. Escrito por um dos criadores originais do Kubernetes no Google.
  2. book Kubernetes Patterns (2nd ed.) — Bilgin Ibryam & Roland Huß (O'Reilly, 2023). Catálogo de padrões de design para workloads Kubernetes — Sidecar, Ambassador, Adapter, Batch Job, Stateful Service. Cobre como estruturar aplicações para tirar proveito das primitivas do Kubernetes, incluindo probes, init containers, e lifecycle hooks.
  3. book Container Security — Liz Rice (O'Reilly, 2020). Segurança de workloads em profundidade — NetworkPolicies, RBAC, Pod Security Admission, OPA/Gatekeeper, e como containers isolam processos via namespaces e cgroups Linux. Essencial para entender o modelo de segurança do Kubernetes além das APIs de surface.
  4. docs Kubernetes Docs — Configure Liveness, Readiness and Startup Probes. kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes. Documentação oficial com semântica completa de cada probe, parâmetros de configuração (failureThreshold, periodSeconds, initialDelaySeconds), e exemplos de HTTP, TCP, e exec probes.
  5. article A Visual Guide on Troubleshooting Kubernetes Deployments — Learnk8s. learnk8s.io/troubleshooting-deployments. Fluxograma interativo de diagnóstico de problemas de produção — pod em Pending, CrashLoopBackOff, ImagePullBackOff, container em OOMKilled. Referência prática para debugging sem depender de memória.
  6. docs EKS Best Practices Guide — AWS. aws.github.io/aws-eks-best-practices. Guia oficial de melhores práticas para EKS — networking, segurança, escalabilidade, e operações de cluster. Cobre especificamente como configurar Calico para NetworkPolicies no EKS (que não suporta NetworkPolicy nativamente com o VPC CNI padrão).
  7. docs Cilium — NetworkPolicy Editor e Documentação. docs.cilium.io e editor.networkpolicy.io. Cilium é o CNI mais avançado para NetworkPolicies — suporta políticas L7 (HTTP path, gRPC method), observabilidade de fluxos de rede, e integração com service mesh. O editor visual de NetworkPolicy (networkpolicy.io) é ferramenta essencial para criar e depurar políticas.
  8. article Production Best Practices Checklist — Learnk8s. learnk8s.io/production-best-practices. Checklist interativo de 30+ itens para clusters de produção — resources, probes, PDB, RBAC, NetworkPolicies, image tags, resource quotas. Útil como checklist de revisão antes de colocar workloads em produção.
  9. article Kubernetes the Hard Way — Kelsey Hightower. github.com/kelseyhightower/kubernetes-the-hard-way. Tutorial de instalação manual de Kubernetes sem automação — configurando etcd, API server, scheduler, controller manager, e kubelets manualmente. Não é para uso em produção, mas para entender o que managed Kubernetes abstrai e o que cada componente faz.
  10. article CNCF Security Whitepaper — Cloud Native Security — CNCF TAG Security. github.com/cncf/tag-security/tree/main/security-whitepaper. Whitepaper oficial da CNCF sobre segurança cloud native — modelo de ameaças para Kubernetes, layers de segurança (cluster, container, código), e framework de avaliação. Referência para discussões de segurança com times e auditores.
  11. article Vertical Pod Autoscaler — How It Works — Kubernetes Blog. kubernetes.io/blog. Artigo oficial sobre o VPA — como o recommender analisa métricas históricas, os modos de atualização (Off/Initial/Auto), e como combinar VPA com HPA corretamente. Inclui análise dos riscos de updateMode: Auto em produção.
  12. book Production Kubernetes — Josh Rosso et al. (O'Reilly, 2021). Cobre o gap entre "consigo rodar Kubernetes" e "consigo operar Kubernetes em produção" — multi-tenancy, network segmentation, storage classes, backup de cluster, e operações de dia 2. Complementa o Kubernetes: Up and Running com foco operacional.