As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Nodes versus taxa de rotatividade
Muitas vezes, quando discutimos a escalabilidade do Kubernetes, fazemos isso em termos de quantos nós existem em um único cluster. Curiosamente, essa raramente é a métrica mais útil para entender a escalabilidade. Por exemplo, um cluster de 5.000 nós com um número grande, mas fixo, de pods não colocaria muito estresse no plano de controle após a configuração inicial. No entanto, se pegássemos um cluster de 1.000 nós e tentássemos criar 10.000 trabalhos de curta duração em menos de um minuto, isso colocaria uma grande pressão contínua no plano de controle.
O simples uso do número de nós para entender o dimensionamento pode ser enganoso. É melhor pensar em termos da taxa de mudança que ocorre em um período de tempo específico (vamos usar um intervalo de 5 minutos para essa discussão, pois é isso que as consultas do Prometheus normalmente usam por padrão). Vamos explorar por que enquadrar o problema em termos da taxa de mudança pode nos dar uma ideia melhor do que ajustar para alcançar a escala desejada.
Pensando em consultas por segundo
O Kubernetes tem vários mecanismos de proteção para cada componente — o Kubelet, o Scheduler, o Kube Controller Manager e o servidor de API — para evitar sobrecarregar o próximo elo na cadeia do Kubernetes. Por exemplo, o Kubelet tem um sinalizador para acelerar as chamadas para o servidor da API em uma determinada taxa. Esses mecanismos de proteção geralmente, mas nem sempre, são expressos em termos de consultas permitidas por segundo ou QPS.
É preciso ter muito cuidado ao alterar essas configurações de QPS. A remoção de um gargalo, como as consultas por segundo em um Kubelet, terá um impacto em outros componentes posteriores. Isso pode e sobrecarregará o sistema acima de uma certa taxa, portanto, entender e monitorar cada parte da cadeia de serviços é fundamental para escalar com sucesso as cargas de trabalho no Kubernetes.
nota
O servidor da API tem um sistema mais complexo com a introdução da API Priority and Fairness, que discutiremos separadamente.
nota
Cuidado, algumas métricas parecem adequadas, mas na verdade estão medindo outra coisa. Por exemplo, kubelet_http_inflight_requests
está relacionado apenas ao servidor de métricas no Kubelet, não ao número de solicitações do Kubelet para solicitações do apiserver. Isso pode fazer com que configuremos incorretamente o sinalizador QPS no Kubelet. Uma consulta nos registros de auditoria de um Kubelet específico seria uma maneira mais confiável de verificar as métricas.
Dimensionamento de componentes distribuídos
Como o EKS é um serviço gerenciado, vamos dividir os componentes do Kubernetes em duas categorias: componentes gerenciados pela AWS, que incluem etcd, Kube Controller Manager e Scheduler (na parte esquerda do diagrama), e componentes configuráveis pelo cliente, como o Kubelet, o Container Runtime e os vários operadores que chamam a AWS, APIs como os drivers de rede e armazenamento (na parte direita do diagrama). Deixamos o servidor da API no meio, mesmo que ele seja gerenciado pela AWS, pois as configurações de prioridade e justiça da API podem ser definidas pelos clientes.

Gargalos a montante e a jusante
À medida que monitoramos cada serviço, é importante analisar as métricas em ambas as direções para identificar gargalos. Vamos aprender como fazer isso usando o Kubelet como exemplo. O Kubelet fala tanto com o servidor da API quanto com o tempo de execução do contêiner; como e o que precisamos monitorar para detectar se algum componente está enfrentando algum problema?
Quantos pods por Node
Quando analisamos os números de escala, como quantos pods podem ser executados em um nó, podemos considerar os 110 pods por nó que o upstream suporta pelo valor nominal.
No entanto, sua carga de trabalho provavelmente é mais complexa do que a que foi testada em um teste de escalabilidade no Upstream. Para garantir que possamos atender ao número de pods que queremos executar na produção, vamos garantir que o Kubelet esteja “acompanhando” o tempo de execução do Containerd.

Para simplificar demais, o Kubelet está obtendo o status dos pods a partir do tempo de execução do contêiner (no nosso caso, Containerd). E se tivéssemos muitos pods mudando de status muito rapidamente? Se a taxa de alteração for muito alta, as solicitações [para o tempo de execução do contêiner] podem expirar.
nota
O Kubernetes está em constante evolução. Atualmente, esse subsistema está passando por mudanças. https://github.com/kubernetes/aprimoramentos/problemas/3386


