TL;DR (Quick Summary)#
- Namespace: Virtual cluster isolation dividing physical cluster resources logically.
- Requests vs Limits:
- Requests: Guaranteed CPU/Memory reserved for the Pod during scheduling (
kube-scheduler). - Limits: Maximum CPU/Memory cap the container is allowed to consume. CPU exceeding limit is throttled; Memory exceeding limit triggers OOMKilled (Exit Code 137).
- Requests: Guaranteed CPU/Memory reserved for the Pod during scheduling (
- ResourceQuota: Cap total aggregate CPU, RAM, and Pod counts per Namespace.
- LimitRange: Enforce default requests/limits for Pods created without explicit specs.
1. Multi-Tenancy Governance Architecture#
graph TD
subgraph Cluster["Kubernetes Physical Cluster (64 Core CPU, 256GB RAM)"]
subgraph NS1["Namespace: payments-prod"]
RQ1["ResourceQuota: max 16 CPU, 64GB RAM"]
P1["Pod A (Req: 2 CPU, Lim: 4 CPU)"]
P2["Pod B (Req: 4 CPU, Lim: 8 CPU)"]
end
subgraph NS2["Namespace: marketing-dev"]
RQ2["ResourceQuota: max 4 CPU, 16GB RAM"]
P3["Pod C (Req: 500m CPU, Lim: 1 CPU)"]
end
end
2. Resource Requests, Limits & Quality of Service (QoS)#
Every container specification should define requests and limits:
resources:
requests:
cpu: "250m" # 0.25 CPU Core
memory: "256Mi" # 256 Megabytes RAM
limits:
cpu: "500m" # 0.50 CPU Core
memory: "512Mi" # 512 Megabytes RAMKubernetes Quality of Service (QoS) Classes#
- Guaranteed: Every container in the Pod has
requests == limitsfor both CPU and RAM. (Highest eviction priority protection). - Burstable: Pod has
requestsspecified, butlimits > requests. - BestEffort: Pod has NO requests or limits specified. First to be killed when host runs low on RAM!
3. Creating a Namespace with ResourceQuota#
Create namespace-quota.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: team-payments
labels:
environment: production
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: payments-quota
namespace: team-payments
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "10"
services.loadbalancers: "2"Apply manifest:
kubectl apply -f namespace-quota.yaml
kubectl get resourcequota -n team-paymentsExpected Terminal Output:
NAME AGE REQUESTS LIMITS
payments-quota 15s requests.cpu: 0/4, requests.memory: 0/8Gi limits.cpu: 0/8, limits.memory: 0/16Gi4. Enforcing Defaults via LimitRange#
If a user tries to deploy a Pod without specifying resources in a namespace governed by a ResourceQuota, the API server rejects the request. A LimitRange solves this by injecting default requests and limits automatically.
Create limitrange.yaml:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-payments
spec:
limits:
- default: # Default limits
cpu: "500m"
memory: "512Mi"
defaultRequest: # Default requests
cpu: "200m"
memory: "256Mi"
max: # Maximum allowed limit per container
cpu: "2"
memory: "4Gi"
min: # Minimum allowed request per container
cpu: "50m"
memory: "64Mi"
type: ContainerApply manifest:
kubectl apply -f limitrange.yaml5. Troubleshooting OOMKilled (Exit Code 137)#
If an application attempts to allocate more RAM than its defined limits.memory, the Linux kernel OOM Killer immediately terminates the process with Exit Code 137.
Diagnose OOMKilled Pods:
kubectl get pod -n team-payments -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[*].state.terminated.reason}{"\t"}{.status.containerStatuses[*].state.terminated.exitCode}{"\n"}{end}'payment-api-7d4f9b-2x9lq OOMKilled 137To fix OOMKilled, inspect real-time metrics using kubectl top pod -n team-payments and increase limits.memory in your manifest!
6. Summary & Next Steps#
Namespaces, ResourceQuotas, and LimitRanges establish clean resource boundaries across teams and namespaces.
In Episode 13: RBAC, ServiceAccounts & Security, we will tackle security governance, learning how to configure Role-Based Access Control (RBAC), Roles, ClusterRoles, and ServiceAccounts to secure cluster access!

