# Multi-Container Pods and Sidecar Patterns

> Chapter 18 of the Courseiva CNCF-CKAD curriculum — https://courseiva.com/learn/cncf-ckad/multi-container-pods-and-sidecars

**Official objective:** 1.3 — Design and manage multi-container pods, including sidecar patterns

## Introduction

Multi-container pods and sidecar patterns. The core idea is that you sometimes need more than one container working together inside a single pod to build a complete application. For the CKAD exam, understanding how to design and manage these multi-container setups is critical because many real-world applications rely on helper containers for logging, proxying, or configuration.

## The Wedding Catering Van Analogy

3 vans arrive at a wedding venue: one carries the main course (stacked trays of roast chicken), the second carries the tables and chairs, and the third carries the drinks and ice. Each van has its own job, but together they form a single 'catering service' for the event. The main-course van is the primary container — it holds the essential dinner people came for. The table-and-chair van is the init container — it sets up the venue before the dinner van can unload its trays. The drink-and-ice van is the sidecar — it runs alongside the main course van the entire evening, keeping drinks cold and ready for every guest. The wedding venue doesn't care that there are three separate vans; it only cares that the catering service shows up as one coordinated team. If the drink van breaks down, the main course van can still serve food, but guests will be unhappy without drinks. The venue manager can replace the drink van with a spare van without touching the main course van. 

This is exactly a multi-container pod in Kubernetes. The pod is the wedding venue — a single shared space where containers live and die together. The main container serves the application's core function (like the web server). The sidecar container provides a supporting service (like a log collector or proxy) that shares the same network and storage as the main container. They communicate over localhost because they share the same IP address, just like the vans communicate over walkie-talkies inside the venue. The init container runs first, sets up configuration, then exits forever — it is the table-and-chair van that leaves after setting up.

## Core explanation

A pod is the smallest deployable unit in Kubernetes. Think of it as a single 'logical host' — a wrapper that holds one or more containers. Containers inside the same pod share the same network namespace (so they can talk to each other on localhost) and the same storage volumes (so they can share files). Why would you want more than one container in a pod? Because some tasks are not the main application's responsibility but are still essential for its operation. 

For CKAD, you need to understand three patterns for multi-container pods: sidecar, ambassador, and adapter. The sidecar pattern adds a helper container that runs alongside the main container to provide a supporting function — like collecting logs, monitoring health, or serving static files. The ambassador pattern uses a proxy container that handles network communication on behalf of the main container, abstracting away the complexity of connecting to external services. The adapter pattern transforms the output of the main container into a format that other systems can understand, like converting metrics from one format to another. These patterns are not mutually exclusive; you can combine them in a single pod. 

Let us break down the sidecar pattern in detail. The main container runs your application code — for example, a Node.js web server. The sidecar container runs a lightweight log shipper like Fluentd or Filebeat. Both containers share an emptyDir volume where the main container writes its access logs. The sidecar reads those logs from the same volume and forwards them to a central logging system like Elasticsearch. Because the sidecar shares the same network namespace, the main container does not need to worry about network connectivity to the logging backend; the sidecar handles that. 

In the CKAD exam, you will be asked to create or modify YAML manifest files that define multi-container pods. You need to know how to add the 'containers' field with multiple entries, how to specify which containers run as init containers (using the 'initContainers' field), and how to configure shared volumes. Key exam traps include: 

- Forgetting that init containers run sequentially and must complete before regular containers start.
- Using restartPolicy on init containers (it cannot be set; init containers always restart until they succeed).
- Not realising that containers in the same pod share the same IP address and port space, so naming conflicts can happen if two containers try to bind to the same port.

The sidecar pattern is particularly important because it separates concerns: the main container stays simple and focused on business logic, while the sidecar handles cross-cutting concerns like logging, monitoring, or proxying. This makes the application easier to maintain and test. For example, you can upgrade the sidecar's logging agent without redeploying the main application. 

Another important concept is the init container pattern. Init containers run before any regular containers start inside the pod. They are ideal for tasks like waiting for a database to be ready, checking prerequisites, or setting up files in a shared volume. Unlike sidecars, init containers run to completion and then stop. If an init container fails, the pod does not start. The CKAD exam frequently tests init containers as a variation of multi-container pods. 

In summary, multi-container pods allow you to compose specialised containers that work together as a single unit. The sidecar pattern is the most common multi-container pattern tested on the CKAD exam. Know how to declare multiple containers in a pod spec, how to share volumes between them, and how to use init containers for prerequisite setup.

## Real-world context

