K8s em Exemplos: Requests e Limits de Recursos

Requests definem o mínimo de recursos que um Pod precisa. Limits definem o máximo que pode usar. O scheduler usa requests para alocar Pods em nodes.

pod-resources.yaml

Resources são definidos por container. requests são garantidos - o scheduler reserva esta quantidade. limits são o máximo permitido - exceder causa throttling ou OOMKill.

spec:
  containers:
    - name: app
      image: my-app:v1
      resources:
        requests:
          cpu: 100m
          memory: 256Mi
        limits:
          cpu: 500m
          memory: 512Mi
pod-resources-safe.yaml

CPU é compressível: exceder limit causa throttling. Memória é incompressível: exceder limit causa OOMKill. Defina limits de memória igual a requests para evitar surpresas de OOMKill.

resources:
  requests:
    cpu: 100m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 512Mi
resource-units.yaml

Unidades de CPU: 1 = 1 core, 500m = 0.5 core, 100m = 0.1 core (millicores). Unidades de memória: Mi (mebibytes), Gi (gibibytes). Unidades decimais M, G também funcionam. Use unidades binárias para consistência.

cpu: 1
cpu: 500m
cpu: 100m
cpu: "0.1"

memory: 128Mi
memory: 1Gi
memory: 128M
memory: 1G
qos-classes.yaml

Classes QoS são atribuídas baseadas em requests e limits. Guaranteed (requests = limits, primeiro exemplo): maior prioridade, último evicted. Burstable (requests < limits, segundo exemplo): prioridade média. BestEffort (sem resources): primeiro evicted.

resources:
  requests:
    cpu: 500m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 512Mi
---
resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi
limit-range.yaml

LimitRange define recursos default, min e max por namespace. Aplicado automaticamente a Pods sem recursos explícitos. Previne consumo descontrolado de recursos.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
    - type: Container
      default:
        cpu: 500m
        memory: 512Mi
      defaultRequest:
        cpu: 100m
        memory: 256Mi
      max:
        cpu: 2
        memory: 4Gi
      min:
        cpu: 50m
        memory: 64Mi
terminal

Node allocatable é capacidade menos reservado do sistema. Scheduler só considera allocatable ao alocar Pods. Soma de requests dos Pods deve ser menor que allocatable do node.

$ kubectl describe node node-1 | grep -A8 "Capacity:"
Capacity:
  cpu:                4
  memory:             16Gi
  pods:               110
Allocatable:
  cpu:                3800m
  memory:             15Gi
  pods:               110

$ kubectl describe node node-1 | grep -A5 "Allocated resources"
Allocated resources:
  Resource           Requests     Limits
  cpu                2100m (55%)  4500m (118%)
  memory             3Gi (20%)    6Gi (40%)
terminal

Eviction acontece quando recursos do node ficam baixos. Kubelet evicta Pods baseado em classe QoS e uso de recursos. BestEffort primeiro, depois Burstable excedendo requests, finalmente Guaranteed.

$ kubectl describe node node-1 | grep -A5 "Conditions"
Conditions:
  Type             Status  Reason
  MemoryPressure   False   KubeletHasSufficientMemory
  DiskPressure     False   KubeletHasNoDiskPressure
  PIDPressure      False   KubeletHasSufficientPID

$ kubectl get events --field-selector reason=Evicted
LAST SEEN   TYPE      REASON    MESSAGE
5m          Warning   Evicted   The node was low on resource: memory
terminal

Debug problemas de recursos verificando uso real vs requests. Requer metrics-server. Containers OOMKilled mostram exit code 137. Alto throttling de CPU significa limit muito baixo.

$ kubectl top pods
NAME        CPU(cores)   MEMORY(bytes)
my-app-1    150m         200Mi
my-app-2    140m         195Mi

$ kubectl top nodes
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
node-1   2100m        55%    8Gi             50%

$ kubectl get pod my-app -o jsonpath='{.spec.containers[*].resources}'
{"limits":{"cpu":"500m","memory":"512Mi"},"requests":{"cpu":"100m","memory":"256Mi"}}

$ kubectl get pods -o json | jq '.items[] |
    select(.status.containerStatuses[]?.lastState.terminated.exitCode == 137) |
    .metadata.name'
"my-app-3"

Índice | GitHub | Use as setas do teclado para navegar |