Skip to main content
mastering ckad certified kubernetes application developer

Namespace Resource Quotas

7 min read Chapter 53 of 87
Summary

Covers ResourceQuota creation via imperative commands and YAML,...

Covers ResourceQuota creation via imperative commands and YAML, compute quotas (CPU, memory requests/limits), object count quotas (pods, services, configmaps, secrets), the enforcement rule that forces Pods to specify resources when quotas are active, inspection with kubectl describe quota, and interaction with LimitRanges.

Namespace Resource Quotas

A ResourceQuota is a namespaced object that constrains the aggregate resource consumption within that namespace. Once a quota is active, the API server tracks the total resources requested by all Pods in the namespace and rejects any new Pod that would cause the total to exceed the quota.

Think of a ResourceQuota as a budget: the namespace has a fixed allocation of CPU, memory, and object counts. Every Pod spends from that budget. When the budget is exhausted, no more Pods can be created until existing ones are deleted or the quota is increased.

Creating a ResourceQuota

Imperative Command

The fastest approach on the exam:

kubectl create quota my-quota \
  --hard=pods=10,cpu=4,memory=8Gi \
  -n dev

This creates a ResourceQuota named my-quota in the dev namespace with three constraints:

  • Maximum 10 Pods
  • Maximum 4 CPU cores total (across all Pods’ requests)
  • Maximum 8 GiB memory total (across all Pods’ requests)

Verify:

kubectl describe quota my-quota -n dev
Name:       my-quota
Namespace:  dev
Resource    Used  Hard
--------    ----  ----
cpu         0     4
memory      0     8Gi
pods        0     10

The Used column shows current consumption. The Hard column shows the ceiling. As Pods are created, Used increases.

Declarative YAML

For more complex quotas, a YAML manifest gives full control:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi

This quota distinguishes between requests and limits:

  • requests.cpu: “4” — total CPU requests across all Pods cannot exceed 4 cores
  • limits.cpu: “8” — total CPU limits across all Pods cannot exceed 8 cores
  • requests.memory: 8Gi — total memory requests cannot exceed 8 GiB
  • limits.memory: 16Gi — total memory limits cannot exceed 16 GiB

The distinction matters. A Pod requesting 500m CPU with a limit of 1 CPU consumes 500m from the requests budget and 1 from the limits budget. Quotas on both prevent overcommitment (limits exceed node capacity) and over-request (requests consume too much guaranteed capacity).

Compute Resource Quotas

The following compute resources can be constrained:

Quota FieldDescription
requests.cpuTotal CPU requests across all Pods
requests.memoryTotal memory requests across all Pods
limits.cpuTotal CPU limits across all Pods
limits.memoryTotal memory limits across all Pods
cpuAlias for requests.cpu
memoryAlias for requests.memory

CPU is measured in cores (or millicores: 500m = 0.5 cores). Memory is measured in bytes with standard suffixes: Ki, Mi, Gi, Ti.

Example: Tracking Resource Consumption

# Create namespace and quota
kubectl create namespace quota-lab
kubectl create quota compute-quota \
  --hard=requests.cpu=2,requests.memory=4Gi,limits.cpu=4,limits.memory=8Gi \
  -n quota-lab

# Create a Pod that consumes resources
kubectl run web --image=nginx:1.25 \
  --requests='cpu=250m,memory=256Mi' \
  --limits='cpu=500m,memory=512Mi' \
  -n quota-lab

# Check quota usage
kubectl describe quota compute-quota -n quota-lab
Name:            compute-quota
Namespace:       quota-lab
Resource         Used   Hard
--------         ----   ----
limits.cpu       500m   4
limits.memory    512Mi  8Gi
requests.cpu     250m   2
requests.memory  256Mi  4Gi

One Pod consumed 250m/2000m of the CPU request budget and 256Mi/4096Mi of the memory request budget. The remaining budget is available for additional Pods.

Object Count Quotas

ResourceQuotas also limit the number of API objects:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-quota
  namespace: dev
spec:
  hard:
    pods: "20"
    services: "10"
    services.loadbalancers: "2"
    services.nodeports: "5"
    configmaps: "20"
    secrets: "20"
    persistentvolumeclaims: "10"
    replicationcontrollers: "10"

Each field caps the total count of that object type in the namespace. Attempting to create the 21st Pod in a namespace with pods: 20 produces an error:

Error from server (Forbidden): pods "pod-21" is forbidden: 
exceeded quota: object-quota, requested: pods=1, used: pods=20, limited: pods=20

