Multi-Container Pods

A comprehensive guide to running multiple containers inside a single Kubernetes Pod — the patterns, the YAML anatomy, and the exam traps. Synthesized from CKA Day 11 — Multi Container Pod Kubernetes: Sidecar vs Init Container.

Why Multi-Container Pods?

While the best practice is one container per Pod, there are legitimate cases where co-locating containers is necessary:

  • Tight coupling: The auxiliary process must share the network namespace (localhost) or filesystem with the main app
  • Co-scheduling guarantee: Both containers must always run on the same node
  • Atomic lifecycle: The sidecar/init should be created/destroyed with the main app, not independently

Anti-pattern: Using a multi-container Pod as a substitute for a Deployment. If containers don’t need to share a network namespace or volume, they should be separate Pods (possibly in the same Deployment). Source: CKA Day 11

Shared Resources

Containers in the same Pod share:

ResourceImplication
Network namespaceSame IP address, port space, and localhost. Containers can reach each other via localhost:<port>
Storage volumesVolumes mounted in the Pod spec are accessible to all containers that mount them
IPC namespaceOptional shared memory and Unix domain sockets (set shareProcessNamespace: true)
UTS namespaceSame hostname

Security note: Because containers share the network namespace, a compromised sidecar can sniff traffic bound for the main app. Use NetworkPolicies to restrict east-west traffic even within the same Pod when possible. Source: CKA Day 11

Container Roles

There are three distinct container roles inside a Pod:

RoleSection in YAMLLifecycleUse Case
Init Containerspec.initContainersRuns to completion before main containers startSetup, validation, migration
Main Containerspec.containersLong-running primary workloadApplication server, database, worker
Sidecar Containerspec.containersLong-running auxiliary workloadLogging, monitoring, proxy, config reloader

Multi-Container Pod YAML Anatomy

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-demo
  labels:
    app: web
spec:
  initContainers:
  - name: init-permissions
    image: busybox:1.36
    command: ['sh', '-c', 'chmod 755 /shared']
    volumeMounts:
    - name: shared-data
      mountPath: /shared
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-data
      mountPath: /shared
  - name: log-processor
    image: fluentd:latest
    volumeMounts:
    - name: shared-data
      mountPath: /shared
  volumes:
  - name: shared-data
    emptyDir: {}

Key ordering rules:

  1. All initContainers run in the order defined, one at a time
  2. Only when all init containers succeed do the containers start
  3. All containers run concurrently

Common Multi-Container Patterns

Sidecar (Logging/Monitoring)

The sidecar reads logs or metrics from a shared volume and forwards them to a central system.

containers:
- name: app
  image: my-app
  volumeMounts:
  - name: logs
    mountPath: /var/log/app
- name: log-shipper
  image: fluentd
  volumeMounts:
  - name: logs
    mountPath: /var/log/app
volumes:
- name: logs
  emptyDir: {}

Adapter (Output Transformation)

Transform the main app’s output into a format expected by downstream consumers.

containers:
- name: nginx
  image: nginx
- name: nginx-exporter
  image: nginx/nginx-prometheus-exporter
  args: ["-nginx.scrape-uri", "http://localhost:8080/stub_status"]

Ambassador (Proxy/Connection Pooling)

Proxy external connections so the main app thinks it’s talking to a local service.

containers:
- name: app
  image: my-app
- name: redis-proxy
  image: twemproxy

Troubleshooting Multi-Container Pods

SymptomDiagnosisCommand
Pod stuck PendingInit container hasn’t finishedkubectl describe pod <name>
Pod Init:ErrorInit container failedkubectl logs <pod> -c <init-container>
CrashLoopBackOffMain container exits repeatedlykubectl logs <pod> -c <main-container>
Sidecar not workingVolume path mismatchkubectl exec -it <pod> -c <sidecar> -- ls <mountPath>
OOMKilledMemory limit too lowkubectl describe pod <pod> → check Last State

CKA Exam Speed Patterns

# Create a multi-container Pod quickly
kubectl run multi --image=nginx --dry-run=client -o yaml > pod.yaml
# Then edit the YAML to add the second container and init container
 
# Get logs from a specific container
kubectl logs my-pod -c sidecar
 
# Execute into a specific container
kubectl exec -it my-pod -c main -- /bin/sh
 
# Check init container status
kubectl get pod my-pod -o jsonpath='{.status.initContainerStatuses}'

Practical Practice

Exam-style hands-on tasks for this topic. Complete each task before reviewing the solution. Time yourself — CKA tasks average 5–7 minutes.

Task 1: Create a Two-Container Pod You are asked to create a Pod named api-cache with two containers: api using image nginx and cache using image redis:alpine. Requirements: Use --dry-run=client -o yaml, edit the manifest to add the second container, then apply. Verification: kubectl get pod api-cache and kubectl describe pod api-cache Solution:

kubectl run api-cache --image=nginx --dry-run=client -o yaml > api-cache.yaml
# Edit api-cache.yaml to add the redis:alpine container in spec.containers
kubectl apply -f api-cache.yaml

Task 2: Add an Init Container that Waits for a Service You are asked to add an init container to an existing Pod secure-app that waits until a Service named db is reachable on port 5432 before the main app starts. Requirements: The init container must use busybox:1.36 and nc -z db 5432 in a loop. Verification: kubectl get pod secure-app transitions from Init:0/1 to Running. Solution:

kubectl get pod secure-app -o yaml > secure-app.yaml
# Add spec.initContainers with busybox waiting for db:5432
kubectl apply -f secure-app.yaml --force

Task 3: Adapter Pattern Sidecar You are asked to create a Pod where the main nginx container writes logs to /var/log/nginx/access.log, and a sidecar busybox container tails that file and prints to stdout. Requirements: Share an emptyDir volume between both containers mounted at /var/log/nginx. Verification: kubectl logs <pod> -c sidecar shows nginx log lines. Solution:

apiVersion: v1
kind: Pod
metadata:
  name: adapter-pod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  - name: sidecar
    image: busybox
    command: ['sh', '-c', 'tail -f /var/log/nginx/access.log']
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  volumes:
  - name: logs
    emptyDir: {}

Tags: kubernetes pod multi-container sidecar init-container cka devops patterns