Skip to main content
RunBook Academy

KubernetesXII · Resource Requests and LimitsResource requests and limits

LimitRange defaults and constraints — namespace-level resource policies

Advanced⏱ ~16 minkubectl

What you'll learn

  • Configure LimitRange for default requests and limits
  • Set per-container min/max constraints
  • Reason about the interaction between LimitRange and explicit Pod specs
  • Apply LimitRange to enforce production resource policies

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

A LimitRange is a namespace-level policy that sets default resource requests and limits and enforces per-container constraints. It is the safety net for new Pods that don’t declare resources explicitly. This lesson covers the LimitRange fields, the constraints, and the production discipline around namespace resource policies.

LimitRange anatomy

apiVersion: v1
kind: LimitRange
metadata:
  name: default
  namespace: team-a-prod
spec:
  limits:
  - type: Container
    default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    min:
      cpu: 50m
      memory: 32Mi
    max:
      cpu: 2
      memory: 4Gi
    maxLimitRequestRatio:
      cpu: "4"
      memory: "2"

The fields:

  • type: Container: applies to individual containers (the default type).
  • default: default limits for containers that don’t declare limits.
  • defaultRequest: default requests for containers that don’t declare requests.
  • min: minimum allowed requests. A container with a request below this is rejected.
  • max: maximum allowed limits. A container with a limit above this is rejected.
  • maxLimitRequestRatio: max ratio of limit to request. A container with limit > request * ratio is rejected.

Other types:

  • type: Pod: applies to the Pod as a whole (sum of containers).
  • type: PersistentVolumeClaim: applies to PVC storage requests.

How default requests and limits work

When a Pod is created in a namespace with a LimitRange:

  1. For each container:
    • If requests.cpu is not set, use defaultRequest.cpu from the LimitRange.
    • If requests.memory is not set, use defaultRequest.memory.
    • If limits.cpu is not set, use default.cpu.
    • If limits.memory is not set, use default.memory.
  2. Validate against min/max: if any container exceeds max or is below min, reject the Pod.
flowchart TD
    Pod[Pod created] --> Check{Has resources?}
    Check -- no --> Default[Apply defaults from LimitRange]
    Check -- yes --> Validate[Validate against min/max]
    Default --> Validate
    Validate --> Pass{Passes?}
    Pass -- yes --> Create[Pod created]
    Pass -- no --> Reject[Pod rejected]

Production discipline: every namespace should have a LimitRange so new Pods land inside sane resource bounds. A Pod without resources is BestEffort and evicted first under node pressure.

Min/max constraints

The min and max fields enforce hard limits:

spec:
  limits:
  - type: Container
    min:
      cpu: 50m
      memory: 32Mi
    max:
      cpu: 2
      memory: 4Gi
  • A container requesting cpu: 10m (below min) is rejected.
  • A container with limits.cpu: 4 (above max) is rejected.
  • A container with no requests is given the default request (which must be ≥ min).

This prevents:

  • A Pod requesting 0 CPU (which would be BestEffort).
  • A Pod requesting an entire node’s CPU.
  • A Pod with no memory limit (which could OOMKill the node).

maxLimitRequestRatio

The maxLimitRequestRatio enforces that the limit is not too far above the request:

maxLimitRequestRatio:
  cpu: "4"
  memory: "2"

A container with requests.cpu: 100m, limits.cpu: 1000m has ratio 10; above 4. The Pod is rejected.

The ratio prevents:

  • A Pod with requests.cpu: 100m, limits.cpu: 100 (the Pod reserves almost no CPU but can use 100 cores). This Pod is BestEffort-like in scheduling but unlimited in throttling.

Production discipline: set maxLimitRequestRatio based on the workload’s burst pattern. A web service might tolerate 4:1 (4x burst over request); a database should be 1:1 (Guaranteed).

Default requests and limits in practice

The default LimitRange for a production namespace:

apiVersion: v1
kind: LimitRange
metadata:
  name: default
  namespace: team-a-prod
spec:
  limits:
  - type: Container
    default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    min:
      cpu: 10m
      memory: 16Mi
    max:
      cpu: 4
      memory: 8Gi
    maxLimitRequestRatio:
      cpu: "4"
      memory: "2"

