Garantir que o estado do cluster corresponda continuamente a um estado desejado.
Confie no `kube-controller-manager`. Ele executa laços de controle que observam recursos (p.ex., ReplicaSets, Deployments) e reconciliam diferenças.
Por quê: Este é o principal mecanismo declarativo e de auto-recuperação. Se um Pod gerenciado por um ReplicaSet falhar, o controlador o substitui automaticamente.
Atribuir automaticamente novos Pods criados ao nó de trabalho mais adequado.
Confie no `kube-scheduler`. Ele filtra nós com base nos requisitos do Pod (p.ex., requisições de recursos) e os pontua para escolher o melhor ajuste.
Por quê: O agendador toma decisões de alocação com base em políticas, afinidade e disponibilidade, abstraindo a seleção de nós do usuário.
Garantir que os contêineres especificados nos Pods estejam em execução e saudáveis em um determinado nó de trabalho.
O agente `kubelet` é executado em cada nó, comunica-se com o servidor da API e gerencia o ciclo de vida do contêiner (iniciar, parar, verificações de saúde) através de um runtime de contêiner.
Por quê: O Kubelet é o elo entre o plano de controle e o nó de trabalho; ele executa as especificações do Pod.
Persistir o estado e a configuração completos do cluster Kubernetes de forma confiável.
Use `etcd`, um armazenamento de chave-valor consistente e altamente disponível. Ele serve como a única fonte de verdade para o cluster.
Por quê: Todos os objetos do cluster (Pods, Services, etc.) são armazenados no etcd. Apenas o servidor da API se comunica diretamente com ele.
Implementar regras de rede em cada nó para permitir a comunicação via Kubernetes Services.
O componente `kube-proxy` em cada nó mantém regras de rede (p.ex., iptables, IPVS) que encaminham o tráfego de um IP de Service para os Pods de backend corretos.
Por quê: Kube-proxy é o detalhe de implementação por trás da abstração de Service, lidando com balanceamento de carga e roteamento.
Particionar logicamente um único cluster Kubernetes para múltiplas equipes, projetos ou ambientes.
Crie recursos `Namespace`. Namespaces fornecem um escopo para nomes e uma forma de anexar autorização e políticas (p.ex., ResourceQuotas).
Por quê: Namespaces permitem multi-locação e organização de recursos sem a sobrecarga de múltiplos clusters.
Fornecer um endpoint de rede estável (IP e DNS) para um conjunto de Pods efêmeros.
Defina um recurso `Service` que alveja um conjunto de Pods usando um seletor de rótulos.
Por quê: Pods são efêmeros e seus IPs mudam. Um Service fornece uma abstração durável que balanceia a carga do tráfego para os Pods corretos.
Expor uma aplicação rodando em Pods a diferentes escopos de rede.
Escolha um `type` de Service: `ClusterIP` (apenas interno, padrão), `NodePort` (expõe em cada nó IP:porta), ou `LoadBalancer` (provisiona um balanceador de carga da nuvem).
Por quê: O tipo de Service determina a acessibilidade da aplicação, de puramente interna a totalmente externa.
Permitir a descoberta de rede direta de Pods individuais, ignorando o proxy do Service.
Crie um `Service` com `clusterIP: None`. Isso cria registros DNS A para cada Pod, permitindo que os clientes se conectem diretamente aos Pods.
Por quê: Essencial para aplicações stateful como bancos de dados (frequentemente com StatefulSets) onde a comunicação peer-to-peer ou identidade estável do Pod é necessária.
Organizar e selecionar um subconjunto de objetos Kubernetes.
Anexe `labels` de chave-valor a objetos (p.ex., `app: my-api`). Use `label selectors` em outros objetos (p.ex., Services, Deployments) para selecioná-los.
Por quê: Labels são o principal mecanismo de agrupamento no Kubernetes, permitindo o acoplamento fraco entre recursos.
Desacoplar a configuração da aplicação da imagem do contêiner.
Armazene dados de configuração não sensíveis em um `ConfigMap`. Monte-o como um volume ou injete chaves como variáveis de ambiente em Pods.
Por quê: Isso permite que a configuração seja gerenciada independentemente do código da aplicação, seguindo os princípios do 12-Factor App.
Armazenar dados sensíveis como senhas, tokens ou chaves de API para uso da aplicação.
Use um objeto `Secret`. Monte como um volume ou injete como uma variável de ambiente.
Por quê: Secrets são especificamente para dados sensíveis e tratados de forma mais segura do que ConfigMaps (p.ex., não são exibidos em `kubectl describe` por padrão, podem ser criptografados em repouso).
Fornecer a aplicações stateful armazenamento que sobrevive a reinícios de Pods.
Um Pod cria um `PersistentVolumeClaim` (PVC) para solicitar armazenamento. Um administrador provisiona um `PersistentVolume` (PV) que atende à solicitação.
Por quê: Isso desacopla o consumo de armazenamento (PVC) do provisionamento de armazenamento (PV), permitindo definições de carga de trabalho portáteis.
Gerenciar a alocação de CPU e memória para contêineres.
Defina `resources.requests` para recursos garantidos (usados para agendamento) e `resources.limits` para o uso máximo permitido (imposto em tempo de execução).
Por quê: Requisições garantem que os Pods tenham recursos suficientes para rodar; Limites impedem que os Pods consumam muitos recursos e impactem outras cargas de trabalho.
Definir restrições agregadas de recursos em um namespace.
Crie um objeto `ResourceQuota` para limitar a quantidade total de CPU, memória ou número de objetos (Pods, Services) que podem ser criados em um namespace.
Por quê: ResourceQuotas são essenciais para ambientes multi-tenant para garantir o compartilhamento justo de recursos e prevenir o consumo excessivo.
Gerenciar recursos Kubernetes usando arquivos de configuração versionados.
Use `kubectl apply -f <filename.yaml>`. Este comando cria ou atualiza recursos com base no conteúdo do arquivo.
Por quê: `apply` é declarativo, tornando-o ideal para GitOps e CI/CD. Ele rastreia mudanças e realiza uma fusão de três vias, o que é mais seguro do que os comandos imperativos `create` ou `replace`.
Diagnosticar por que um Pod não está rodando corretamente (p.ex., preso em Pending, ContainerCreating, ou CrashLoopBackOff).
Use `kubectl describe pod <pod-name>`. Verifique a seção `Events` na parte inferior para mensagens detalhadas do agendador, kubelet ou controladores.
Por quê: `describe` fornece um log de eventos cronológico que é a ferramenta principal para depurar problemas do ciclo de vida dos recursos.
Fornecer funcionalidade de rede para contêineres, permitindo a comunicação Pod-a-Pod através do cluster.
Use um plugin Container Network Interface (CNI) (p.ex., Calico, Flannel, Cilium). O kubelet em cada nó usa o plugin CNI para configurar a rede para cada Pod.
Por quê: CNI fornece uma interface padrão, permitindo que o Kubernetes seja integrado com várias soluções de rede sem modificar os componentes centrais.
Controlar o acesso aos recursos da API Kubernetes para usuários e aplicações.
Use Role-Based Access Control (RBAC). Defina um `Role` (com escopo de namespace) ou `ClusterRole` (com escopo de cluster) com permissões, e associe-o a um sujeito (User, Group, ServiceAccount) usando um `RoleBinding` ou `ClusterRoleBinding`.
Por quê: RBAC é o padrão para proteger o Kubernetes, permitindo o princípio do menor privilégio para todas as interações da API.
Gerenciar uma aplicação stateless, permitindo atualizações e rollbacks fáceis.
Use uma carga de trabalho `Deployment`. Ele gerencia ReplicaSets para garantir que um número desejado de réplicas de Pod esteja em execução e fornece estratégias de atualização declarativas.
Por quê: Deployments são o padrão para aplicações stateless, abstraindo os detalhes de escalonamento e atualizações contínuas.
Implantar uma aplicação stateful (p.ex., banco de dados) que requer identidade de rede e armazenamento estáveis.
Use uma carga de trabalho `StatefulSet`. Ela fornece a cada Pod um hostname estável e único e armazenamento persistente que o acompanha em reinícios.
Por quê: Ao contrário dos Deployments, StatefulSets gerenciam Pods com identidade, garantindo implantação e escalonamento ordenados, o que é crítico para sistemas stateful.
Implantar um agente (p.ex., coletor de logs, agente de monitoramento) em cada nó do cluster.
Use uma carga de trabalho `DaemonSet`. Ela garante que uma cópia de um Pod seja executada em cada nó (ou um subconjunto de nós).
Por quê: DaemonSets automatizam a distribuição de serviços em nível de nó, escalonando automaticamente para novos nós à medida que eles se juntam ao cluster.
Executar uma tarefa finita e única que precisa ser concluída.
Use um recurso `Job`. Ele cria um ou mais Pods e garante que eles terminem com sucesso.
Por quê: Jobs são para processamento em lote, ao contrário dos Deployments que são para serviços contínuos. Os Pods não são substituídos após a conclusão bem-sucedida.
Executar uma tarefa em um cronograma recorrente (p.ex., backups noturnos, relatórios).
Use um recurso `CronJob`. Ele cria Jobs com base em uma string de agendamento cron.
Por quê: CronJobs fornecem uma maneira nativa do Kubernetes para gerenciar tarefas recorrentes baseadas em tempo.
Reiniciar automaticamente um contêiner que se tornou não responsivo (p.ex., deadlock).
Configure uma `livenessProbe` na especificação do contêiner. Se a sonda falhar, o kubelet reinicia o contêiner.
Por quê: As sondas de liveness fornecem um poderoso mecanismo de auto-recuperação para aplicações que podem ficar presas em um estado quebrado sem falhar.
Impedir que o tráfego seja enviado para um contêiner que ainda não está pronto para atender requisições.
Configure uma `readinessProbe` na especificação do contêiner. O Pod é adicionado aos endpoints do Service apenas após a sonda ser bem-sucedida.
Por quê: As sondas de readiness são críticas para atualizações contínuas sem tempo de inatividade, garantindo que novos Pods estejam totalmente inicializados antes de receber tráfego de produção.
Executar tarefas de configuração ou esperar que as dependências estejam prontas antes de iniciar o contêiner principal da aplicação.
Defina um ou mais `initContainers` na especificação do Pod. Eles são executados até a conclusão em sequência antes que qualquer contêiner da aplicação inicie.
Por quê: Contêineres de inicialização fornecem uma separação limpa para a lógica de configuração, garantindo que os pré-requisitos sejam atendidos sem sobrecarregar o contêiner principal da aplicação.
Garantir que os Pods sejam agendados em nós com características específicas (p.ex., nós com GPUs, SSDs).
Use `nodeAffinity` na especificação do Pod para definir regras com base em rótulos de nó. Pode ser uma restrição "required" (rígida) ou "preferred" (suave).
Por quê: A afinidade de nó é mais expressiva do que `nodeSelector` e é a maneira moderna de controlar o posicionamento do Pod com base nas propriedades do nó.
Controlar a co-localização de Pods em relação uns aos outros para desempenho ou alta disponibilidade.
Use `podAffinity` para agendar Pods juntos (p.ex., no mesmo nó) ou `podAntiAffinity` para espalhá-los (p.ex., entre diferentes nós ou zonas).
Por quê: A anti-afinidade é crucial para garantir que as réplicas de um serviço não estejam no mesmo domínio de falha, aumentando assim a disponibilidade.
Impedir que Pods de propósito geral sejam agendados em nós dedicados ou de propósito especial.
Aplique um `Taint` a um nó. Pods devem ter uma `Toleration` correspondente em sua especificação para serem agendados naquele nó.
Por quê: Taints e tolerations garantem que os nós sejam reservados para cargas de trabalho que são explicitamente permitidas para rodar lá.
Garantir alta disponibilidade distribuindo Pods uniformemente por domínios de falha como zonas ou nós.
Defina `topologySpreadConstraints` na especificação do Pod para controlar como os Pods são distribuídos com base em rótulos e chaves de topologia (p.ex., `topology.kubernetes.io/zone`).
Por quê: Isso fornece um controle mais granular sobre a HA do que a anti-afinidade de pod, evitando que todas as réplicas sejam concentradas em um único local.
Dimensionar automaticamente o número de réplicas de aplicações com base na carga observada.
Crie um recurso `HorizontalPodAutoscaler` (HPA) que almeja um Deployment e especifica uma métrica (p.ex., utilização de CPU) e valor alvo.
Por quê: O HPA permite escalonamento elástico, garantindo desempenho sob carga e economizando custos durante períodos de baixa atividade, sem intervenção manual.
Adicionar ou remover automaticamente nós de trabalho do cluster para corresponder à demanda de recursos.
Implante o `Cluster Autoscaler`. Ele observa Pods que não podem ser agendados (devido à escassez de recursos) e adiciona nós, ou remove nós subutilizados.
Por quê: O Cluster Autoscaler gerencia a elasticidade em nível de infraestrutura, trabalhando com provedores de nuvem para ajustar o tamanho do cluster com base nas necessidades da carga de trabalho.
Garantir que um número mínimo de réplicas de aplicações permaneça disponível durante interrupções voluntárias (p.ex., atualizações de nó).
Crie um `PodDisruptionBudget` (PDB) especificando `minAvailable` ou `maxUnavailable` para um conjunto de Pods.
Por quê: PDBs impedem que ações como `kubectl drain` derrubem muitas réplicas de uma vez, protegendo a disponibilidade da aplicação.
Realizar uma atualização sem tempo de inatividade para uma aplicação stateless.
Use um `Deployment` com a estratégia `RollingUpdate` padrão. Configure `maxSurge` e `maxUnavailable` para controlar o processo de atualização.
Por quê: Atualizações contínuas substituem gradualmente os Pods antigos por novos, garantindo que o serviço permaneça disponível durante toda a atualização.
Entrega de Aplicações Cloud Native
Gerenciar implantações de infraestrutura e aplicações declarativamente com controle de versão e trilha de auditoria.
Implemente GitOps. Use um repositório Git como a única fonte de verdade. Use uma ferramenta como Argo CD ou Flux para sincronizar automaticamente o estado do cluster com o Git.
Por quê: GitOps fornece um histórico claro e auditável de todas as mudanças e permite rollbacks fáceis revertendo commits do Git. Ele operacionaliza Infraestrutura como Código.
Empacotar, configurar e implantar aplicações Kubernetes complexas de forma reutilizável e versionada.
Use `Helm`, o gerenciador de pacotes para Kubernetes. Empacote aplicações como `Charts` com manifestos templated e arquivos `values.yaml` configuráveis.
Por quê: Helm simplifica o gerenciamento de aplicações complexas com muitos componentes, lidando com dependências, versionamento e gerenciamento de ciclo de vida.
Personalizar manifestos Kubernetes para diferentes ambientes sem usar templates.
Use `Kustomize`. Defina um arquivo `kustomization.yaml` que especifica uma configuração base e aplica patches ou overlays para cada ambiente.
Por quê: Kustomize oferece uma maneira declarativa e sem templates para gerenciar variantes de configuração, o que pode ser mais simples e menos propenso a erros do que a templating baseada em texto.
Testar uma nova versão da aplicação com um pequeno subconjunto do tráfego de produção antes de uma implantação completa.
Implante a nova versão junto com a antiga. Use uma service mesh ou um Ingress controller para rotear uma pequena porcentagem do tráfego (p.ex., 5%) para a nova versão "canary".
Por quê: Lançamentos Canary reduzem o risco de introduzir um lançamento ruim, limitando o raio de impacto e permitindo testes em produção.
Implantar uma nova versão da aplicação com tempo de inatividade zero e capacidade de rollback instantâneo.
Implante a nova versão "verde" junto com a versão "azul" existente. Uma vez que a versão verde é verificada, alterne 100% do tráfego da azul para a verde no nível do Service/roteador.
Por quê: Implantações blue-green eliminam o tempo de inatividade. O rollback é tão simples quanto reverter o tráfego para o ambiente azul.
Arquitetura Cloud Native
Projetar uma aplicação complexa como uma coleção de serviços pequenos, independentes e pouco acoplados.
Estruture a aplicação como microsserviços, cada um organizado em torno de uma capacidade de negócio. Cada serviço deve possuir seus próprios dados e se comunicar via APIs bem definidas.
Por quê: Esta arquitetura permite o desenvolvimento, implantação e escalonamento independentes de serviços, melhorando a agilidade e a resiliência.
Construir uma aplicação portátil, escalável e cloud-native seguindo as melhores práticas estabelecidas.
Siga a metodologia do Twelve-Factor App. Um princípio chave é armazenar toda a configuração que varia entre ambientes em variáveis de ambiente.
Por quê: Isso separa estritamente a configuração do código, permitindo que a mesma imagem de contêiner seja promovida entre ambientes sem alterações.
Gerenciar comunicação complexa serviço-a-serviço, fornecendo gerenciamento de tráfego, segurança e observabilidade.
Implemente uma service mesh (p.ex., Istio, Linkerd). Ela injeta um proxy sidecar em cada Pod para interceptar e gerenciar todo o tráfego de rede.
Por quê: Uma service mesh abstrai preocupações de rede (mTLS, retentativas, circuit breaking) do código da aplicação, aplicando-as no nível da plataforma.
Estender ou aprimorar a funcionalidade de um contêiner de aplicação sem modificar seu código.
Implante um contêiner "sidecar" no mesmo Pod que a aplicação principal. Ele compartilha a mesma rede e armazenamento.
Por quê: Sidecars são usados para preocupações transversais como logging, monitoramento ou proxy (como em uma service mesh), promovendo a separação de preocupações.
Obter insights profundos sobre o comportamento de um sistema distribuído para facilitar a solução de problemas.
Implementar os três pilares da observabilidade: `Metrics` (dados numéricos agregados), `Logs` (eventos discretos) e `Traces` (fluxos de requisição de ponta a ponta).
Por quê: Juntos, esses tipos de dados fornecem uma visão abrangente da saúde e desempenho do sistema, o que é essencial para arquiteturas de microsserviços complexas.