Consider a company running a web application for processing customer orders. The main container runs the Python Flask application that handles incoming HTTP requests, validates data, and stores orders in a PostgreSQL database. The operations team needs to monitor the application's performance and capture all HTTP requests for debugging. They decide to deploy a sidecar container running Nginx as a reverse proxy. 

Here is what happens step by step:

- The pod is defined in a YAML file with two containers: 'web-app' and 'nginx-proxy'.
- They share an emptyDir volume mounted at '/var/log/nginx' where Nginx writes access logs.
- The web application listens on port 5000, but it is not exposed to the outside world directly. Instead, the Nginx sidecar listens on port 80 and proxies requests to 'localhost:5000'.
- Nginx also compresses responses and caches static files, reducing the load on the Python application.
- The operations team can view Nginx's access logs to understand traffic patterns without modifying the application code.
- When the team wants to add rate limiting, they update the sidecar's Nginx configuration and restart the pod — they do not touch the web application container.

This setup solves several problems: 

- Security: the web application is not directly exposed to the internet; only the sidecar is.
- Observability: logs are centralised without the application needing to handle them.
- Maintainability: the sidecar can be upgraded independently as long as the API contract (port 5000) stays the same.

The same pattern applies to other sidecar types: 

- A log shipper sidecar like Filebeat reads application logs from a shared volume and ships them to Elasticsearch.
- A monitoring sidecar like Prometheus exporter exposes application metrics from the main container.
- A service mesh sidecar like Envoy intercepts all network traffic to handle authentication, load balancing, and encryption.

In a real cloud deployment, the sidecar pattern is used heavily in service meshes like Istio, where every application pod has an Envoy proxy sidecar injected automatically. The application developer does not even need to know about the sidecar; it is added by a mutating webhook when the pod is created. 

For CKAD candidates, the practical skill is writing the YAML to define these multi-container pods. You need to specify the shared volumes using the 'volumes' field at the pod level and then mount them in each container's 'volumeMounts' section. Remember that containers within the same pod can communicate over localhost because they share the same network namespace. This is a key differentiator from communicating between pods, which requires a Service object.

## Exam focus

The CKAD exam tests multi-container pods and sidecar patterns in two main ways: creating YAML definitions and debugging existing definitions. Expect questions that require you to:

- Add a sidecar container to an existing pod definition.
- Define an init container that sets up a prerequisite (like waiting for a database).
- Configure shared volumes between multiple containers in the same pod.
- Identify the correct pattern (sidecar, ambassador, or adapter) for a given scenario.
- Recognise common traps such as port conflicts or missing volume mounts.

The exam loves testing init containers with commands like 'sleep 30' or 'sh -c "until ..."'. They will give you a scenario where the main container needs a file or service to be ready before it starts. You must add an init container that creates that file or waits for that service. The trap is forgetting to mark the container as an init container using the 'initContainers' field (instead of 'containers'). Another trap is setting a high restartPolicy on init containers — they always restart until they succeed, so restartPolicy is not allowed there.

Key definitions to memorise for the exam:

- Init container: runs to completion before any regular containers start. Declared under 'spec.initContainers'.
- Sidecar container: runs alongside the main container for the entire lifetime of the pod. Declared under 'spec.containers' as an additional item.
- Shared volume: defined at the pod level with 'spec.volumes' (e.g., emptyDir) and mounted in each container with 'volumeMounts'.
- Ambassador pattern: a sidecar that proxies network calls on behalf of the main container.
- Adapter pattern: a sidecar that transforms the main container's output (e.g., logs) into a different format.

Common trap patterns the exam sets:

- They ask you to add a sidecar that needs to read from a log file, but the log file is written to a location that is not shared via a volume. Your job is to add an emptyDir volume and mount it in both containers at the correct paths.
- They give you a scenario where an init container must run a command, but the command fails because an environment variable is missing. You must add the variable to the init container's 'env' field.
- They ask you to expose a sidecar's port (e.g., port 8080) but forget to declare the port in the container spec. The correct answer includes a 'ports' entry for the sidecar.
- They present a scenario where two containers try to bind to the same port — for example, both listening on port 80. The fix is to use different port numbers or different interfaces.

For the sidecar pattern specifically, the exam expects you to know that sidecars share the same network namespace (so they can talk via localhost) and the same pod lifecycle (so when the main container crashes, the sidecar also terminates). This is different from running two separate pods where each has its own lifecycle.

Finally, be prepared to interpret a YAML file and spot missing or incorrect fields. The exam often uses kubectl commands like 'kubectl describe pod' or 'kubectl logs' to troubleshoot. You might need to check if the sidecar's logs show any errors, or if the shared volume is mounted correctly.