This LimitRange:

  • Sets defaults so new Pods have resources.
  • Allows small resources (10m CPU is reasonable for a control-plane component).
  • Caps large resources (4 CPU, 8Gi is reasonable for an application).
  • Prevents unlimited bursting.

Pod-level LimitRange

apiVersion: v1
kind: LimitRange
metadata:
  name: pod-defaults
  namespace: team-a-prod
spec:
  limits:
  - type: Pod
    default:
      cpu: 1
      memory: 1Gi
    defaultRequest:
      cpu: 200m
      memory: 256Mi
    max:
      cpu: 8
      memory: 16Gi

A type: Pod LimitRange applies to the sum of all containers in the Pod. The Pod’s total requests and limits are validated against the Pod-level defaults.

Use Pod-level LimitRange to enforce:

  • The Pod as a whole must have at least 200m CPU / 256Mi memory requested.
  • The Pod’s total limits cannot exceed 8 CPU / 16Gi.

PVC LimitRange

apiVersion: v1
kind: LimitRange
metadata:
  name: pvc-defaults
  namespace: team-a-prod
spec:
  limits:
  - type: PersistentVolumeClaim
    default:
      storage: 10Gi
    defaultRequest:
      storage: 10Gi
    max:
      storage: 1Ti

A PVC created without spec.resources.requests.storage gets the default. PVCs with requests above max are rejected.

Production discipline

Pair LimitRange with ResourceQuota:

# LimitRange: per-container
apiVersion: v1
kind: LimitRange
metadata:
  name: default
  namespace: team-a-prod
spec:
  limits:
  - type: Container
    default: {cpu: 500m, memory: 512Mi}
    defaultRequest: {cpu: 100m, memory: 128Mi}
    max: {cpu: 4, memory: 8Gi}

# ResourceQuota: namespace total
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-a-prod-quota
  namespace: team-a-prod
spec:
  hard:
    requests.cpu: "32"
    requests.memory: 64Gi
    limits.cpu: "64"
    limits.memory: 128Gi

LimitRange sets per-container defaults and limits; ResourceQuota caps the total in the namespace. Together, they enforce a complete resource policy.

  • Every namespace has a LimitRange. New Pods land inside sane resource bounds.
  • Set maxLimitRequestRatio to prevent BestEffort-like bursting. Ratio 4:1 for web services; 1:1 for databases.
  • Audit LimitRange on namespace creation. Add to the namespace-onboarding runbook.

Diagnosing LimitRange rejections

A Pod that violates LimitRange is rejected with a clear error:

kubectl apply -f deployment.yaml
# Error from server (Invalid): error when creating "deployment.yaml":
#   admission webhook "v1.NamespaceBound" denied the request:
#   memory: requested memory "64Mi" is below the minimum "128Mi"

The admission controller (the LimitRange plugin) reports the exact violation. Common errors:

  • requested memory "X" is below the minimum "Y": increase the request or lower the min.
  • requested memory "X" exceeds the maximum "Y": reduce the request or raise the max.
  • limit "X" exceeds the maximum "Y": reduce the limit or raise the max.
  • limit/request ratio "X" exceeds maximum "Y": increase the request or reduce the limit.

Cross-course references

  • The Linux course part XXXVII-Linux-Resources covers cgroup resource limits; LimitRange is the cluster-level policy.
  • The Ansible course part XLIX-Ansible-Compliance covers compliance policies; LimitRange is the cluster-level equivalent.
  • The Observability course part LXXXVII-Kubernetes-MetricsServer covers kubectl top; use it to verify LimitRange defaults are appropriate.

Quiz

Knowledge check · 4 questions

  1. Q1. When does a LimitRange's `default` field apply to a container?

  2. Q2. `maxLimitRequestRatio` is used to prevent a Pod from having a very high CPU limit with a very low CPU request (which would make it BestEffort-like in scheduling but unlimited in throttling).

  3. Q3. A team deploys a new Pod to a namespace with no LimitRange. The Pod has no `resources` block. What is the QoS class, and what happens under node pressure?

    Namespace: `team-a-prod` with no LimitRange. New Pod has no `resources:` block in its container spec. The cluster has 10 nodes, each with 4 CPU and 4Gi memory. After deployment, node 3 runs low on memory (200Mi available).

  4. Q4. What is the difference between LimitRange and ResourceQuota? When is each the right tool?

Passing score: 75%. Answers are checked in this browser.