4.05 Multi Container Pods
-
Multi-container Pods allow multiple containers to run inside a single Kubernetes Pod when they must be tightly coupled and operate together.
-
Instead of merging everything into one large container image, Kubernetes lets you package helper components alongside the main application container.
1. App + reverse proxy
2. App + log shipper
3. App + metrics exporter
4. App + config reloader
5. App + dependency checker
6. App + service mesh proxy
🎯 What Makes Multi-Container Pods Special
Containers inside the same Pod share:
- ✅ Lifecycle (start and stop together)
- ✅ Network namespace (same IP, use
localhost) - ✅ Storage volumes
- ✅ Scheduling & node placement
- ✅ Restart behavior
Success
Multi-container Pods are meant for tightly coupled helper containers, not unrelated services.
🧠 When You SHOULD Use Multi-Container Pods
Use multi-container Pods when containers must:
- Always run together
- Scale together
- Share files directly
- Communicate via localhost
- Be deployed as one unit
Warning
If components can scale independently → use separate Deployments, not one Pod.
🧱 Basic Multi-Container Pod Example
The containers field is a list — this allows multiple containers in one Pod.
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp
spec:
containers:
- name: web-app
image: web-app
ports:
- containerPort: 8080
- name: main-app
image: main-app
Behavior:
- Both containers start together
- Both run together
- Both stop together
- No startup order guarantee
Note
Kubernetes does not guarantee which container starts first in this pattern.
🧩 Multi-Container Pod Design Patterns
There are three core patterns you must know:
- Co‑Located Containers
- Init Containers
- Sidecar Containers
1️⃣ Co‑Located Containers Pattern
Two or more containers:
- Run for full Pod lifecycle
- No guaranteed startup order
- All are long-running
Use when:
- Containers depend on each other
- No strict startup sequencing required
Note
Good for helper daemons, lightweight proxies, or tightly bound services.
2️⃣ Init Containers Pattern
Init containers run before main containers start.
Rules:
- Must complete successfully
- Run sequentially
- Main containers wait until init completes
Used for:
- Database readiness checks
- Schema migrations
- Config downloads
- Dependency validation
🛠 Init Container — DB Readiness Template
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
initContainers:
- name: db-wait
image: busybox
command:
- sh
- -c
- >
until nc -z db-service 5432;
do echo "Waiting for DB...";
sleep 2;
done
containers:
- name: app
image: my-app
Tip
Prefer init containers over sleep loops inside your main app.
🔄 Multiple Init Containers — Ordered Execution
Init containers run one-by-one in order:
initContainers:
- name: db-checker
image: busybox
command: ["sh","-c","./wait-for-db.sh"]
- name: api-checker
image: busybox
command: ["sh","-c","./wait-for-api.sh"]
Execution order:
3️⃣ Sidecar Containers Pattern
Sidecar containers:
- Run alongside main container
- Support main container
- Run for full Pod lifecycle
- Provide helper capabilities
Used for:
- Log shipping
- Metrics exporting
- Security monitoring
- Config reloaders
- Service mesh proxies
Success
Sidecars extend app behavior without modifying app code.
🧱 Sidecar Pattern — Logging Example
A common production use case:
App + Log Shipper Sidecar
Flow:
This ensures:
- Startup logs captured
- Runtime logs streamed
- Crash/termination logs preserved
⚙️ Sidecar Pattern YAML
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp
labels:
name: simple-webapp
spec:
containers:
- name: web-app
image: web-app
ports:
- containerPort: 8080
initContainers:
- name: log-shipper
image: busybox
command: 'setup-log-shipper.sh'
restartPolicy: Always
🔁 About restartPolicy
-
restartPolicyset to always for Sidecar Pattern in Init Containers. So this will also ensure the init container is terminated after the main application stops. -
That way the log shipper can catch the startup and termination logs of the main container.
Valid restartPolicy values:
- Always
- OnFailure
- Never
🧠 Sidecar vs Init Container — Difference
| Feature | Init Container | Sidecar Container |
|---|---|---|
| Runs before app | ✅ | ✅ |
| Stops before app starts | ✅ | ❌ |
| Runs during app lifecycle | ❌ | ✅ |
| Used for | Setup / checks | Continuous support |
Note
Init containers execute setup tasks and terminate, while sidecars provide continuous support services and run as long as the Pod is running.
🚀 Production Use Cases
- Log shippers (Fluent Bit, Filebeat)
- Metrics exporters
- Security agents
- Service mesh proxies (Envoy)
- Config reload helpers
🧪 Troubleshooting Multi-Container Pods
Always debug per-container.
Describe Pod
Logs per container
Exec into specific container
kubectl -n elastic-stack exec -it app -- cat /log/app.log
# Pod Name: app
# Command to execute: cat /log/app.log
Tip
Most “Pod failures” are actually one container failing.
🏭 Production Best Practices
Success
Keep each container single-purpose
Success
Use init containers for readiness logic
Success
Use sidecars for logging & metrics
Success
Define resource limits per container
Success
Add readiness & liveness probes
Success
Use shared volumes carefully
❌ Production Don’ts
Danger
Do not group unrelated services
Danger
Do not assume container start order
Danger
Do not put business logic in sidecars
Danger
Do not skip health probes