Aqui na Lambda3, é muito comum publicarmos aplicações em clusters de kubernetes compartilhados entre uma organização inteira. Por isso temos que lidar diretamente com o gerenciamento de consumo de recursos dessas aplicações.

Recentemente atuei em um time que estava utilizando um namespace no cluster de k8s para realizar processamento massivo de dados,conforme o projeto foi crescendo, começamos a criar diversas apis + processos até que tínhamos por volta de uns 20 pods apenas para esse sistema e todos com seus requests e limits setados. Entretanto, como não éramos responsáveis pelo gerenciamento do cluster, não sabíamos o que isso poderia impactar em outras aplicações e vimos a necessidade de estimar um limite inicial para o sistema/namespace para já deixar acordado com a área de infraestrutura e que caso o sistema precisasse de mais recursos, marcaríamos uma conversa com a equipe para apresentar os possíveis cenários de custos e etc.

A preocupação veio devido ao cenário de nesse mesmo cluster o cliente ter outras aplicações que poderiam ter seus desempenhos degradados devido aos diversos processos que vários times estavam publicando nesse cluster e nesse post, vou mostrar uma forma de limitar o uso de recursos por namespace, permitindo que o planejamento de recursos do cluster seja antecipado aos problemas que podem acontecer.

Prática

Executei os comandos abaixo no kubernetes que vem junto com o docker desktop pra facilitar a reprodução.

A primeira coisa que precisamos criar é um objeto chamado Resource Quota em nosso cluster:

kubectl create -n default -f- <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: limitacao-recursos
spec:
hard:
requests.cpu: "50m"
limits.cpu: "100m"
EOF

view raw
resource-quota.sh
hosted with ❤ by GitHub

Depois disso, vamos criar um pod que pede mais recurso do que o resource quota permite no namespace “default”:

kubectl create -n default -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
name: teste-recursos
spec:
containers:
– name: teste-recursos
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Executando ; sleep 10000']
resources:
requests:
cpu: "100m"
limits:
cpu: "200m"
restartPolicy: Never
EOF

view raw
pod1.sh
hosted with ❤ by GitHub

Ao aplicar o pod, o kubernetes nos dá um erro dizendo que os recursos ultrapassam o valor permitido:

kubectl apply -f .\pod.yaml -n teste
Error from server (Forbidden): error when creating ".\\pod.yaml": pods "teste-recursos" is forbidden: exceeded quota: limitacao-recursos, requested: limits.cpu=200m,requests.cpu=100m, used: limits.cpu=0,requests.cpu=0, limited: limits.cpu=100m,requests.cpu=50m

Vamos alterar o valor dos recursos do pod para ficar menor/igual ao valor que definimos no resource quota:

kubectl create -n default -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
name: teste-recursos
spec:
containers:
– name: teste-recursos
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Executando ; sleep 10000']
resources:
requests:
cpu: "50m"
limits:
cpu: "100m"
restartPolicy: Never
EOF

view raw
pod2.sh
hosted with ❤ by GitHub

kubectl apply -f .\pod.yaml -n default
pod/teste-recursos created

Rodando um describe no resource quota, vemos a quantidade de recursos que estão sendo usados no namespace:

kubectl describe resourcequota limitacao-recursos -n default
Name: limitacao-recursos
Namespace: default
Resource Used Hard
-------- ---- ----
limits.cpu 100m 100m
requests.cpu 50m 50m

Com o retorno acima, vemos que estamos usando a capacidade máxima do que definimos para o namespace. “Used” é a coluna que representa o que todos os recursos do namespace estão utilizando e a coluna hard são os valores limite que definimos no resource quota.

Com esse recurso, podemos definir por exemplo que um determinado projeto pode consumir até 10gb de memória e quando chegar um número de pods que seus requisitos de memória excedam esses 10gb o kubernetes retornará erro como acima, dizendo que não é possível alocar o pod no cluster e é onde deverão acontecer conversas para entender o custo para adicionar mais nós ou aumentar os recursos do cluster.

Espero ter ajudado, até a próxima.