No gráfico acima, vemos uma linha plana indicando que acabamos de atingir o valor de tempo limite da métrica de duração da geração de eventos do ciclo de vida do pod. Se você quiser ver isso em seu próprio cluster, você pode usar a seguinte sintaxe do PromQL.
increase(kubelet_pleg_relist_duration_seconds_bucket{instance="$instance"}[$__rate_interval])
Se testemunharmos esse comportamento de tempo limite, sabemos que empurramos o nó para além do limite de que ele era capaz. Precisamos corrigir a causa do tempo limite antes de prosseguir. Isso pode ser feito reduzindo o número de pods por nó ou procurando erros que possam estar causando um alto volume de novas tentativas (afetando assim a taxa de rotatividade). A conclusão importante é que as métricas são a melhor maneira de entender se um nó é capaz de lidar com a taxa de rotatividade dos pods atribuídos versus usar um número fixo.
Escala por métricas
Embora o conceito de usar métricas para otimizar sistemas seja antigo, ele geralmente é esquecido quando as pessoas iniciam sua jornada no Kubernetes. Em vez de focar em números específicos (ou seja, 110 pods por nó), concentramos nossos esforços em encontrar as métricas que nos ajudam a encontrar gargalos em nosso sistema. Compreender os limites corretos para essas métricas pode nos dar um alto grau de confiança de que nosso sistema está configurado de maneira ideal.
O impacto das mudanças
Um padrão comum que pode nos causar problemas é focar na primeira métrica ou erro de registro que pareça suspeito. Quando vimos que o Kubelet estava atingindo o tempo limite mais cedo, pudemos tentar coisas aleatórias, como aumentar a taxa por segundo que o Kubelet tem permissão para enviar, etc. No entanto, é aconselhável analisar o quadro geral de tudo o que está relacionado ao erro que encontramos primeiro. Faça cada alteração com um propósito e apoiada por dados.
A jusante do Kubelet estaria o tempo de execução do Containerd (erros de pod), DaemonSets como o driver de armazenamento (CSI) e o driver de rede (CNI) que se comunicam com a API, etc. EC2

Vamos continuar nosso exemplo anterior de que o Kubelet não acompanha o tempo de execução. Há vários pontos em que podemos empacotar um nó com tanta densidade que ele desencadeie erros.

Ao projetar o tamanho certo do nó para nossas cargas de trabalho, esses são easy-to-overlook sinais que podem estar colocando uma pressão desnecessária no sistema, limitando nossa escala e desempenho.
O custo de erros desnecessários
Os controladores Kubernetes são excelentes em tentar novamente quando surgem condições de erro, mas isso tem um custo. Essas novas tentativas podem aumentar a pressão sobre componentes como o Kube Controller Manager. É um importante fator do teste de escala monitorar esses erros.
Quando menos erros estão ocorrendo, é mais fácil identificar problemas no sistema. Ao garantir periodicamente que nossos clusters estejam livres de erros antes de grandes operações (como atualizações), podemos simplificar os registros de solução de problemas quando eventos imprevistos acontecem.
Expandindo nossa visão
Em clusters de grande escala com milhares de nós, não queremos procurar gargalos individualmente. No PromQL, podemos encontrar os valores mais altos em um conjunto de dados usando uma função chamada topk; sendo K uma variável, colocamos o número de itens que queremos. Aqui, usamos três nós para ter uma ideia se todos os Kubelets no cluster estão saturados. Estamos analisando a latência até agora, agora vamos ver se o Kubelet está descartando eventos.
topk(3, increase(kubelet_pleg_discard_events{}[$__rate_interval]))
Detalhando essa declaração.
-
Usamos a variável Grafana
$__rate_interval
para garantir que ela receba as quatro amostras necessárias. Isso ignora um tópico complexo no monitoramento com uma variável simples. -
topk
nos dê apenas os melhores resultados e o número 3 limita esses resultados a três. Essa é uma função útil para métricas em todo o cluster. -
{}
diga-nos que não há filtros; normalmente, você colocaria o nome do trabalho de qualquer regra de raspagem; no entanto, como esses nomes variam, deixaremos em branco.
Dividindo o problema pela metade
Para resolver um gargalo no sistema, usaremos a abordagem de encontrar uma métrica que mostre que há um problema a montante ou a jusante, pois isso nos permite dividir o problema pela metade. Também será um princípio fundamental de como exibimos nossos dados de métricas.
Um bom lugar para começar com esse processo é o servidor da API, pois ele nos permite ver se há algum problema com um aplicativo cliente ou com o plano de controle.