Common object count fields:

Quota FieldObject Type
podsTotal Pods
servicesTotal Services
services.loadbalancersLoadBalancer Services only
services.nodeportsNodePort Services only
configmapsTotal ConfigMaps
secretsTotal Secrets
persistentvolumeclaimsTotal PVCs
count/deployments.appsTotal Deployments

The count/<resource>.<group> syntax works for any resource, including custom resources:

spec:
  hard:
    count/deployments.apps: "5"
    count/jobs.batch: "10"
    count/cronjobs.batch: "3"

The Enforcement Rule: Pods Must Specify Resources

This is the most commonly encountered gotcha with ResourceQuotas. When a namespace has a compute quota (any of requests.cpu, requests.memory, limits.cpu, limits.memory), every Pod in that namespace must specify the corresponding resource field.

If a quota sets requests.cpu, every Pod must include resources.requests.cpu. If a quota sets limits.memory, every Pod must include resources.limits.memory. A Pod without the required field is rejected immediately:

Error from server (Forbidden): pods "no-resources" is forbidden: 
failed quota: compute-quota: must specify limits.cpu, limits.memory, 
requests.cpu, requests.memory

This means existing workflows that never specified resource requests or limits break the moment a quota is applied. The solution is one of two approaches:

  1. Add resource specifications to every Pod/Deployment in the namespace. This is the correct long-term approach.
  2. Create a LimitRange that provides defaults. When a LimitRange with default and defaultRequest values exists, Pods that omit resource specifications inherit the defaults. The next section covers LimitRanges in detail.

In practice, teams deploy a LimitRange alongside the ResourceQuota to ensure no Pod is rejected solely for missing resource specifications.

Combining Compute and Object Quotas

A single ResourceQuota can contain both compute and object constraints:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    # Compute
    requests.cpu: "8"
    requests.memory: 16Gi
    limits.cpu: "16"
    limits.memory: 32Gi
    # Object counts
    pods: "50"
    services: "20"
    configmaps: "30"
    secrets: "30"
    persistentvolumeclaims: "15"

You can also create multiple ResourceQuota objects in the same namespace. Kubernetes merges them — a Pod must satisfy all quotas simultaneously. If quota-a allows 10 Pods and quota-b allows 5, the effective limit is 5 (the more restrictive quota wins).

Quota Scopes

Quotas can be scoped to specific Pod categories:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: besteffort-quota
  namespace: dev
spec:
  hard:
    pods: "5"
  scopes:
    - BestEffort

This quota limits only BestEffort Pods (those without any resource requests or limits) to 5. Pods with resource specifications are not affected by this quota.

Available scopes:

ScopeApplies To
BestEffortPods with no resource requests or limits
NotBestEffortPods with at least one resource request or limit
TerminatingPods with activeDeadlineSeconds set
NotTerminatingPods without activeDeadlineSeconds

Inspecting Quotas

Describe a Specific Quota

kubectl describe quota my-quota -n dev

Shows the quota name, namespace, each resource field with its current Used value and Hard limit.

List All Quotas in a Namespace

kubectl get resourcequota -n dev
NAME             AGE   REQUEST                                              LIMIT
compute-quota    5m    requests.cpu: 250m/2, requests.memory: 256Mi/4Gi     limits.cpu: 500m/4, limits.memory: 512Mi/8Gi
object-quota     5m    configmaps: 3/20, pods: 1/20, secrets: 2/20, ...

Check Why a Pod Was Rejected

If a Pod creation fails due to quota, the error message specifies exactly which resource was exceeded:

kubectl run overflow --image=nginx --requests='cpu=10' -n quota-lab
Error from server (Forbidden): pods "overflow" is forbidden: 
exceeded quota: compute-quota, requested: requests.cpu=10, 
used: requests.cpu=250m, limited: requests.cpu=2

The error tells you: the Pod requested 10 CPU cores, the quota allows 2 total, and 250m is already used. This diagnostic output is precise enough to identify the problem immediately.

Exam Strategy

ResourceQuota tasks on the CKAD are straightforward:

  1. Create the quota: kubectl create quota <name> --hard=<key>=<value>,... -n <ns>
  2. Verify the quota: kubectl describe quota <name> -n <ns>
  3. Understand the enforcement rule: adding a compute quota forces all Pods to specify resources.
  4. Diagnose failures: read the error message — it tells you exactly which resource was exceeded.

The imperative kubectl create quota command handles the most common exam scenarios. For complex quotas with separate request and limit fields, write a YAML manifest.