Chapter 01: Kubernetes Core Workloads & Pods
⚡ Interactive Problems in this Chapter (Click to solve in Playground)
1. Architectural Overview & Control Plane Mechanics
In Kubernetes, Kubernetes Core Workloads & Pods is reconciled through declarative state loops managed by the control plane and node daemons:
flowchart TD
subgraph ControlPlane["Control Plane (API & Scheduling)"]
API["kube-apiserver<br/><code>v1/pods</code>"]
ETCD[("etcd Storage")]
SCHED["kube-scheduler<br/><i>Filters & Scores Nodes</i>"]
API <--> ETCD
SCHED -->|Assigns Node| API
end
subgraph WorkerNode["Worker Node (kubelet & Runtime)"]
KUBELET["kubelet.service<br/><i>Sync Loop & PLEG</i>"]
CRI["CRI Engine (containerd / CRI-O)<br/><i>Cgroups & Namespaces</i>"]
subgraph PodSandbox["Pod Sandbox Network & IPC"]
INIT["Init Container<br/><i>(runs sequentially to exit 0)</i>"]
MAIN["Main Container<br/><i>(app: web-server)</i>"]
SIDECAR["Sidecar Container<br/><i>(proxy / log-shipper)</i>"]
VOL[("Shared Volume<br/><i>emptyDir / ConfigMap / Secret</i>")]
end
end
API -->|Watch Event| KUBELET
KUBELET -->|gRPC CRI API| CRI
CRI --> INIT
INIT -.->|Exit 0 Success| MAIN
INIT -.->|Exit 0 Success| SIDECAR
MAIN <-->|Mount| VOL
SIDECAR <-->|Mount| VOL
1.1 Architectural Flow & Lifecycle Walkthrough
- Manifest Ingestion & OpenAPI Deserialization: The user or CI client submits a YAML Pod manifest via
kubectl apply. Thekube-apiserverdeserializes the YAML into native Go structs (v1.Pod), validates the fields against OpenAPI v3 schemas, and applies admission checks. - Persistence in etcd: Upon passing validation,
kube-apiserverencodes the Go struct into a compact Protobuf binary payload and executes an atomic MVCC transaction to persist the record at key/registry/pods/{namespace}/{name}inetcd3. - Scheduling Watch & Node Binding:
kube-schedulermaintains an HTTP/2 streaming watch on unassigned Pods (spec.nodeName == ""). It filters and scores candidate nodes, selecting the optimal worker node, and writes an asynchronousBindingsubresource back to the API server. - Kubelet Sync Loop & PLEG: The target worker node's
kubeletdetects the scheduled Pod via itsPodConfigchannel. The Pod Lifecycle Event Generator (PLEG) detects state divergence and initiates container reconciliation. - CRI gRPC Sandbox Creation:
kubeletconnects to the Container Runtime Interface (CRI) engine (containerdorCRI-O) via a local Unix Domain Socket (/run/containerd/containerd.sock) over gRPC. It issues aRunPodSandboxgRPC request, promptingcontainerdto spawn the Linux pause container (CLONE_NEWNET,CLONE_NEWUTS,CLONE_NEWIPC). - Sequential Init Container Execution:
kubeletinvokesCreateContainerandStartContainerover CRI gRPC for each init container in strict sequential order. Each init container must terminate with exit code 0 before subsequent containers are scheduled. - Main & Sidecar Container Startup:
kubeletinitiates the application and sidecar containers concurrently within the shared network and IPC namespaces, attaching mounted storage volumes (emptyDir,ConfigMap, or persistent block mounts).
1.2 Serialization, Protocols & Communication Pathways
- gRPC over Unix Domain Sockets (UDS):
kubeletcommunicates withcontainerdvia/run/containerd/containerd.sockusing theruntime.v1.RuntimeServicegRPC interface. - Protobuf Serialization: Data exchanged over CRI gRPC and stored within
etcd3is serialized using Protocol Buffers (proto3) to eliminate JSON parsing overhead and minimize CPU/memory serialization latency. - JSON/YAML Deserialization & Scheme Conversion:
kubectltransmits JSON payloads over HTTP/2 with TLS 1.3 tokube-apiserver. The API server usesk8s.io/apimachinerycodec schemes to convert external versions (v1) into internal unstructured objects before validation.
1.3 Deep-Dive Component Breakdown
- kube-apiserver: Stateless HTTP REST gateway providing OpenAPI v3 schema validation, authentication (AuthN), authorization (AuthZ), admission mutation/validation, and
etcdpersistence. - kubelet & PLEG: Node management agent running as a systemd service. PLEG (Pod Lifecycle Event Generator) polls runtime relists and container events to maintain internal active pod caches.
- Pause Container: A minimal C program (
pause.c) that sleeps indefinitely (pause()), holding the Linux network (CLONE_NEWNET), IPC (CLONE_NEWIPC), and UTS namespaces open for all co-located containers in the Pod. - Shared Volume Subsystem: Linux VFS bind-mounts configured by kubelet's Volume Manager, enabling atomic inter-container data exchange via memory-backed
tmpfsor host filesystem mounts.
1.4 Under-The-Hood Mechanics & Failure Modes
- cgroups v2 Enforcement: Resource limits translate directly to Linux control group v2 files:
spec.containers[*].resources.limits.cpusetscpu.max(quota and period in microseconds), whilelimits.memorysetsmemory.max(hard memory ceiling). - OOM Killer &
oom_score_adj: The Linux kernel Out-Of-Memory (OOM) killer uses/proc/[pid]/oom_score_adj. Kubelet assigns-997to Guaranteed QoS Pods, while BestEffort Pods receive1000, making BestEffort workloads the first candidates for termination under memory exhaustion. - Init Container Failure Modes: If any init container exits with non-zero status and
restartPolicy: Always, kubelet restarts the failed init container using exponential backoff (10s, 20s, up to 5 minutes), blocking application startup indefinitely.
2. Annotated Production YAML Anatomy & Field Reference
Below is a production-grade declarative manifest demonstrating field definitions and operational patterns:
apiVersion: v1
kind: Pod
metadata:
name: production-web-service
namespace: default
labels:
app.kubernetes.io/name: web-service
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: e-commerce
spec:
restartPolicy: Always
terminationGracePeriodSeconds: 30
initContainers:
- name: init-db-check
image: busybox:1.36
command: ['sh', '-c', 'echo "Waiting for database ready..."; sleep 2;']
resources:
limits:
cpu: "100m"
memory: "64Mi"
requests:
cpu: "50m"
memory: "32Mi"
containers:
- name: web-app
image: nginx:1.27-alpine
ports:
- name: http
containerPort: 80
protocol: TCP
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
- name: log-collector
image: busybox:1.36
command: ['sh', '-c', 'tail -F /var/log/nginx/access.log 2>/dev/null || true']
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
volumes:
- name: shared-logs
emptyDir: {}
Key Field Schema Reference
| Field | Type | Description |
|---|---|---|
spec.initContainers |
Array |
Containers executed sequentially before app containers start. Must exit with code 0. |
spec.containers[*].resources |
Object |
Compute requests (scheduler quota) and limits (cgroup enforcement). |
spec.volumes |
Array |
Shared storage abstractions mounted into container filesystems. |
spec.terminationGracePeriodSeconds |
Integer (Default: 30) |
Duration given for SIGTERM handling before SIGKILL is dispatched. |
3. Real-World Architectural Patterns
Sidecar Logging Pattern
apiVersion: v1
kind: Pod
metadata:
name: sidecar-log-processor
spec:
containers:
- name: app
image: alpine:3.20
command: ["sh", "-c", "while true; do date >> /logs/app.log; sleep 1; done"]
volumeMounts:
- name: log-volume
mountPath: /logs
- name: shipper
image: busybox:1.36
command: ["sh", "-c", "tail -f /logs/app.log"]
volumeMounts:
- name: log-volume
mountPath: /logs
volumes:
- name: log-volume
emptyDir: {}
Downward API Metadata Injection
apiVersion: v1
kind: Pod
metadata:
name: downward-api-env
labels:
tier: frontend
spec:
containers:
- name: client
image: busybox:1.36
command: ["sh", "-c", "env | grep POD_ && sleep 3600"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
4. Production Hardening & Operational Governance
- Always set both
requestsandlimitsto establish predictable QoS classes (Guaranteed vs Burstable). - Set
securityContext.runAsNonRoot: trueandsecurityContext.readOnlyRootFilesystem: true. - Drop all Linux capabilities with
capabilities.drop: ['ALL']and add back only strictly necessary capabilities (e.g.NET_BIND_SERVICE). - Pair multi-instance workloads with
PodDisruptionBudgetto ensure high availability during node drains.
5. Failure Modes & Diagnostic Triage Tree
CrashLoopBackOff
Root Cause: Container starts and exits immediately with an error code.
Diagnostic Triage Sequence:
1. Inspect exit code: kubectl get pod <name> -o jsonpath='{.status.containerStatuses[*].state.terminated}'
2. Check previous container logs: kubectl logs <name> -c <container> --previous
3. Verify entrypoint args and required environment variables.
OOMKilled (Exit Code 137)
Root Cause: Container exceeded its memory limit cgroup.
Diagnostic Triage Sequence:
1. Run kubectl describe pod <name> and look for Last State: Terminated / Reason: OOMKilled.
2. Increase resources.limits.memory or profile application heap memory consumption.
Pending (Scheduling Failure)
Root Cause: Scheduler cannot find a node meeting CPU/memory/taint requirements.
Diagnostic Triage Sequence:
1. Inspect scheduling events: kubectl describe pod <name>
2. Review cluster capacity: kubectl describe nodes | grep -A 8 'Allocated resources'.
6. Interactive Practice Matrix
Practice concepts from this chapter directly in the interactive WebAssembly sandbox:
| Exercise ID | Challenge Description | Direct Link | Action |
|---|---|---|---|
pods01 |
First Pod Manifest & Spec | ../playground/index.html?exercise=pods01 |
⚡ Solve pods01 in Playground → |
pods02 |
Multi-Container Pods & Sidecar Pattern | ../playground/index.html?exercise=pods02 |
⚡ Solve pods02 in Playground → |
pods03 |
Init Containers for Initialization | ../playground/index.html?exercise=pods03 |
⚡ Solve pods03 in Playground → |
pods04 |
Resource Requests, Limits & QoS | ../playground/index.html?exercise=pods04 |
⚡ Solve pods04 in Playground → |
pods05 |
Downward API & Env Variables | ../playground/index.html?exercise=pods05 |
⚡ Solve pods05 in Playground → |
pods06 |
Pod Disruption Budgets & Static Pods | ../playground/index.html?exercise=pods06 |
⚡ Solve pods06 in Playground → |