Pular para o conteúdo

Definir requests e limits sem chutar

Intermediário14 min de leiturakubernetes

requests é o que o scheduler reserva para o Pod; limits é o teto que o runtime impõe. Chutar os dois produz os dois piores resultados ao mesmo tempo: nó cheio de Pods ociosos e aplicação sendo freada no pico. Este guia dimensiona com dado.

Você precisa de pelo menos uma semana de dados, cobrindo o pico do negócio.

Janela do terminal
kubectl top pods -n loja --containers # instantâneo, para uma primeira noção
# CPU: percentil 95 dos últimos 7 dias, por container
quantile_over_time(0.95,
rate(container_cpu_usage_seconds_total{namespace="loja", container!=""}[5m])[7d:5m])
# Memória: o MÁXIMO, não o percentil — memória não se comprime
max_over_time(
container_memory_working_set_bytes{namespace="loja", container!=""}[7d])

Sem Prometheus, o metrics-server com kubectl top amostrado ao longo do dia já dá uma base melhor que o chute.

  • CPU request = p95 do uso, com uma folga de 20% a 30%.
  • Memória request = pico observado, com folga de 20% a 30%.
resources:
requests:
cpu: 200m # p95 medido: ~150m
memory: 512Mi # pico medido: ~400Mi
limits:
memory: 512Mi # igual ao request: veja o passo 3
# cpu: intencionalmente ausente

Request muito acima do uso desperdiça nó inteiro; muito abaixo faz o scheduler superlotar o nó e todo mundo sofre no pico.

Esta é a parte que mais gera dúvida, e as duas se comportam de formas opostas:

  • CPU é compressível. Passar do limite não mata o processo: ele é freado (throttling), o que aparece como latência alta sem nenhum erro. Por isso, para a maioria dos serviços em produção, não definir limite de CPU é a escolha mais defensável — o request já garante a fatia mínima, e a folga do nó fica disponível no pico.
  • Memória não é compressível. Passar do limite significa OOMKill, imediato e sem aviso. Limite de memória é obrigatório, e a prática segura é limits.memory igual a requests.memory.
# está havendo throttling? Se sim, o limite de CPU está atrapalhando.
sum by (pod) (rate(container_cpu_cfs_throttled_seconds_total{namespace="loja"}[5m]))
# houve OOMKill?
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}

A exceção ao “sem limite de CPU”: ambientes multi-inquilino onde um vizinho barulhento prejudica os outros, ou quando você precisa de comportamento previsível para testes. Nesses casos, use limite generoso e monitore o throttling.

4. Entenda a classe de QoS que você acabou de escolher

Seção intitulada “4. Entenda a classe de QoS que você acabou de escolher”

A combinação de requests e limits define quem é despejado primeiro quando o nó fica sem memória:

Classe Como se obtém Despejo
Guaranteed requests == limits, para CPU e memória, em todos os containers por último
Burstable requests definidos, limits diferentes ou ausentes no meio
BestEffort nada definido primeiro

Nunca deixe um serviço de produção sem requests: além de virar BestEffort e ser o primeiro a morrer, ele impede qualquer decisão correta do scheduler e do autoscaler.

Para não depender de disciplina, force um mínimo:

apiVersion: v1
kind: LimitRange
metadata: { name: padroes, namespace: loja }
spec:
limits:
- type: Container
default: { memory: 512Mi } # limits, se não declarado
defaultRequest: { cpu: 100m, memory: 256Mi }
max: { memory: 4Gi }
---
apiVersion: v1
kind: ResourceQuota
metadata: { name: cota, namespace: loja }
spec:
hard:
requests.cpu: "40"
requests.memory: 80Gi
limits.memory: 80Gi

E complete com política de admissão exigindo requests declarados — veja política como código.

Uso muda com versão, tráfego e feature nova. Coloque na rotina trimestral:

# quem pede muito mais do que usa (candidatos a redução)
sum by (namespace, pod) (kube_pod_container_resource_requests{resource="cpu"})
/ sum by (namespace, pod) (rate(container_cpu_usage_seconds_total[7d]))

Ferramentas ajudam: o VPA em modo Off gera recomendações sem aplicar nada — é a forma mais segura de usá-lo, e evita o conflito com o HPA descrito em escala automática.

  • Requests baseados em 7 dias de dados, não em chute.
  • limits.memory definido e igual ao request.
  • Limite de CPU ausente (ou justificado e monitorado por throttling).
  • Nenhum Pod de produção em BestEffort.
  • LimitRange e ResourceQuota no namespace.
  • Alerta de OOMKill e de throttling ativo.
  • Revisão agendada.