## Step by step

1. **Understand the Problem** — Recognise that your application needs a supporting service (e.g., logging, monitoring, SSL termination) that should not be baked into the main container. This separation of concerns makes the main container simpler and easier to maintain.
2. **Design the Multi-Container Pod** — Decide which pattern to use: sidecar (for long-running helpers), init (for setup tasks), ambassador (for networking), or adapter (for format conversion). For CKAD, sidecar is the most common.
3. **Define the YAML Manifes** — Write the pod specification in YAML. Include the 'containers' field with multiple entries. Add a 'volumes' field at the pod level for shared storage (e.g., emptyDir). Ensure each container has a 'volumeMounts' entry referencing the shared volume.
4. **Configure Inter-Container Communication** — Since containers share the same network namespace, set up communication via localhost. For example, the main container listens on port 5000, and the sidecar proxies on port 80 forwarding to localhost:5000. Avoid port conflicts by assigning unique ports.
5. **Test and Debug** — Apply the YAML using 'kubectl apply -f pod.yaml'. Check pod status with 'kubectl get pods'. Use 'kubectl logs <pod-name> -c <container-name>' to verify each container's output. Confirm that sidecar logs show the expected data (e.g., log shipping or proxy requests).

## Comparisons

### Sidecar Pattern vs Init Container Pattern

**Sidecar Pattern:**
- Runs alongside the main container for the entire pod lifetime.
- Used for continuous supporting tasks like logging, proxying, or monitoring.
- Declared under 'spec.containers' as an additional container.

**Init Container Pattern:**
- Runs to completion before any regular containers start.
- Used for one-time setup tasks like waiting for a database or generating config files.
- Declared under 'spec.initContainers'.

### Multi-Container Pod vs Multiple Single-Container Pods

**Multi-Container Pod:**
- All containers share the same network namespace and volumes.
- Containers can communicate via localhost without a Service.
- Containers share the same lifecycle; if one fails, the pod is affected.

**Multiple Single-Container Pods:**
- Each pod has its own IP address and storage.
- Communication between pods requires a Service object or DNS.
- Each pod has an independent lifecycle; failure of one pod does not directly affect another.

### Ambassador Pattern vs Sidecar Pattern

**Ambassador Pattern:**
- Focuses on proxying network traffic to external services.
- Acts as a network proxy container (e.g., Envoy, HAProxy).
- Main container does not need to know about external service details.

**Sidecar Pattern:**
- Focuses on supporting services like logging, monitoring, or SSL termination.
- May handle non-network tasks like file processing or metrics collection.
- Commonly used for cross-cutting concerns, not just network proxying.

### Shared Volume (emptyDir) vs Persistent Volume (PVC)

**Shared Volume (emptyDir):**
- Created empty when a pod starts, deleted when the pod terminates.
- Ideal for temporary data that containers need to share within the pod.
- No persistent storage beyond the pod's lifetime.

**Persistent Volume (PVC):**
- Provides persistent storage that survives pod restarts.
- Used for data that must be retained across pod failures or updates.
- Requires a PersistentVolumeClaim (PVC) and underlying storage.

## Diagram

_A multi-container pod with an init container, a main web server, and a sidecar log shipper sharing an emptyDir volume._

```mermaid
flowchart TD
    A[Pod] --> B[Main Container - Web Server]
    A --> C[Sidecar Container - Log Shipper]
    A --> D[Init Container - Setup]
    B --> E[Shared EmptyDir Volume /logs]
    C --> E
    D --> F[Config File Creation]
    F --> E
    B --> G[Listen on port 80]
    C --> H[Ship logs to Elasticsearch]
```

## Common misconceptions

