Multi-Container Patterns
Learn the multi-container patterns used in production Kubernetes: sidecar, adapter, ambassador, init containers, and native sidecars.
Time: ~15 minutes Difficulty: Intermediate
What You Will Learn
Section titled “What You Will Learn”- Sidecar: extend app behavior without changing the app (log shipping, monitoring)
- Adapter: normalize output format (convert metrics to Prometheus format)
- Ambassador: proxy connections on behalf of the app (TLS termination)
- Init containers: run setup tasks before the app starts
- Native sidecar containers (Kubernetes 1.28+) with
restartPolicy: Always - Container lifecycle ordering and shared resources
Deploy
Section titled “Deploy”Navigate to the demo directory:
cd demos/multi-containerkubectl apply -f manifests/namespace.yamlkubectl apply -f manifests/Wait for all pods to be ready:
kubectl get pods -n multi-container-demoPart 1: Classic Patterns
Section titled “Part 1: Classic Patterns”Pattern 1: Sidecar (Log Shipping)
Section titled “Pattern 1: Sidecar (Log Shipping)”The app writes logs to a shared volume. The sidecar tails and ships them.
# App logs (writing to file)kubectl logs sidecar-logging -c app -n multi-container-demo
# Sidecar output (tailing the same file)kubectl logs sidecar-logging -c log-shipper -n multi-container-demoBoth containers share the log-volume emptyDir. The app writes, the sidecar reads. Neither knows about the other.
Pattern 2: Adapter (Format Conversion)
Section titled “Pattern 2: Adapter (Format Conversion)”The app writes metrics in a custom pipe-delimited format. The adapter converts to Prometheus format.
# Raw app metrics (custom format)kubectl exec adapter-format -c app -n multi-container-demo -- tail -5 /var/log/app/metrics.raw
# Adapter output (Prometheus format)kubectl logs adapter-format -c adapter -n multi-container-demo | tail -5Pattern 3: Ambassador (TLS Proxy)
Section titled “Pattern 3: Ambassador (TLS Proxy)”The proxy container terminates TLS and forwards to the app on localhost.
# Direct HTTP access (app container)kubectl exec ambassador-proxy -c app -n multi-container-demo -- wget -qO- http://localhost:80
# TLS access via the proxy (ambassador container)kubectl exec ambassador-proxy -c app -n multi-container-demo -- wget -qO- --no-check-certificate https://localhost:8443Pattern 4: Init Containers
Section titled “Pattern 4: Init Containers”Init containers run sequentially before the main container starts.
# See the init container logskubectl logs init-demo -c init-config -n multi-container-demokubectl logs init-demo -c init-wait-db -n multi-container-demo
# App uses the config created by initkubectl logs init-demo -c app -n multi-container-demoPart 2: Native Sidecar Containers (Kubernetes 1.28+)
Section titled “Part 2: Native Sidecar Containers (Kubernetes 1.28+)”Native sidecars are defined in initContainers with restartPolicy: Always. They start before the main containers but keep running alongside them.
Native Sidecar Proxy
Section titled “Native Sidecar Proxy”The proxy sidecar forwards requests to the main app and adds custom headers:
# Direct access to the app on port 80kubectl exec -n multi-container-demo deployment/sidecar-proxy -c app -- wget -qO- http://localhost:80
# Access via the proxy sidecar on port 8080kubectl exec -n multi-container-demo deployment/sidecar-proxy -c app -- wget -qO- http://localhost:8080
# Check proxy health endpointkubectl exec -n multi-container-demo deployment/sidecar-proxy -c app -- wget -qO- http://localhost:8080/healthThe proxy runs as a native sidecar and shares the network namespace (localhost) with the main app. Kubernetes manages its lifecycle: it starts before the main container and stops gracefully when the pod terminates.
How Native Sidecars Differ from Classic Sidecars
Section titled “How Native Sidecars Differ from Classic Sidecars”| Aspect | Classic Sidecar | Native Sidecar (1.28+) |
|---|---|---|
| Definition | containers section | initContainers with restartPolicy: Always |
| Startup order | Undefined (parallel) | Guaranteed before main containers |
| Shutdown order | Undefined | Graceful, after main containers |
| Crash recovery | Pod restart policy | Individual restart (Always) |
| Use cases | Any companion process | Proxies, log shippers, service mesh |
What is Happening
Section titled “What is Happening”manifests/ namespace.yaml # multi-container-demo namespace sidecar-logging.yaml # App + log shipper sharing a volume adapter-format.yaml # App + format converter sharing a volume ambassador-proxy.yaml # App + TLS proxy sharing localhost init-container.yaml # Two init containers + app sidecar-proxy.yaml # Native sidecar proxy (restartPolicy: Always) service.yaml # Services for proxy demosKey principle: containers in the same pod share:
- Network namespace (localhost is the same for all containers)
- Volumes (emptyDir mounts shared between containers)
- Lifecycle (all containers start together, pod dies if any crashes)
| Pattern | Communication | Use Case |
|---|---|---|
| Sidecar | Shared volume | Log collection, monitoring agents, config reload |
| Adapter | Shared volume | Format conversion, protocol translation |
| Ambassador | localhost | TLS termination, connection pooling, rate limiting |
| Init | Sequential execution | Database migrations, config download, wait-for-service |
| Native Sidecar | localhost + volumes | Proxies, service mesh, log shippers (with lifecycle guarantees) |
Experiment
Section titled “Experiment”-
Test sidecar crash recovery. Kill the native sidecar process and watch it restart automatically:
Terminal window kubectl exec -n multi-container-demo -c proxy deployment/sidecar-proxy -- kill 1kubectl get pods -n multi-container-demo -w -
Remove
restartPolicy: Alwaysfrom the proxy insidecar-proxy.yaml. The proxy will run as a traditional init container and complete before the main app starts (breaking the proxy). -
Add a failing init container to
init-container.yaml:initContainers:- name: failing-initimage: busybox:1.36command: ["sh", "-c", "exit 1"]Apply and watch the pod get stuck in
Init:Error. Init containers block the entire pod startup if they fail. -
Check resource accounting. Sidecars count toward the pod’s total resource requests and limits:
Terminal window kubectl describe pod -l app=sidecar-proxy -n multi-container-demo | grep -A5 Requests
Cleanup
Section titled “Cleanup”kubectl delete namespace multi-container-demoFurther Reading
Section titled “Further Reading”See docs/deep-dive.md for a detailed explanation of shared namespaces, native sidecar containers (KEP-753), container ordering, and real-world multi-container architectures.
Next Step
Section titled “Next Step”Move on to PersistentVolumes to learn about the Kubernetes storage layer.