Uma referência rápida dos padrões arquiteturais que o exame CKA avalia. Leia de cima a baixo ou pule para uma seção.
Arquitetura do Cluster, Instalação e Configuração
Requisito para realizar um backup de recuperação de desastres do estado do cluster.
Use `etcdctl snapshot save` com os certificados TLS apropriados (`--cacert`, `--cert`, `--key`) e endpoint.
Por quê: O etcd armazena todo o estado do cluster. O snapshotting direto é a forma canônica de fazer backup. Em um cluster kubeadm, o TLS está habilitado, então os certificados são obrigatórios para o `etcdctl` se autenticar.
Restaurar um cluster a partir de um backup de recuperação de desastres.
Use `etcdctl snapshot restore` para um novo diretório de dados. Em seguida, atualize o manifesto do static pod `etcd.yaml` para apontar seu volume mount `--data-dir` para o novo local e reinicie o kubelet.
Por quê: A restauração cria um novo diretório de dados. O manifesto do static pod deve ser atualizado para usar esses novos dados, caso contrário, o etcd iniciará com o diretório de dados antigo (ou vazio).
Realizar uma atualização de versão para um cluster gerenciado por kubeadm.
1. No control plane: atualize o `kubeadm`, execute `kubeadm upgrade plan`, depois `kubeadm upgrade apply`. 2. Em cada nó worker: `kubectl drain`, atualize o `kubelet`, reinicie o serviço kubelet, `kubectl uncordon`.
Por quê: O processo é multi-etapas e sequencial. O `kubeadm` apenas atualiza os componentes do control plane; o `kubelet` deve ser atualizado manualmente em cada nó. Drenar os nós garante que os workloads sejam seguramente removidos antes da manutenção.
Os certificados do cluster estão expirando e precisam ser verificados ou renovados.
Use `kubeadm certs check-expiration` para visualizar as datas de expiração. Use `kubeadm certs renew all` (ou para componentes específicos) para renová-los. Reinicie os pods do control plane após a renovação.
Por quê: Os certificados gerados pelo Kubeadm têm validade de 1 ano. A renovação é uma tarefa de manutenção comum. Os componentes do control plane devem ser reiniciados para carregar os novos certificados.
Um componente do control plane (p.ex., API server) precisa ser configurado ou reiniciado.
Modifique o manifesto do componente em `/etc/kubernetes/manifests/`. O kubelet no nó detectará automaticamente a alteração e reiniciará o pod.
Por quê: Os componentes do control plane no kubeadm são executados como static pods, gerenciados diretamente pelo kubelet, não pelo API server. Toda a gestão acontece via arquivos de manifesto no diretório monitorado.
Definir controles de acesso para usuários ou aplicações.
Use um `Role` e `RoleBinding` para permissões com escopo de namespace. Use um `ClusterRole` e `ClusterRoleBinding` para permissões de todo o cluster.
Por quê: Esta é a separação fundamental no RBAC. Um Role está sempre vinculado a um namespace, enquanto um ClusterRole pode conceder acesso a recursos sem namespace (como nós) ou a recursos em todos os namespaces.
Uma service account precisa acessar recursos em todos os namespaces.
Crie um `ClusterRole` definindo as permissões. Crie um `ClusterRoleBinding` para conceder esse ClusterRole à `ServiceAccount` específica.
Por quê: Mesmo que uma ServiceAccount seja namespaced, um ClusterRoleBinding pode conceder-lhe permissões em todo o cluster. Um `RoleBinding` concederia as permissões apenas dentro do próprio namespace do RoleBinding.
Serviços e Rede
Expor uma aplicação ao tráfego externo sem um balanceador de carga da nuvem.
Use um Service do `type: NodePort`. Isso expõe o serviço em uma porta estática (faixa padrão: 30000-32767) no endereço IP de cada nó.
Por quê: NodePort é uma maneira simples de obter tráfego externo para o cluster. É menos caro e agnóstico de plataforma em comparação com `type: LoadBalancer`, mas exige que os clientes saibam o IP de um nó.
Expor múltiplos serviços HTTP/S sob um único endereço IP, com roteamento baseado em host ou caminho.
Implante um Ingress Controller (p.ex., NGINX). Crie recursos `Ingress` que definam regras de roteamento de hosts/caminhos para `Services` de backend.
Por quê: Ingress é o recurso padrão do Kubernetes para roteamento L7. Ele requer um controller separado para realmente implementar a lógica de roteamento. Isso desacopla as regras de roteamento da implementação do proxy.
Proteger um namespace negando todo o tráfego de entrada por padrão.
Crie uma `NetworkPolicy` que selecione todos os pods (`podSelector: {}`) e especifique uma regra de entrada vazia (`ingress: []`).
Por quê: Uma vez que um pod é selecionado por qualquer NetworkPolicy, todo o tráfego não explicitamente permitido é negado. Uma política que seleciona todos os pods com uma regra de entrada vazia cria efetivamente um firewall "negar tudo" para o namespace.
Permitir que pods em um namespace "frontend" acessem pods em um namespace "backend".
No namespace "backend", crie uma NetworkPolicy. Na regra `ingress.from`, use um `namespaceSelector` para corresponder aos rótulos no recurso `Namespace` "frontend".
Por quê: O `podSelector` funciona apenas dentro do namespace da política. Para permitir tráfego de outros namespaces, você deve usar um `namespaceSelector`. Isso requer rotular os próprios objetos `Namespace`.
Uma aplicação precisa se conectar a outro serviço dentro do cluster.
Use o nome DNS interno do serviço: `<service-name>.<namespace>.svc.cluster.local`. Se no mesmo namespace, `<service-name>` é suficiente.
Por quê: O Kubernetes fornece descoberta de serviço estável baseada em DNS via CoreDNS. Isso desacopla as aplicações de IPs de pod específicos, que são efêmeros.
Uma aplicação stateful (p.ex., um conjunto de réplicas de banco de dados) requer identidade de rede direta para cada pod.
Crie um `Service` headless (`clusterIP: None`) para o `StatefulSet`. Isso fornece registros DNS A únicos para cada pod (p.ex., `pod-0.my-service.my-ns...`).
Por quê: Um serviço headless não faz balanceamento de carga. Em vez disso, ele fornece registros DNS para cada pod, permitindo que os clientes se conectem a instâncias específicas, o que é crucial para eleição de líder ou descoberta de pares em sistemas stateful.
Um serviço voltado para o exterior precisa ver o endereço IP original do cliente para registro ou filtragem baseada em IP.
Defina `externalTrafficPolicy: Local` no Service `NodePort` ou `LoadBalancer`.
Por quê: A política padrão `Cluster` oculta o IP do cliente via SNAT. O `Local` evita esse salto de rede extra, roteando o tráfego apenas para os pods no nó que recebeu o tráfego, preservando o IP de origem.
Workloads e Agendamento
Co-localizar ou espalhar pods para desempenho ou alta disponibilidade.
Use `podAffinity` para agendar pods no mesmo nó/zona que outros pods específicos. Use `podAntiAffinity` para evitar agendá-los juntos.
Por quê: Isso fornece controle de agendamento mais avançado do que a afinidade em nível de nó. A antiafinidade com `requiredDuringScheduling...` é crítica para espalhar réplicas de um serviço por nós ou zonas para HA.
Dedicar nós a workloads específicos ou impedir que certos workloads sejam executados neles.
Aplique um `taint` a um nó (p.ex., `gpu=true:NoSchedule`). Adicione uma `toleration` correspondente aos pods que devem ser permitidos a executar nesse nó.
Por quê: Taints repelem pods, enquanto tolerations os permitem. Este é o mecanismo primário para dedicar nós. O efeito `NoExecute` irá remover pods já em execução que não possuem a toleration.
Implantar um agente de monitoramento ou log em cada nó do cluster.
Use um `DaemonSet`. Ele garante que uma cópia do pod seja executada em cada nó que corresponda aos seus critérios de agendamento.
Por quê: DaemonSet é projetado para esse propósito exato. Ele implanta automaticamente em novos nós e lida com o gerenciamento de pods em nível de nó, o que seria difícil com um Deployment.
Executar uma tarefa em lote única ou uma tarefa agendada recorrente.
Use um `Job` para uma tarefa que executa uma vez até a conclusão. Use um `CronJob` para criar Jobs em um agendamento repetido (p.ex., backups noturnos).
Por quê: Jobs garantem que os pods sejam executados até um número especificado de conclusões. CronJobs são um controller de nível superior que gerencia Jobs com base em um agendamento cron.
Atualizar uma aplicação para uma nova versão com zero tempo de inatividade.
Use um `Deployment` com a estratégia padrão `RollingUpdate`. Configure `maxSurge` e `maxUnavailable` para controlar a velocidade e a disponibilidade da atualização.
Por quê: As atualizações rolling substituem gradualmente os pods antigos por novos, garantindo que o serviço permaneça disponível. `maxUnavailable` garante um número mínimo de pods em execução, enquanto `maxSurge` permite um aumento acima da contagem de réplicas desejada para acelerar a implantação.
Garantir que os pods recebam recursos garantidos e não consumam recursos excessivos em um nó.
Defina `resources.requests` (CPU/memória) para garantir um mínimo para agendamento. Defina `resources.limits` para evitar que um container exceda uma certa quantidade.
Por quê: As requests são usadas pelo scheduler para posicionamento e garantem recursos. Os limits são aplicados pelo kubelet e pelo container runtime; exceder o limite de memória resulta em OOMKill.
Implantar uma aplicação stateful que requer identificadores de rede estáveis e únicos e armazenamento persistente por réplica.
Use um `StatefulSet` com um `volumeClaimTemplate`. Isso cria um `PersistentVolumeClaim` único para cada pod, garantindo que os dados sejam reanexados à mesma identidade de pod após a reinicialização.
Por quê: StatefulSets fornecem nomes de pod estáveis (p.ex., `web-0`, `web-1`) e um PVC persistente e único para cada um. Isso é essencial para aplicações que dependem de identidade e armazenamento estáveis.
Armazenamento
Fornecer armazenamento persistente para uma aplicação sem pré-provisionar volumes.
Crie uma `StorageClass` que defina um provisionador de armazenamento. Em seguida, crie um `PersistentVolumeClaim` (PVC) que solicite armazenamento dessa classe. Um `PersistentVolume` (PV) será provisionado dinamicamente.
Por quê: Isso desacopla as aplicações da infraestrutura de armazenamento subjacente. Os desenvolvedores solicitam armazenamento via PVCs, e o administrador do cluster define como esse armazenamento é provisionado via StorageClasses.
Controlar o que acontece com um volume persistente após a exclusão de sua claim.
Defina `persistentVolumeReclaimPolicy` no PV ou StorageClass. `Delete` apaga automaticamente o armazenamento subjacente. `Retain` mantém o volume e os dados intactos, exigindo limpeza manual.
Por quê: `Retain` é a opção mais segura para dados de produção, pois evita a perda acidental de dados. `Delete` é conveniente para ambientes efêmeros ou de desenvolvimento. O padrão depende do provisionador.
Definir como um volume pode ser montado por pods.
Use `accessModes`: `ReadWriteOnce` (RWO) para leitura-escrita em um único nó, `ReadOnlyMany` (ROX) para leitura-somente em múltiplos nós, `ReadWriteMany` (RWX) para leitura-escrita em múltiplos nós.
Por quê: O modo de acesso deve ser suportado pelo provedor de armazenamento subjacente. A incompatibilidade das necessidades da aplicação (p.ex., precisar de RWX) com as capacidades de armazenamento (suportando apenas RWO) é uma causa comum de PVCs Pendentes.
Injetar arquivos de configuração ou dados sensíveis em um pod.
Monte um `ConfigMap` ou `Secret` como um volume. Cada chave no objeto de dados se torna um arquivo no caminho de montagem.
Por quê: Esta é a forma padrão de fornecer configuração para pods. Permite que a configuração seja gerenciada como um objeto Kubernetes e atualizada independentemente da imagem do pod.
Uma aplicação precisa de mais espaço de armazenamento em seu volume persistente existente.
Garanta que a `StorageClass` tenha `allowVolumeExpansion: true`. Edite o `PVC` para solicitar um tamanho maior em `spec.resources.requests.storage`.
Por quê: A expansão de volume é um recurso opt-in. A StorageClass deve explicitamente permiti-lo, e o CSI driver subjacente deve suportá-lo. O pod pode precisar ser reiniciado para que o sistema de arquivos seja redimensionado.
Resolução de Problemas
Um pod está preso no estado `Pending` e não está sendo agendado.
Execute `kubectl describe pod <nome-do-pod>`. Verifique a seção `Events` para mensagens do scheduler.
Por quê: O comando `describe` é a ferramenta principal para isso. Ele mostrará razões como "Insufficient cpu/memory", "node(s) had taints the pod didn't tolerate", ou "didn't match node selector".
Um pod está iniciando e falhando repetidamente, com um status de `CrashLoopBackOff`.
1. `kubectl logs <nome-do-pod> --previous` para ver os logs do container que falhou. 2. `kubectl describe pod <nome-do-pod>` para verificar o código de saída e a razão.
Por quê: `CrashLoopBackOff` significa que a aplicação dentro do container está sendo encerrada. Os logs da instância anterior (`--previous`) são cruciais, pois o container atual pode ainda não ter registrado nada útil. O código de saída também pode indicar o tipo de erro.
Um pod falha ao iniciar com o status `ImagePullBackOff` ou `ErrImagePull`.
`kubectl describe pod <nome-do-pod>` para ver a mensagem do evento. Verifique se o nome e a tag da imagem estão corretos. Para registros privados, certifique-se de que um `imagePullSecrets` esteja configurado e o secret seja válido.
Por quê: Este é um problema de registro ou nome da imagem, não um problema da aplicação. Causas comuns são erros de digitação, tags incorretas ou falha de autenticação com um registro privado.
Um nó tem o status `NotReady`.
Conecte-se via SSH ao nó afetado. Verifique o status do serviço kubelet com `systemctl status kubelet`. Veja seus logs com `journalctl -u kubelet`.
Por quê: O `kubelet` é o agente responsável pelo relatório de saúde do nó. Se estiver inativo ou não conseguir se comunicar com o API server, o nó será marcado como NotReady. Seus logs são o primeiro lugar para procurar.
Um serviço existe, mas o tráfego não está chegando aos pods de backend.
1. `kubectl describe svc <nome-do-serviço>` e verifique se o `Selector` corresponde aos rótulos dos pods. 2. `kubectl get endpoints <nome-do-serviço>` e certifique-se de que ele lista os IPs corretos dos pods. Caso contrário, os rótulos estão incorretos.
Por quê: A ligação entre um Service e seus Pods é o seletor de rótulos. Se o seletor estiver errado ou os pods não tiverem os rótulos corretos, o objeto Endpoints estará vazio e o serviço não terá para onde rotear o tráfego.
Pods são incapazes de resolver nomes de serviço ou nomes de host externos.
1. Verifique se os pods do CoreDNS estão em execução em `kube-system`. 2. Verifique os logs do CoreDNS. 3. Execute um pod de depuração (p.ex., `busybox`) e use `nslookup` para testar a resolução de dentro do cluster.
Por quê: O DNS é uma dependência crítica do cluster. Falhas geralmente remontam à própria implantação do CoreDNS, sua configuração (em um ConfigMap) ou políticas de rede bloqueando o tráfego DNS na porta UDP/TCP 53.
Um nó deve ser colocado offline para manutenção.
Primeiro, `kubectl cordon <nome-do-nó>` para marcá-lo como não agendável. Em seguida, `kubectl drain <nome-do-nó> --ignore-daemonsets` para remover com segurança todos os pods de usuário.
Por quê: `cordon` impede que novos pods sejam agendados. `drain` respeita os PodDisruptionBudgets e remove os pods de forma graciosa. `--ignore-daemonsets` é necessário porque os pods DaemonSet não podem ser removidos.
Identificar quais pods ou nós estão consumindo mais CPU ou memória.
Use `kubectl top pods` e `kubectl top nodes`. Isso requer que o `metrics-server` esteja implantado no cluster.
Por quê: `kubectl top` fornece uma visão rápida e em tempo real do consumo de recursos, essencial para identificar aplicações que consomem muitos recursos ou pressão de recursos no nó.
Um pod está no estado `Terminating` há muito tempo e não está sendo removido.
Force a exclusão do pod com `kubectl delete pod <nome-do-pod> --grace-period=0 --force`.
Por quê: Isso pode acontecer se um finalizer estiver preso ou o kubelet não conseguir limpar os recursos. A exclusão forçada remove o pod do API server imediatamente, mas deve ser usada como último recurso, pois pode deixar recursos órfãos no nó.