Resource requests e limits

1. Fundamentos de Gerenciamento de Recursos no Kubernetes

1.1. Conceitos básicos de CPU e Memória

No Kubernetes, CPU e memória são os dois principais recursos gerenciados. A CPU é medida em millicores (1000m = 1 vCPU), enquanto a memória é expressa em bytes (Mi, Gi). A CPU é um recurso compressível — quando um contêiner atinge seu limite, o sistema reduz o tempo de CPU (throttling), mas o processo continua executando. Já a memória é não compressível — se um contêiner ultrapassa o limite, ele é encerrado com OOMKilled.

1.2. O que são Requests e Limits?

  • Requests: valor mínimo garantido para o Pod. O scheduler usa esse valor para decidir em qual nó colocar o Pod.
  • Limits: teto máximo que o Pod pode consumir. Se ultrapassar, CPU sofre throttling; memória causa OOMKill.

1.3. Como o Kubernetes utiliza esses valores

O scheduler seleciona nós com capacidade suficiente para somar todos os requests dos Pods. A combinação de requests e limits define a classe de QoS (Quality of Service) do Pod, que determina prioridade de remoção em situações de pressão de recursos.

2. Configurando Requests e Limits em Pods e Deployments

2.1. Sintaxe YAML para recursos

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        cpu: "250m"        # 0.25 vCPU
        memory: "128Mi"    # 128 Mebibytes
      limits:
        cpu: "500m"        # 0.5 vCPU
        memory: "256Mi"    # 256 Mebibytes

2.2. Práticas recomendadas de valores

Baseie requests no percentil 95 do uso real (monitorado com Prometheus ou Metrics Server). Evite overcommit excessivo (soma de requests > capacidade do nó) para não causar contenção. Para limites, defina um teto 20-50% acima do request típico.

2.3. Exemplo prático: Deployment com recursos definidos

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"

Verifique com kubectl describe pod web-app-xxxxx na seção Resources.

3. Classes de Qualidade de Serviço (QoS) e Impacto no Cluster

3.1. As três classes de QoS

  • Guaranteed: requests == limits (para CPU e memória). Maior prioridade.
  • Burstable: requests < limits (pelo menos um recurso). Prioridade média.
  • BestEffort: sem requests nem limits. Menor prioridade.

3.2. Comportamento do kubelet e OOM Killer

Em estresse de memória, o kubelet remove Pods na ordem: BestEffort → Burstable (com maior consumo) → Guaranteed. Para evitar OOMKilled, mantenha limites de memória 30-50% acima do uso médio.

3.3. Efeitos no escalonamento e no uso do nó

O scheduler aloca Pods apenas se o nó tiver capacidade para somar todos os requests. Se você não define requests, o scheduler assume consumo zero, podendo causar superprovisionamento e fragmentação de recursos.

4. Monitoramento e Ajuste de Recursos

4.1. Ferramentas para visualizar consumo

# Ver consumo de Pods
kubectl top pods -n production

# Ver capacidade dos nós
kubectl top nodes

# Com Metrics Server instalado, use também:
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods

4.2. Estratégias para ajuste dinâmico

O Vertical Pod Autoscaler (VPA) recomenda valores ideais de requests/limits baseados em histórico. Modo Auto atualiza automaticamente; modo Initial apenas na criação.

4.3. Alertas e limites de segurança

Use LimitRanger para definir limites mínimos e máximos por namespace:

apiVersion: v1
kind: LimitRange
metadata:
  name: limits
  namespace: production
spec:
  limits:
  - max:
      cpu: "1"
      memory: "1Gi"
    min:
      cpu: "50m"
      memory: "32Mi"
    default:
      cpu: "200m"
      memory: "256Mi"
    defaultRequest:
      cpu: "100m"
      memory: "128Mi"
    type: Container

5. Boas Práticas e Armadilhas Comuns

5.1. Erros frequentes

  • Limits muito baixos: causa throttling de CPU e OOMKilled. Exemplo: definir limits.cpu: "100m" para uma aplicação que precisa de 300m.
  • Esquecer requests: o Pod vira BestEffort, podendo ser removido primeiro em estresse.
  • Ignorar memória: aplicações com vazamento de memória sem limites adequados derrubam o nó.

5.2. Como lidar com aplicações stateful

Bancos de dados (MySQL, PostgreSQL) devem usar Guaranteed (requests == limits) para evitar OOMKill durante picos. Para StatefulSets, considere que a perda de um Pod pode exigir recuperação manual.

5.3. Integração com Docker e contêineres

Os limites do Kubernetes são convertidos para flags do Docker (--memory, --cpu-shares) e implementados via cgroups. O docker run --memory=256m equivale a limits.memory: "256Mi" no Kubernetes.

6. Casos de Uso e Exemplos Práticos

6.1. Aplicação web com tráfego variável

Para Nginx com tráfego variável, use Burstable:

resources:
  requests:
    cpu: "100m"
    memory: "64Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"

Isso permite picos sem desperdício de recursos ociosos.

6.2. Job batch com requisitos previsíveis

Para jobs críticos, use Guaranteed:

resources:
  requests:
    cpu: "1"
    memory: "512Mi"
  limits:
    cpu: "1"
    memory: "512Mi"

6.3. Cenário de troubleshooting

Se um Pod entra em CrashLoopBackOff com OOMKilled:

kubectl logs pod-name --previous
kubectl describe pod pod-name | grep -A5 State

Aumente limits.memory em 50% e reimplante. Monitore com kubectl top pod.

7. Relação com Temas Vizinhos da Série

7.1. Como requests/limits afetam o Horizontal Pod Autoscaler

O HPA escala baseado na utilização em relação aos requests. Se um Pod tem requests.cpu: "200m" e usa 150m, a utilização é 75%. Sem requests definidos, o HPA não pode calcular métricas corretamente.

7.2. Interação com Namespaces e Ingress

O LimitRanger atua por namespace, garantindo governança. O Ingress não gerencia recursos internos dos Pods — ele apenas roteia tráfego.

7.3. Impacto em Rolling Updates e Rollbacks

Durante rolling updates, o scheduler precisa de capacidade extra para o novo Pod antes de remover o antigo. Sem requests adequados, a atualização pode falhar por falta de espaço no nó.

Referências