3.1 Pod Lifecycle, Multi-Container Patterns & Init Containers
Key Takeaways
- Pods transition through five distinct phases: Pending, Running, Succeeded, Failed, and Unknown, reflected in status conditions such as PodScheduled, Initialized, ContainersReady, and Ready.
- Init containers execute sequentially to completion before any application containers start; a failed regular init container is retried according to the Pod restartPolicy and prevents app containers from starting.
- Native sidecar containers (stable since Kubernetes v1.33) are defined in initContainers with restartPolicy: Always, starting before app containers and terminating after them.
- Three specialized multi-container design patterns—Sidecar (supporting task), Adapter (output standardization), and Ambassador (network proxy)—enable separation of operational concerns.
- Container health is governed by startupProbe, livenessProbe, and readinessProbe across exec, httpGet, tcpSocket, and gRPC mechanisms, while graceful termination follows a strict sequence governed by terminationGracePeriodSeconds.
Pod Lifecycle, Multi-Container Patterns & Init Containers
The Pod is the atomic execution unit in Kubernetes. While a Pod can encapsulate a single container, enterprise workloads frequently employ multi-container architectures and complex startup workflows. Mastering the internal phases of a Pod, the sequencing of Init Containers, the implementation of Sidecar, Adapter, and Ambassador patterns, and the tuning of Probes and Lifecycle Hooks is essential for designing resilient applications and acing the Certified Kubernetes Administrator (CKA) exam.
1. Pod Lifecycle Phases and Status Conditions
A Pod's lifecycle is represented by high-level Phases (status.phase) and granular Conditions (status.conditions).
+-----------------------------------------------------------------------------------------+
| POD LIFECYCLE PHASES |
| |
| +-----------+ +-----------+ +-----------+ +-------------+ |
| | Pending | ---> | Running | ---> | Succeeded | OR | Failed | |
| +-----------+ +-----------+ +-----------+ +-------------+ |
| | | |
| v v |
| (Scheduling / (At least one |
| Image Pull / app container |
| Init Containers) executing) |
| |
| * Unknown: Pod state cannot be obtained (typically kubelet communication loss) |
+-----------------------------------------------------------------------------------------+
The Five Pod Phases
Pending: The Pod manifest has been accepted by the API server and stored in etcd, but one or more containers have not been created. This includes time spent waiting to be scheduled bykube-scheduler, downloading container images over the network, and runninginitContainers.Running: The Pod has been bound to a node, all init containers have completed successfully, and at least one application container is running, starting, or restarting.Succeeded: All containers in the Pod have terminated successfully (exit code0) and will not restart. This is typical for completed batchJobs.Failed: All containers in the Pod have terminated, and at least one container terminated in failure (non-zero exit code) or was stopped by the system (e.g., OOMKilled).Unknown: The state of the Pod cannot be obtained, typically due to network partitions between the control plane and the node'skubelet.
Detailed Pod Conditions
Conditions provide granular insight into the Pod's progression:
PodScheduled: The Pod has been assigned to a target node.Initialized: All init containers have completed successfully.ContainersReady: All containers in the Pod have passed their readiness checks.Ready: The Pod is ready to serve traffic and should be included in the matching Service'sEndpointsorEndpointSlices.
Container States & Exit Codes
Within status.containerStatuses, individual containers exist in one of three states:
Waiting: Container is blocked from running. Common reasons include:ImagePullBackOff/ErrImagePull: Invalid image name, missing tag, or unauthenticated private registry.CrashLoopBackOff: Application starts but crashes repeatedly; kubelet applies exponential backoff delays (10s, 20s, 40s, up to 5 minutes).CreateContainerConfigError: Missing ConfigMap or Secret referenced byvalueFromwithoutoptional: true.
Running: Executing without errors.Terminated: Container finished execution. Key exit codes:0: Clean exit / success.1/2: Application runtime error or unhandled exception.137(128 + 9): Killed bySIGKILL—frequently caused by the Linux OOM (Out Of Memory) Killer when memory limit is breached (OOMKilled: true).143(128 + 15): Terminated gracefully viaSIGTERM.
2. Init Containers & Native Sidecars
Init containers run before application containers and are designed to perform setup tasks, database migrations, configuration seeding, or dependency waiting.
+-----------------------------------------------------------------------------------------+
| INIT CONTAINER EXECUTION FLOW |
| |
| +---------------------+ +---------------------+ +-----------------------+ |
| | Init Container 1 | ---> | Init Container 2 | ---> | App Containers | |
| | (e.g., wait for DB) | | (e.g., run schema) | | (Start in Parallel) | |
| +---------------------+ +---------------------+ +-----------------------+ |
| Exit Code 0 Exit Code 0 Running / Ready |
+-----------------------------------------------------------------------------------------+
Execution Rules for Init Containers
- Sequential Execution: Init containers always run one after another in the exact order defined in the
spec.initContainersarray. - Blocking Nature: Each init container must exit with return code
0before the next one starts. If an init container fails,kubeletrestarts the Pod according tospec.restartPolicy(Always,OnFailure,Never). - Resource Allocation: The highest request/limit among init containers is compared against the sum of app container requests/limits; the effective Pod request is the maximum of the two.
Native Sidecar Containers (Stable in Kubernetes v1.33+)
Historically, sidecar containers had to run inside spec.containers, creating race conditions where app containers started before logging or proxy sidecars were ready, and batch jobs hung because sidecars never terminated.
Kubernetes resolved this by introducing Native Sidecars within spec.initContainers by specifying restartPolicy: Always:
apiVersion: v1
kind: Pod
metadata:
name: native-sidecar-demo
spec:
initContainers:
- name: vault-agent-sidecar
image: hashicorp/vault:1.15.0
restartPolicy: Always
command: ["vault", "agent", "-config=/etc/vault/vault-agent-config.hcl"]
volumeMounts:
- name: vault-config
mountPath: /etc/vault
- name: shared-secrets
mountPath: /vault/secrets
containers:
- name: primary-app
image: nginx:1.25
volumeMounts:
- name: shared-secrets
mountPath: /etc/secrets
volumes:
- name: vault-config
configMap:
name: vault-agent-config
- name: shared-secrets
emptyDir: {}
[!NOTE] Native sidecars in
initContainersstart before application containers, keep running throughout the Pod's lifecycle, and do not block Pod termination when application containers finish in batch workloads.
3. Multi-Container Design Patterns
Multi-container Pods share the same network namespace (localhost), IPC namespace, and storage volumes (emptyDir, PVCs).
+-----------------------------------------------------------------------------------------+
| MULTI-CONTAINER ARCHITECTURE PATTERNS |
| |
| 1. SIDECAR PATTERN 2. ADAPTER PATTERN 3. AMBASSADOR PATTERN |
| +-----------------------+ +-----------------------+ +---------------------+ |
| | [Primary Web App] | | [Legacy App] | | [Local App] | |
| | | | | | (raw logs) | | | | |
| | v (shared log)| | v | | v (localhost| |
| | [Logging Sidecar] | | [Adapter (JSON / Prom)| | [Ambassador Proxy] | |
| | (Ship to Fluentd) | | (Expose Metrics) | | (Route DB/Cloud) | |
| +-----------------------+ +-----------------------+ +---------------------+ |
+-----------------------------------------------------------------------------------------+
| Pattern | Primary Purpose | Real-World Example |
|---|---|---|
| Sidecar | Enhances or extends the primary container without modifying its code. | Fluentbit log tailer shipping access.log to an Elasticsearch cluster. |
| Adapter | Standardizes and normalizes output or interfaces across heterogeneous applications. | Prometheus exporter scraping an app's custom text metrics and converting them to OpenMetrics format. |
| Ambassador | Acts as an out-of-process network proxy, abstracting external connections. | Envoy proxy routing traffic to database read-replicas based on write/read query types. |
4. Container Health Probes
kubelet monitors container health using three distinct probe types:
+-----------------------------------------------------------------------------------------+
| PROBE LIFECYCLE TIMELINE |
| |
| Container Start |
| | |
| v |
| [startupProbe] ------------------> Holds liveness & readiness probes in check |
| | until startupProbe succeeds. |
| | (Success) |
| +-------------------+ |
| | | |
| v v |
| [livenessProbe] [readinessProbe] |
| | | |
| Failure: Kills & Failure: Removes Pod from Service Endpoints / |
| Restarts Container EndpointSlices (traffic stops routed to Pod) |
+-----------------------------------------------------------------------------------------+
Probe Types and Behavioral Differences
startupProbe: Determines if the application within the container has initialized. All other probes are disabled untilstartupProbesucceeds. If it fails, the container is killed and restarted. Ideal for legacy applications with slow boot times.livenessProbe: Determines if the container needs to be restarted. If the liveness probe failsfailureThresholdtimes,kubeletterminates the container and initiates a restart according torestartPolicy. It does not protect against slow database queries—misconfigured liveness probes can cause cascading restart loops.readinessProbe: Determines if a container is ready to accept incoming network traffic. If it fails, the Pod's IP address is immediately removed from theEndpoints/EndpointSliceof all matching Services. The container is not killed or restarted.
Probe Mechanisms
httpGet: Sends an HTTP GET request to a specified port and path. Returns success if HTTP status code is >= 200 and $< 400$.tcpSocket: Attempts to open a TCP connection to the specified container port. Success if socket opens.exec: Runs a command inside the container. Success if command exits with status code0.grpc: Issues a standard gRPC Health Checking Protocol request (grpc.health.v1.HealthCheckRequest).
spec:
containers:
- name: api-server
image: registry.example.com/api:v2.1
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz/startup
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz/liveness
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /healthz/readiness
port: 8080
periodSeconds: 5
successThreshold: 1
failureThreshold: 2
[!IMPORTANT] Probe Tuning Parameters:
initialDelaySeconds: Seconds to wait after container start before probing.periodSeconds: Frequency of the probe in seconds (default: 10).timeoutSeconds: Timeout before the probe is considered failed (default: 1).failureThreshold: Consecutive failures required to trigger action (default: 3).successThreshold: Consecutive successes required to regain healthy state (default: 1; must be 1 for liveness and startup).
5. Lifecycle Hooks and Graceful Termination
Kubernetes provides two container lifecycle hooks executed by kubelet:
postStart: Executes immediately after the container is created. It runs asynchronously with the container's entrypoint; however, the container status will not be marked asRunninguntilpostStartcompletes.preStop: Executes synchronously before the container is sent aSIGTERMsignal. IfpreStophangs, it runs until theterminationGracePeriodSecondsexpires.
spec:
terminationGracePeriodSeconds: 60
containers:
- name: web
image: nginx:alpine
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "nginx -s quit; sleep 15"]
The Pod Graceful Termination Sequence
When a Pod is deleted (kubectl delete pod <name>):
- API Server updates Pod state: Deletion timestamp is recorded; Pod enters
Terminatingstate. - EndpointSlice controller deregisters Pod: The Pod's IP is removed from Service endpoints; kube-proxy updates iptables/IPVS rules to stop sending new traffic.
preStophook executes: Container runs the defined cleanup command.SIGTERMsent:kubeletsendsSIGTERM(signal 15) to PID 1 inside each container.- Grace period countdown:
kubeletwaits forterminationGracePeriodSeconds(default: 30s). SIGKILLsent: If containers are still running after the grace period expires,kubeletimmediately sendsSIGKILL(signal 9) to terminate all processes.
A production backend Pod running an e-commerce API is frequently restarting with exit code 137. Inspection via 'kubectl describe pod' indicates Last State: Terminated with Reason: OOMKilled. What is the root cause and the appropriate administrative remediation?
An administrator configures a multi-container Pod with an init container designed to perform database migrations and an application container. The init container script encounters a syntax error and exits with code 1. If the Pod has restartPolicy: OnFailure, what will happen?
Which of the following scenarios describes the precise difference between a failed livenessProbe and a failed readinessProbe?