- **Misconception:** Containers in the same pod can communicate using the pod's IP address only, not localhost. **Reality:** Containers in the same pod share the same network namespace, so they can communicate using 'localhost' and the port number. They do not need to use the pod's external IP. (This misconception arises because people are used to communicating between different machines or pods over network IPs. They forget that a pod is a shared environment where all containers share the same loopback interface.)
- **Misconception:** If a sidecar container crashes, the pod stays running because the main container is still healthy. **Reality:** The pod's overall status depends on its restartPolicy. If restartPolicy is 'Always' (the default), Kubernetes will restart the sidecar container automatically. However, if the sidecar keeps crashing and exceeds the backoff limit, the pod may eventually go into CrashLoopBackOff and become unhealthy, affecting the pod's lifecycle. (Beginners assume that sidecars are optional helpers that can fail independently without affecting the pod. In reality, Kubernetes treats all containers in a pod as a unit; if any container is unhealthy, the pod as a whole is considered unhealthy, and the scheduler may restart or evict it.)
- **Misconception:** Init containers can be used to perform long-running background tasks because they run to completion but can be restarted. **Reality:** Init containers are designed for short-lived tasks that must complete before the pod starts. They run sequentially and once they finish, they stop permanently. They cannot be used for long-running background tasks; those belong in sidecar containers. (The name 'init container' sounds like it could initialise long-running processes, but the key point is that they run to completion and then exit. People confuse them with sidecars, which run continuously.)
- **Misconception:** You can communicate between containers in the same pod using a Service object just like between pods. **Reality:** Containers within the same pod do not need a Service object to communicate; they can use localhost directly. Using a Service for intra-pod communication is unnecessary and overcomplicated. (This misconception stems from overgeneralising the concept of Services for pod-to-pod communication. Inside a pod, the containers already share a network stack, so introducing a Service adds unnecessary abstraction.)
- **Misconception:** All containers in a pod must run the same application code or base image. **Reality:** Containers in a pod can run completely different images and serve different purposes. For example, one container can run a web server (e.g., Nginx) and another can run a log shipper (e.g., Filebeat). They only need to coordinate via shared volumes or network. (Newcomers think of a pod as a single 'application unit' and assume all containers contribute to the same codebase. In reality, they are independent processes that collaborate, similar to how different tools work together in a system.)

## Key takeaways

- A pod can contain multiple containers that share the same network namespace and storage volumes, allowing them to communicate via localhost.
- The sidecar pattern adds a helper container that runs alongside the main container to handle cross-cutting concerns like logging, proxying, or monitoring.
- Init containers run to completion before any regular containers start and are used for setup tasks like waiting for a database or creating configuration files.
- Containers in the same pod share the same lifecycle; if one container fails repeatedly, the pod may be restarted or evicted based on the restartPolicy.
- Shared volumes in a pod are defined at the pod level using the 'volumes' field and mounted into each container using 'volumeMounts'.
- Kubernetes supports three multi-container patterns: sidecar, ambassador (proxy), and adapter (format conversion), but the sidecar is the most tested on CKAD.

## FAQ

**Can I have more than two containers in a single pod?**

Yes. A pod can contain any number of containers, but keep it reasonable (typically 2-5) to avoid complexity and resource contention. All containers share the same network and volumes.

**How do I make a sidecar container start before the main container?**

You cannot control the order of regular containers; they all start simultaneously. If you need a container to run first, use an init container. Sidecars are designed to run concurrently with the main container.

**Do sidecar containers need their own ports exposed in the pod spec?**

Not necessarily, but if the sidecar offers a network service (like a proxy or exporter), you should declare its port in the container's 'ports' field for documentation and to avoid port conflicts. The pod's ports are not automatically exposed outside; you need a Service for that.

**What happens if the sidecar container uses too much memory?**

If the sidecar exceeds its resource limits, Kubernetes will kill and potentially restart it (depending on the restartPolicy). This can degrade the main container's functionality because the sidecar is missing. Always set resource requests and limits for all containers.

**Can I update a sidecar without restarting the main container?**

No. Containers in a pod share the same lifecycle. To update a sidecar's image or configuration, you must recreate the entire pod (e.g., by deleting it and letting a Deployment recreate it). However, you can use a Deployment to roll out updates with zero downtime by updating the pod template.

**Is there a performance overhead to using sidecars?**

Yes. Each sidecar uses CPU, memory, and network resources. Running many sidecars in a cluster can increase resource usage. The overhead is usually acceptable for typical sidecar functions like logging or monitoring, but you should monitor usage and avoid unnecessary sidecars.

## Check your understanding

1. **How do you declare a sidecar container in a pod YAML file?**

   Answer: Add an additional item under the 'containers' array in the pod spec. Each container has its own 'name', 'image', and other fields.

2. **What is the difference between a sidecar and an init container?**

   Answer: A sidecar runs continuously alongside the main container; an init container runs to completion before any regular containers start and then exits.

3. **Do containers in the same pod share the same IP address?**

   Answer: Yes, they share the same network namespace and thus the same IP address (the pod's IP). They can communicate via localhost.

4. **Can you use a Service to expose a sidecar container's port?**

   Answer: Yes, by creating a Service that selects the pod by label, you can expose the sidecar's port to the cluster or externally.

5. **How does a sidecar access logs from the main container?**

   Answer: They share a volume (e.g., emptyDir) where the main container writes logs, and the sidecar reads from the same volume.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/cncf-ckad/multi-container-pods-and-sidecars
