Uma referência rápida dos padrões arquiteturais que o exame CKAD avalia. Leia de cima a baixo ou pule para uma seção.
Ambiente, Configuração e Segurança da Aplicação
Criar um ConfigMap ou Secret genérico a partir de pares chave-valor da linha de comando.
Use `kubectl create configmap <name> --from-literal=<key>=<value>` ou `kubectl create secret generic <name> --from-literal=<key>=<value>`.
Por quê: `--from-literal` é para entrada direta de chave-valor. Use a flag várias vezes para múltiplas chaves. Isso é mais rápido do que criar um arquivo YAML para casos simples.
Por quê: `valueFrom` oferece injeção seletiva e permite mapear a chave de origem para um nome de variável de ambiente diferente.
Montar um ConfigMap ou Secret como arquivos em um Pod, permitindo atualizações em tempo real.
Defina um `volume` do tipo `configMap` ou `secret`. Monte-o no container usando `volumeMounts`. Os arquivos serão nomeados de acordo com as chaves.
Por quê: Os arquivos montados de ConfigMaps/Secrets são atualizados automaticamente quando a origem muda. As variáveis de ambiente não são, exigindo um reinício do Pod.
Aplicar as melhores práticas de segurança: impedir a execução como root, tornar o sistema de arquivos root somente leitura ou especificar um ID de usuário.
Use `securityContext` no nível do Pod ou do container. Defina `runAsNonRoot: true`, `readOnlyRootFilesystem: true` e/ou `runAsUser: <UID>`.
Por quê: SecurityContext oferece controle declarativo e granular sobre os privilégios do container, essencial para fortalecer aplicações e atender às políticas de segurança.
Conceder a um Pod permissões mínimas para acessar a Kubernetes API.
1. Crie um `ServiceAccount` personalizado. 2. Crie um `Role` com apenas as permissões de API necessárias (ex: listar pods). 3. Crie um `RoleBinding` para vincular o ServiceAccount e o Role. 4. Atribua o ServiceAccount ao Pod via `spec.serviceAccountName`.
Por quê: Segue o princípio do menor privilégio, minimizando a superfície de ataque caso um Pod seja comprometido.
Impedir a montagem automática de um token de ServiceAccount em um Pod que não precisa de acesso à API.
Defina `automountServiceAccountToken: false` na especificação do Pod ou no próprio ServiceAccount.
Por quê: Reduz a superfície de ataque ao não fornecer credenciais de API a containers que não as exigem.
Criar um Secret para uso em terminação TLS para um Ingress ou outro serviço seguro.
Use `kubectl create secret tls <secret-name> --cert=<path/to/cert.pem> --key=<path/to/key.pem>`.
Por quê: Isso cria um Secret do tipo correto `kubernetes.io/tls` com as chaves de dados padrão `tls.crt` e `tls.key` esperadas pelos Ingress controllers.
Expor metadados do Pod (como nome, namespace, labels ou IP do nó) a um container.
Use a Downward API para projetar metadados como variáveis de ambiente ou arquivos em um volume `downwardAPI`. Exemplo: `valueFrom: {fieldRef: {fieldPath: metadata.name}}`.
Por quê: Permite que os containers sejam autoconscientes sem precisar consultar a Kubernetes API, simplificando a configuração e reduzindo os requisitos de RBAC.
Definir solicitações e limites padrão de CPU/memória para todos os Pods em um namespace.
Crie um objeto `LimitRange` no namespace. Defina os valores `default` e `defaultRequest` para os recursos.
Por quê: Garante que todos os Pods tenham restrições de recursos, melhorando o agendamento e a estabilidade, mesmo que os desenvolvedores se esqueçam de especificá-los. Funciona em conjunto com ResourceQuota.
Limitar a quantidade total de recursos (CPU, memória, contagem de objetos) que podem ser consumidos em um namespace.
Crie um objeto `ResourceQuota`. Defina limites rígidos em `spec.hard`, por exemplo, `requests.cpu: "4"`, `pods: "10"`.
Por quê: Impede que um namespace ou equipe consuma todos os recursos do cluster, garantindo uma alocação justa de recursos.
Design e Construção da Aplicação
Executar tarefas pré-requisito (ex: esperar por um banco de dados, executar migrações, buscar dados) antes do início da aplicação principal.
Defina um ou mais `initContainers` na especificação do Pod. Eles são executados sequencialmente até a conclusão antes que os containers da aplicação principal iniciem.
Por quê: Desacopla a lógica de configuração do container da aplicação e garante que as dependências sejam atendidas antes que a aplicação seja lançada.
Estender um container de aplicação primário com funcionalidade auxiliar como logging, monitoramento ou proxying.
Adicione um segundo container (o sidecar) à especificação do Pod. Ambos os containers compartilham recursos como rede e volumes.
Por quê: Aprimora a funcionalidade sem modificar o código da aplicação principal, promovendo a separação de responsabilidades.
Compartilhar um diretório para leitura/escrita entre containers no mesmo Pod.
Defina um volume `emptyDir` na especificação do Pod e monte-o em todos os containers necessários.
Por quê: `emptyDir` fornece um volume de armazenamento simples e efêmero que existe durante a vida do Pod, perfeito para compartilhamento de dados intra-Pod.
Substituir o ENTRYPOINT e/ou CMD padrão de uma imagem de container.
Na especificação do container, use `command` para substituir ENTRYPOINT e `args` para substituir CMD. `command: ["/bin/sh"], args: ["-c", "echo hello"]`.
Por quê: Oferece controle total sobre o comando de inicialização do container a partir da definição do Pod, útil para adaptar imagens genéricas.
Executar uma tarefa finita até a conclusão, controlando o paralelismo e o número de conclusões bem-sucedidas.
Use um recurso `Job`. Defina `spec.completions` para a contagem de sucesso alvo e `spec.parallelism` para o número de Pods concorrentes. Use `spec.backoffLimit` para controlar as tentativas.
Por quê: Jobs são projetados para tarefas de execução até a conclusão, ao contrário de Deployments de longa duração. Essas configurações são chave para gerenciar cargas de trabalho em batch.
Agendar uma tarefa recorrente usando a sintaxe cron e controlar como os jobs sobrepostos são tratados.
Use um recurso `CronJob`. Defina o `spec.schedule` no formato cron (ex: `*/5 * * * *`). Defina `spec.concurrencyPolicy` para `Allow`, `Forbid` ou `Replace`.
Por quê: Automatiza tarefas agendadas. `concurrencyPolicy` é crítico para prevenir execuções sobrepostas (`Forbid`) ou substituir as obsoletas (`Replace`).
Gerar rapidamente um manifesto YAML para um recurso sem criá-lo no cluster.
Use as flags `--dry-run=client -o yaml` com comandos imperativos. Exemplo: `kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml`.
Por quê: Economiza tempo ao estruturar um manifesto válido que pode ser personalizado e depois aplicado declarativamente.
Implantação da Aplicação
Atualizar, escalar, verificar status, visualizar histórico e reverter um Deployment imperativamente.
Use `kubectl set image`, `kubectl scale`, `kubectl rollout status`, `kubectl rollout history` e `kubectl rollout undo`.
Por quê: Estes são os comandos imperativos essenciais para gerenciar o ciclo de vida de uma aplicação implantada durante o desenvolvimento e a solução de problemas.
Controlar a velocidade e a segurança de uma atualização de Deployment para garantir a disponibilidade.
Em `spec.strategy.rollingUpdate`, configure `maxSurge` (quantos Pods extras podem ser criados) e `maxUnavailable` (quantos podem estar indisponíveis).
Por quê: Equilibrar `maxSurge` e `maxUnavailable` é fundamental para gerenciar a capacidade versus o uso de recursos durante as atualizações. Para zero downtime, `maxUnavailable` deve ser menor que `replicas`.
Garantir que nenhuma das duas versões de uma aplicação seja executada simultaneamente, encerrando todos os Pods antigos antes de criar os novos.
Defina `spec.strategy.type: Recreate` no Deployment.
Por quê: Garante que versões antigas e novas não coexistam, o que é necessário para aplicações que não conseguem lidar com duas versões diferentes acessando os mesmos dados. Esta estratégia acarreta downtime.
Fazer múltiplas alterações em um Deployment ativo sem acionar um rollout intermediário para cada alteração.
Use `kubectl rollout pause deployment/<name>`, aplique as alterações, então `kubectl rollout resume deployment/<name>`.
Por quê: Consolida múltiplas atualizações em um único evento de rollout, prevenindo instabilidade e condições de corrida.
Limitar o número de ReplicaSets antigos retidos para um Deployment para economizar armazenamento etcd.
Defina `spec.revisionHistoryLimit` para o número desejado de revisões a manter (ex: 3). O padrão é 10.
Por quê: Definir um limite menor reduz a desorganização do etcd. Definir como `0` desabilita completamente a capacidade de rollback.
Documentar a razão para uma atualização de Deployment para que ela apareça no histórico de revisões.
Adicione uma anotação `kubernetes.io/change-cause` ao manifesto do Deployment. Exemplo: `kubectl annotate deployment/nginx kubernetes.io/change-cause="update to 1.20"`.
Por quê: Fornece contexto valioso ao visualizar o histórico de rollout (`kubectl rollout history`), facilitando a identificação de qual revisão reverter.
Implantar uma nova versão da aplicação ao lado da antiga e alternar o tráfego instantaneamente com zero downtime.
Use dois Deployments (ex: `app-blue`, `app-green`) com diferentes labels de versão. Um único Service seleciona a versão ativa através do seu `selector`. Para alternar, `kubectl patch service` para atualizar o selector para o novo label de versão.
Por quê: Oferece lançamentos instantâneos e de baixo risco, e capacidade de rollback imediato, simplesmente corrigindo o selector do Service.
Direcionar uma pequena porcentagem do tráfego para uma nova versão da aplicação para testes em produção.
Use dois Deployments (stable, canary) compartilhando a mesma label de selector. Um Service direciona ambos. Controle a porcentagem de tráfego pela proporção de réplicas (ex: 9 réplicas stable, 1 canary para 10% do tráfego).
Por quê: Uma forma simples de realizar releases canary sem uma service mesh, permitindo testes controlados e de baixo risco de novas funcionalidades. A distribuição de tráfego é aproximada.
Serviços e Rede
Expor um conjunto de Pods para comunicação apenas de dentro do cluster.
Use um Service com `type: ClusterIP`. Este é o tipo padrão.
Por quê: `ClusterIP` fornece um endereço IP interno estável e um nome DNS para um serviço, abstraindo os IPs individuais dos Pods.
Expor um serviço em uma porta estática no endereço IP de cada nó.
Use um Service com `type: NodePort`. O K8s aloca uma porta de um intervalo (padrão: 30000-32767).
Por quê: Útil para desenvolvimento ou quando um load balancer externo não está disponível. O tráfego para `<NodeIP>:<NodePort>` é encaminhado para o Service.
Direcionar tráfego HTTP/S externo para serviços internos com base no nome do host ou caminho da URL.
Crie um recurso `Ingress`. Defina `rules` para hosts e `http.paths` para mapear para serviços de backend. Configure TLS com `spec.tls` apontando para um Secret TLS.
Por quê: Ingress fornece roteamento L7, consolidando múltiplos serviços sob um IP externo e descarregando a terminação TLS.
Restringir o tráfego de rede para e de Pods com base em labels, namespaces ou blocos de IP.
Crie uma `NetworkPolicy` direcionando Pods com `podSelector`. Defina regras de `ingress` e/ou `egress` para permitir tráfego específico. Por padrão, aplicar uma política a um pod nega todo o tráfego não explicitamente permitido.
Por quê: NetworkPolicies são fundamentais para segmentação de rede e implementação de um modelo de segurança de confiança zero no Kubernetes.
Bloquear todo o tráfego de entrada e saída para todos os pods em um namespace por padrão.
Crie uma NetworkPolicy com um `podSelector: {}` vazio e regras de entrada/saída vazias. Exemplo: `podSelector: {}, policyTypes: [Ingress, Egress]`.
Por quê: Estabelece uma linha de base segura onde todo o tráfego é negado, a menos que seja explicitamente permitido por outras NetworkPolicies mais específicas.
Fornecer uma entrada DNS estável que resolve para todos os IPs dos Pods diretamente, sem um IP virtual para balanceamento de carga.
Crie um Service com `spec.clusterIP: None`.
Por quê: Essencial para aplicações stateful (como StatefulSets) ou sistemas peer-to-peer que precisam descobrir e comunicar-se diretamente com Pods específicos.
Garantir que os Pods de backend vejam o IP original do cliente para o tráfego de um Service do tipo NodePort ou LoadBalancer.
Defina `spec.externalTrafficPolicy: Local` no Service.
Por quê: A política padrão (`Cluster`) ofusca o IP de origem via tradução de endereço de rede. `Local` o preserva, mas pode levar a uma distribuição de tráfego desigual se os Pods não estiverem em todos os nós.
Garantir que todas as solicitações de um cliente específico sejam enviadas para o mesmo Pod.
No Service, defina `spec.sessionAffinity: ClientIP`.
Por quê: Fornece 'sticky sessions', o que é necessário para aplicações legadas que armazenam o estado da sessão em memória em um Pod específico.
Um Pod em um namespace precisa se comunicar com um Service em outro namespace.
Use o nome DNS expandido: `<service-name>.<namespace-name>.svc.cluster.local` ou a forma abreviada `<service-name>.<namespace-name>`.
Por quê: Nomes de serviço simples só são resolvidos dentro do mesmo namespace. A comunicação entre namespaces exige a especificação do namespace de destino na consulta DNS.
Observabilidade e Manutenção da Aplicação
Definir verificações de saúde para gerenciar o ciclo de vida do Pod: reiniciar em caso de falha vs. remover do serviço.
`livenessProbe`: Reinicia o container se a sonda falhar. `readinessProbe`: Remove o Pod dos endpoints do Service se a sonda falhar. `startupProbe`: Desabilita outras sondas até que o container finalize sua inicialização.
Por quê: Probes configurados corretamente são essenciais para a autocorreção da aplicação e para alcançar implantações com zero downtime.
Diagnosticar por que um Pod está travado em um estado diferente de Running (ex: Pending, ContainerCreating, CrashLoopBackOff).
Use `kubectl describe pod <pod-name>`. A seção `Events` fornece pistas cruciais do scheduler (problemas de recursos), kubelet (erros de pull de imagem) ou runtime do container.
Por quê: `describe` é o comando mais importante para entender problemas de ciclo de vida do Pod que ocorrem antes que a aplicação inicie ou registre qualquer coisa.
Inspecionar os logs de um container que falhou e agora está em um loop de reinício (CrashLoopBackOff).
Use `kubectl logs <pod-name> --previous`.
Por quê: A flag `--previous` mostra os logs da última instância terminada do container, que contém o erro que causou a falha.
Visualizar e seguir logs de todos os Pods que correspondem a um selector de label em tempo real.
Use `kubectl logs -l <label-selector> -f`. Adicione `--prefix` para ver de qual pod cada linha veio.
Por quê: Agrega logs de uma aplicação distribuída, fornecendo uma visão unificada de seu comportamento.
Executar um comando ou obter um shell interativo dentro de um container em execução para depuração.
Use `kubectl exec -it <pod-name> -- /bin/sh` (ou `/bin/bash`). O `--` separa as flags do kubectl do comando.
Por quê: Fornece acesso direto ao ambiente do container para depuração em tempo real, inspeção de arquivos ou verificação de conectividade de rede.
Visualizar o consumo atual de CPU e memória de um Pod em execução.
Use `kubectl top pod <pod-name>`. Use `--containers` para ver o uso de cada container no Pod.
Por quê: Requer que o Metrics Server esteja instalado. É essencial para identificar aplicações que consomem muitos recursos, vazamentos de memória ou gargalos de CPU.
Resolver problemas de um container em execução que não possui um shell ou ferramentas de depuração.
Use `kubectl debug <pod-name> -it --image=busybox --share-processes --copy-to=debug-pod`. Isso cria um novo Pod com um container de depuração compartilhando o mesmo namespace de processo.
Por quê: `kubectl debug` é a maneira moderna de anexar um "ephemeral container" temporário com ferramentas de depuração a um Pod em execução sem modificar a especificação original do Pod.