TL;DR: Nesta postagem, você aprenderá a escolher o melhor nó para seu cluster do Kubernetes antes de escrever qualquer código.
Quando você cria um cluster do Kubernetes, uma das primeiras perguntas que você pode ter é: "Que tipo de nós de trabalho devo usar e quantos deles?"
Ou, se estiver usando um serviço gerenciado do Kubernetes, como o Linode Kubernetes Engine (LKE), você deve usar oito instâncias do Linode de 2 GB ou duas do Linode de 8 GB para atingir a capacidade de computação desejada?
Primeiro, nem todos os recursos nos nós de trabalho podem ser usados para executar cargas de trabalho.
Reservas de nós do Kubernetes
Em um nó do Kubernetes, a CPU e a memória são divididas em:
- Sistema operacional
- Kubelet, CNI, CRI, CSI (e daemons do sistema)
- Pods
- Limite de despejo
Vamos dar um exemplo rápido.
Imagine que você tenha um cluster com uma única instância de computação Linode de 2 GB, ou 1 vCPU e 2 GB de RAM.
Os seguintes recursos são reservados para o kubelet e o sistema operacional:
- -500 MB de memória.
- -60 m de CPU.
Além disso, 100 MB são reservados para o limite de despejo.
No total, são 30% da memória e 6% da CPU que você não pode usar.
Cada provedor de nuvem tem sua maneira de definir os limites, mas, para a CPU, todos parecem concordar com os seguintes valores:
- 6% do primeiro núcleo;
- 1% do próximo núcleo (até 2 núcleos);
- 0,5% dos próximos 2 núcleos (até 4); e
- 0,25% de todos os núcleos acima de quatro núcleos.
Quanto aos limites de memória, isso varia muito entre os provedores.
Mas, em geral, a reserva segue esta tabela:
- 25% dos primeiros 4 GB de memória;
- 20% dos seguintes 4 GB de memória (até 8 GB);
- 10% dos seguintes 8 GB de memória (até 16 GB);
- 6% dos próximos 112 GB de memória (até 128 GB); e
- 2% de qualquer memória acima de 128 GB.
Agora que você sabe como os recursos são repartidos dentro de um nó de trabalho, é hora de fazer a pergunta complicada: qual instância você deve escolher?
Como pode haver muitas respostas corretas, vamos restringir nossas opções, concentrando-nos no melhor nó de trabalho para sua carga de trabalho.
Aplicativos de criação de perfil
No Kubernetes, você tem duas maneiras de especificar a quantidade de memória e CPU que um contêiner pode usar:
- As solicitações geralmente correspondem ao consumo do aplicativo em operações normais.
- Os limites definem o número máximo de recursos permitidos.
O agendador do Kubernetes usa solicitações para determinar onde o pod deve ser alocado no cluster. Como o agendador não conhece o consumo (o pod ainda não foi iniciado), ele precisa de uma dica. Essas "dicas" são solicitações; você pode ter uma para a memória e outra para a CPU.
O kubelet usa limites para interromper o processo quando ele usa mais memória do que o permitido. Ele também limita o processo se ele usar mais tempo de CPU do que o permitido.
Mas como você escolhe os valores corretos para solicitações e limites?
Você pode medir o desempenho de sua carga de trabalho (ou seja, média, percentil 95 e 99, etc.) e usá-los como solicitações e limites. Para facilitar o processo, duas ferramentas convenientes podem acelerar a análise:
O VPA coleta os dados de utilização da memória e da CPU e executa um algoritmo de regressão que sugere solicitações e limites para sua implantação. É um projeto oficial do Kubernetes e também pode ser instrumentado para ajustar os valores automaticamente -você pode fazer com que o controlador atualize as solicitações e os limites diretamente em seu YAML.
O KRR funciona de forma semelhante, mas aproveita os dados que você exporta via Prometheus. Como primeira etapa, suas cargas de trabalho devem ser instrumentadas para exportar métricas para Prometheus. Depois de armazenar todas as métricas, você pode usar o KRR para analisar os dados e sugerir solicitações e limites.
Depois de ter uma ideia dos requisitos (aproximados) de recursos, você pode finalmente selecionar um tipo de instância.
Seleção de um tipo de instância
Imagine que você estima que sua carga de trabalho requer 2 GB de solicitações de memória e que precisa de pelo menos 10 réplicas.
Você já pode descartar a maioria das instâncias pequenas com menos de `2GB * 10 = 20GB`. Neste ponto, você pode adivinhar uma instância que poderia funcionar bem: vamos escolher o Linode 32GB.
Em seguida, você pode dividir a memória e a CPU pelo número máximo de pods que podem ser implantados nessa instância (ou seja, 110 em LKE) para obter uma unidade discreta de memória e CPU.
Por exemplo, as unidades de CPU e memória para o Linode 32 GB são:
- 257 MB para a unidade de memória (ou seja, (32 GB - 3,66 GB reservados) / 110)
- 71 m para a unidade da CPU (ou seja, (8000 m - 90 m reservados) / 110)
Excelente! Na última (e última) etapa, você pode usar essas unidades para estimar quantas cargas de trabalho cabem no nó.
Supondo que você queira implantar um Spring Boot com solicitações de 6 GB e 1 vCPU, isso se traduz em:
- O menor número de unidades que cabe em 6 GB é 24 unidades (24 * 257 MB = 6,1 GB)
- O menor número de unidades que cabe em 1 vCPU é 15 unidades (15 * 71m = 1065m)
Os números sugerem que você ficará sem memória antes de ficar sem CPU, e você pode ter no máximo (110/24) 4 aplicativos implantados no cluster.
Quando você executa quatro cargas de trabalho nessa instância, você usa:
- 24 unidades de memória \* 4 = 96 unidades e 14 não são utilizadas (~12%)
- 15 unidades vCPU \* 4 = 60 unidades e 50 não são utilizadas (~45%)
Não é ruim, mas podemos fazer melhor?
Vamos tentar com uma instância Linode de 64 GB (64 GB / 16 vCPU).
Supondo que você queira implantar o mesmo aplicativo, os números mudam para:
- Uma unidade de memória tem aproximadamente 527 MB (ou seja, (64 GB - 6,06 GB reservados) / 110).
- Uma unidade de CPU tem ~145m (ou seja, (16000m - 110m reservados) / 110).
- O menor número de unidades que cabe em 6 GB é 12 unidades (12 * 527 MB = 6,3 GB).
- O menor número de unidades que cabe em uma vCPU é 7 unidades (7 * 145m = 1015m).
Quantas cargas de trabalho você pode colocar nessa instância?
Como você terá o máximo de memória e cada carga de trabalho requer 12 unidades, o número máximo de aplicativos é 9 (ou seja, 110/12)
Se você computar a eficiência/desperdício, verá que:
- 12 unidades de memória \* 9 = 108 unidades e 2 não são utilizadas (~2%)
- 7 unidades vCPU \* 9 = 63 unidades e 47 não são utilizadas (~42%)
Embora os números da CPU desperdiçada sejam quase idênticos aos da instância anterior, a utilização da memória melhorou drasticamente.
Finalmente, podemos comparar os custos:
- A instância de 32 GB do Linode pode acomodar no máximo 4 cargas de trabalho. Na capacidade total, cada pod custa US$ 48/mês (ou seja, US$ 192 de custo da instância dividido por quatro cargas de trabalho).
- *A instância do Linode de 64 GB pode acomodar até 9 cargas de trabalho. Na capacidade total, cada pod custa US$ 42,6/mês (ou seja, US$ 384 de custo da instância dividido por nove cargas de trabalho).
Em outras palavras, escolher o tamanho de instância maior pode economizar até US$ 6 por mês por carga de trabalho. Excelente!
Comparação de nós usando a calculadora
Mas e se você quiser testar mais instâncias? Fazer esses cálculos dá muito trabalho.
Acelere o processo usando a calculadora learnk8s.
A primeira etapa para usar a calculadora é inserir suas solicitações de memória e CPU. O sistema calcula automaticamente os recursos reservados e sugere a utilização e os custos. Há alguns recursos úteis adicionais: atribua solicitações de CPU e memória próximas ao uso do aplicativo. Se o aplicativo ocasionalmente apresentar uma explosão de uso maior da CPU ou da memória, não há problema.
Mas o que acontece quando todos os pods usam todos os recursos até o limite?
Isso pode levar a um excesso de comprometimento. O widget no centro fornece uma porcentagem de excesso de comprometimento da CPU ou da memória.
O que acontece quando você se compromete demais?
- Se você fizer um comprometimento excessivo de memória, o kubelet expulsará os pods e os moverá para outro lugar no cluster.
- Se você se comprometer em excesso com a CPU, as cargas de trabalho usarão a CPU disponível proporcionalmente.
Por fim, você pode usar o widget DaemonSets e Agent, um mecanismo conveniente para modelar pods que são executados em todos os seus nós. Por exemplo, o LKE tem o plug-in Cilium e CSI implantado como DaemonSets. Esses pods usam recursos que não estão disponíveis para suas cargas de trabalho e devem ser subtraídos dos cálculos. O widget permite que você faça exatamente isso!
Sumário
Neste artigo, você mergulhou em um processo sistemático para definir o preço e identificar os nós de trabalho para o cluster LKE.
Você aprendeu como o Kubernetes reserva recursos para os nós e como pode otimizar seu cluster para tirar proveito disso. Quer saber mais? Registre-se para ver isso em ação com nosso webinar em parceria com os serviços de computação em nuvem da Akamai.
Comentários