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}'

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