K8s by Example: Resource Requests & Limits

Requests define the minimum resources a Pod needs. Limits define the maximum it can use. The scheduler uses requests to place Pods on nodes.

pod-resources.yaml

Resources are defined per container. requests are guaranteed and the scheduler reserves this amount. limits are the maximum allowed, and exceeding them triggers throttling or 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 is compressible: exceeding limit causes throttling. Memory is incompressible: exceeding limit causes OOMKill. Set memory limits equal to requests to avoid OOMKill surprises.

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

CPU units: 1 = 1 core, 500m = 0.5 core, 100m = 0.1 core (millicores). Memory units: Mi (mebibytes), Gi (gibibytes). Decimal units M, G also work. Use binary units for consistency.

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

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

QoS classes are assigned based on requests and limits. Guaranteed (requests = limits, first example): highest priority, last evicted. Burstable (requests < limits, second example): medium priority. BestEffort (no resources): first 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 sets default, min, and max resources per namespace. Applied automatically to Pods without explicit resources. Prevents runaway resource consumption.

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 is capacity minus system reserved. Scheduler only considers allocatable when placing Pods. Sum of Pod requests must be less than node allocatable.

$ 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 happens when node resources run low. Kubelet evicts Pods based on QoS class and resource usage. BestEffort first, then Burstable exceeding requests, finally 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 resource issues by checking actual usage vs requests. Requires metrics-server. OOMKilled containers show exit code 137. High CPU throttling means limit is too low.

$ 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"

Index | GitHub | Use arrow keys to navigate |