Skip to content

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:

  1. Co‑Located Containers
  2. Init Containers
  3. 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
spec:
  containers:
    - name: app
      image: app-image

    - name: helper
      image: helper-image

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:

db-checker → api-checker → main container

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:

App → writes logs → shared volume → sidecar ships logs → Elasticsearch → Kibana

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

  • restartPolicy set 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

kubectl describe pod <pod>

Logs per container

kubectl logs <pod> -c app
kubectl logs <pod> -c sidecar

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