TL;DR
Request e limit fazem coisas diferentes. O request é o que o scheduler reserva para o pod ao escolher o nó; o limit é o teto que o kernel aplica ao container. Em CPU, passar do limit não mata: o container é limitado (throttling). Medimos um container com limit de 200m tentando usar tudo: ficou em 201m e foi limitado em 809 de 810 períodos de 100 ms. Em memória, passar do limit é OOMKilled. Dimensione o request pelo uso típico e o limit de memória acima do pico, ambos medidos por pelo menos uma semana, e confira a classe de QoS que resulta.
Quem usa o quê
| Request | Limit | |
|---|---|---|
| Quem usa | scheduler, na escolha do nó | kernel (cgroup), no container rodando |
| CPU acima dele | permitido, se o nó tiver folga | throttling: o container espera |
| Memória acima dele | permitido; entra na conta da eviction | OOMKilled, exit 137 |
| Sem valor | se houver limit, copia o limit | sem teto: pode usar o nó inteiro |
Fonte: documentação do Kubernetes, "Resource Management for Pods and Containers". A soma dos requests do nó é o que decide se um pod novo cabe; um nó ocioso com requests esgotados deixa o pod em Pending.
CPU: o limit segura, mesmo com o nó livre
Um container em loop infinito, com request de 100m e limit de 200m, num nó de 10 CPUs praticamente ocioso:
kubectl -n loja top pod cpu-limitada --containers POD NAME CPU(cores) MEMORY(bytes)
cpu-limitada app 201m 0Mi O limit vira uma cota no cgroup: 20 ms de CPU a cada período de 100 ms.
kubectl -n loja exec cpu-limitada -- cat /sys/fs/cgroup/cpu.max
kubectl -n loja exec cpu-limitada -- cat /sys/fs/cgroup/cpu.stat 20000 100000
usage_usec 16198471
nr_periods 810
nr_throttled 809
throttled_usec 35571023 Em 810 períodos, o container foi limitado em 809, e passou 35,6 s esperando. Para um loop de teste isso não importa; para uma API, é latência: a requisição que chega no fim da cota espera o próximo período. Se as métricas mostram container_cpu_cfs_throttled_periods_total subindo e a latência junto, o limit de CPU está baixo.
Memória: o limit mata
Memória não se comprime. Passou do limit, o kernel mata o processo com SIGKILL e o container registra OOMKilled com exit 137. Reproduzimos com um container que tenta alocar 150M com limit de 128Mi: três reinícios em 75 s. O passo a passo está em OOMKilled.
Sem limit de memória, o container pode crescer até o nó ficar sem memória, e aí quem age é o kubelet, despejando pods (Evicted). Os primeiros a sair são os que passam do próprio request.
Do uso medido ao manifesto
- Colete uma semana de uso normal, incluindo o pico do dia e os jobs noturnos.
- Request de CPU: perto do uso típico (por exemplo, o percentil 90 da taxa de uso). É o que garante espaço no nó.
- Request de memória: perto do uso típico da memória de trabalho.
- Limit de memória: acima do pico da semana, com folga para crescimento. Escreva o critério no manifesto.
- Limit de CPU: decida se quer (veja o throttling acima). Sem ele, o request continua garantindo a parte do container.
# pico de memória em 7 dias
max_over_time(container_memory_working_set_bytes{namespace="loja", container="checkout"}[7d])
# percentil 90 do uso de CPU em 7 dias (núcleos)
quantile_over_time(0.9, rate(container_cpu_usage_seconds_total{namespace="loja", container="checkout"}[5m])[7d:5m]) resources:
requests:
cpu: 300m # p90 de 7 dias: 0,28 núcleo
memory: 512Mi # uso típico: 470Mi
limits:
memory: 896Mi # pico de 7 dias: 700Mi, mais 25% de folga A classe de QoS que sai disso
Os valores definem a classe de QoS do pod, que decide a ordem de despejo quando o nó aperta. Request igual a limit em CPU e memória, em todos os containers, dá Guaranteed; sem nada, BestEffort; o resto é Burstable (documentação do Kubernetes, "Pod Quality of Service Classes"). O container do teste de CPU, com request 100m e limit 200m, ficou Burstable:
kubectl -n loja get pod cpu-limitada -o jsonpath='{.status.qosClass}' Burstable Para conferir antes de aplicar, use a calculadora de QoS.
Perguntas frequentes
Devo colocar limit de CPU?
Depende do que você prefere perder. Com limit, o container nunca passa dele e é limitado mesmo com o nó ocioso: no nosso teste, um limit de 200m segurou o container em 201m e ele ficou limitado em 809 de 810 períodos. Sem limit, ele usa a folga do nó, e o request continua garantindo a parte dele. Muitos times deixam CPU sem limit e memória com limit.
Request de memória protege contra OOMKilled?
Não. O request serve ao scheduler; quem mata por memória é o limit. Um container com request 64Mi e limit 128Mi morre ao passar de 128Mi.
Como descubro o uso real?
kubectl top mostra o instante (precisa do metrics-server). Para dimensionar, use o histórico: no Prometheus, max_over_time e quantis de container_memory_working_set_bytes e da taxa de container_cpu_usage_seconds_total, por pelo menos uma semana de uso normal.
Existe um fator certo de folga?
A documentação do Kubernetes não prescreve nenhum. Escolha um critério (por exemplo, limite de memória acima do pico de 7 dias com margem para crescimento), escreva o motivo no manifesto e revise quando o pico mudar.