Um cluster Kubernetes é um ambiente compartilhado para o processamento de aplicações de diversas equipes. Para que os picos de consumo de CPU e memória de uma aplicação não degrade a performance de outra aplicação rodando em um mesmo node, é necessário que seja aplicado limites.

Além disto, para que seja possível garantir que os recursos mínimos estejam disponíveis em um node para rodar uma determinada aplicação, é necessário o uso de requests.

Por isso, é muito comum vermos nos Charts Helm e no YAML dos deployments configurações como estas:

resources:
   limits:
     cpu: 200m
     memory: 512Mi
   requests:
     cpu: 100m
     memory: 256Mi

O problema é que o mal dimensionamento destas configurações podem gerar dois cenários:

  • requisições de CPU e memória altos podem aumentar o custo da fatura da AWS, pois mais nodes EKS irão ser provisionados desnecessariamente para evitar que os pods fiquem em estado de Pending.

  • limites de CPU e memória inferior ao consumo médio esperado pela aplicação podem causar degradação da performance (gerando problemas como CPU Throttling e Out of Memory).

Exemplo de requests potencialmente mal dimensionado:

resources:
   limits:
     cpu: 3000m
     memory: 4Gi
   requests:
     cpu: 3000m
     memory: 4Gi

Isto exigirá um node com 4GiB de memória livre e 3 cores ociosas só para sua aplicação. Certamente seu microsserviço precisará de muito menos que isto, certo?

Exemplo de request melhor dimensionado:

resources:
   limits:
     cpu: 200m
     memory: 256Mi
   requests:
     cpu: 100m
     memory: 192Mi

Agora o cenário está mais otimizado: a aplicação exigirá no mínimo 192MiB de memória livre e 10% de 1 core ocioso.

Mas como saber quais requests de CPU e memória devemos ajustar nas nossas aplicações?

Recomendações do Kubecost

O Kubecost é uma ferramenta com interface Web que consome a API do Kubernetes e a API Pública de Pricing da AWS para mensurar os custos de um cluster EKS e disponibilizar recomendações de ajustes de limits e requests.

Na página principal do Kubecost ele te apresenta uma série de valores que ele mensurou. Um valor interessante a se destacar é a eficiência:

A “eficiência” é a relação do recurso requisitado, com o recurso consumido, e o preço deste recurso provisionado na AWS. Quanto maior a eficiência, melhor!
A “eficiência” é a relação do recurso requisitado, com o recurso consumido, e o preço deste recurso provisionado na AWS. Quanto maior a eficiência, melhor!

Quando a eficiência de um cluster EKS está próximo de 100%, isto indica um bom uso dos nodes provisionados. Devemos nos esforçar para subir cada vez mais esta eficiência.

Vejamos um exemplo de melhoria da eficiência de apps do namespace “monitoring”:

1° - clique em “Savings“ no menu esquerdo.
1° - clique em “Savings“ no menu esquerdo.
2° - clique em “Request right-sizing recommendations“.
2° - clique em “Request right-sizing recommendations“.
3° - na tela que se abrir, clique no botão “Customize“ para filtrar por recomendações de objetos k8s de um namespace específico.
3° - na tela que se abrir, clique no botão “Customize“ para filtrar por recomendações de objetos k8s de um namespace específico.
4º - no modal que se abrir, clique em “Filters“ > “namespace“.
4º - no modal que se abrir, clique em “Filters“ > “namespace“.
5º - preencha o campo de texto com o nome do namespace que você quer filtrar. Em seguida clique no botão de +.
5º - preencha o campo de texto com o nome do namespace que você quer filtrar. Em seguida clique no botão de +.
6º - clique no botão de “Save”.
6º - clique no botão de “Save”.
7º - na próxima tela será mostrado a eficiência dos objetos k8s e suas respectivas recomendações de requests de CPU e memória. No caso do print, os três últimos deployments apresentaram eficiência de 100%, mas os três primeiros não!
7º - na próxima tela será mostrado a eficiência dos objetos k8s e suas respectivas recomendações de requests de CPU e memória. No caso do print, os três últimos deployments apresentaram eficiência de 100%, mas os três primeiros não!

Na tela acima temos recomendações de ajustes de três componentes. Vamos acessar o YAML destes DaemonSets e Deployments e aplicar os ajustes recomendados. Por exemplo:

monitoring\daemonset\newrelic-infra antes:

   resources:                                   
     limits:                                    
       memory: 300M                               
     requests:                              
       cpu: 100m                           
       memory: 150M

monitoring\daemonset\newrelic-infra depois:

   resources:                                            
     limits:                                            
       memory: 300M                          
     requests:
       cpu: 85m                                      
       memory: 95M

Após os ajustes, demorará cerca de 3 horas para o Kubecost reavaliar as alterações. Depois de reavaliado, verifique novamente a eficiência dos objetos k8s.