Pular para o conteúdo principal

Resource Requirements e Limits

Pods sempre consomem recursos físicos como memória e CPU dos Nodes que ele está executando. O Scheduler não consegue direcionar um Pod para um Node que não tem recurso suficiente para executá-lo. Porém mais de um Node pode ter recurso suficiente para rodar um Pod e cabe ao Scheduler decidir para onde ele vai.

Para filtrar quais os possíveis Nodes, primeiro é levado em consideração:

    • taints e toleration
    • nodeSelector
    • Affinity
    • resources

Os três primeiros irão filtrar os possíveis Nodes que poderiam receber os Pods. Dentre os possíveis, o Scheduler irá criar um score para cada um deles baseado nos recursos disponíveis para escolher qual é melhor para receber o Pod.

Se nenhum Node tem recursos para receber o Pod, este ficará com o status de Pending.

Alt text

Uma observação importante é que cada Container dentro de um Pod pode ter seus recursos definidos individualmente. Os recursos não são atribuídos ao Pod como um todo, mas sim a cada Container que é executado dentro do Pod. Ao somar os recursos de todos os Containers dentro de um Pod obtemos o total de recursos do Pod. No entanto é o Scheduler do Kubernetes que realiza essa atribuição de recursos, considerando as necessidades de cada Container.

De fato, não faria sentido atribuir recursos diretamente ao Pod, pois o Scheduler precisa entender e distribuir os recursos de forma adequada entre os diferentes Containers que compõem o Pod.

Por padrão um Container não tem nenhum limite definido, ou seja, PODE CONSUMIR UM NODE INTEIRO.

apiVersion: v1
kind: Pod
...
spec:
containers:
- name: busybox
image: busybox
resources:
## requests são os recursos garantidos para o container
requests:
memory: "32Mi"
cpu: "100m"
## Limits é até onde um container pode se extender
limits:
memory: "128Mi"
cpu: "500m"
- name: nginx
image: nginx
resources:
# Se não for definido o requests ele será igual o limits
limits:
memory: "128Mi"
cpu: "500m"

Entendendo os valores.

O menor valor para cpu é 0.1 = 100m (m=mili) 1 representaria 1 vcpu ou seja, um core de cpu.

Para memória podemos ver a tabela para conhecimento, mas o que nos interessa é M (Megabytes )e G (Gigabyte) Usando G estamos usando a base decimal enquanto Gi usa a base binária.

Alt text

1.074G seria igual a 1Gi 1.048M seria igual a 1Mi

Um aspecto a considerar é que um container não opera constantemente em sua capacidade máxima. A demanda por recursos, como memória e CPU, podem variar ao longo do tempo conforme o processo executado pelo container necessitar de mais ou menos recursos.

Quando recursos adicionais estão disponíveis, o processo pode aproveitá-los para otimizar seu desempenho. No entanto, essa abordagem pode levar a uma situação em que outros processos no node, incluindo aqueles do sistema operacional do próprio node e containers de outros pods, acabam sendo prejudicados devido à alocação excessiva de recursos por parte do container em questão.

Para evitar isso podemos definir os limites para frear esse crescimento.

No caso da CPU, o nó é capaz de limitar efetivamente o consumo do contêiner para não exceder a quantidade necessária. No entanto, no que se refere à memória, essa imposição de limite não é tão eficaz. Se um contêiner tenta exceder o limite de memória estabelecido, a ação geralmente é encerrar o pod para evitar que ele continue crescendo e afete o desempenho de outros recursos, resultando no evento "Out of Memory" (OOO).

Cenários:

  • Rodar sem requestes e sem limites não é boa prática e permite o sufocamento.
  • Rodar com limits sem request seria o mesmo que sub utilizar recursos disponíveis se existirem.
  • Rodar com requests e limites te dá um controle mas ainda vamos sub utilizar recursos se estivem disponíveis.
  • Rodar com requests garante o mínimo para o pod e permite que ele cresça. Mas nesse caso se todos os pods tiverem o request definido, eles tem garantia mínima dos seus recursos. Esse é o cenário ideal.

Geralmente usamos limits para evitar o mau uso da infra estrutura.

Alt text

Como definir um valor padrão para todos os containers de todos os pods dentro de um namespace?

Um LimitRange fornece restrições que podem:

  • Impor o uso mínimo e máximo de recursos de computação por pod ou contêiner em um namespace.
  • Aplicar solicitação de armazenamento mínimo e máximo por PersistentVolumeClaim em um espaço para nome.
  • Impor uma proporção entre request e limits para um recurso em um namespace.
  • Definir request/limits padrão para recursos de computação em um namespace e injete-os automaticamente em contêineres em tempo de execução.

Alt text

Se pods já estiverem rodando e um LimitRange for criado depois, somente novos pods terão esses valores setados automaticamente.

Se quisermos limitar todo o recurso de um namespace perante o cluster usaríamos ResourcesQuotas.

Alt text