Part of the series Kubernetes basics

Kubernetes Deployments, Sidecars, and Storage: A simple example

One app writes a message. One helper reads it. Follow this small example to understand how Kubernetes keeps apps running and shares their files.

, 8 min read

Imagine you have an app that writes this message into a file every five seconds:

Hello from the app

You want a helper to read that file and show the messages in the logs.

We will use this one example throughout the post. First, let’s understand where the app and helper live.

1. A Pod holds the app and its helper

A container runs a program. In our example, one container runs the app and another runs the helper.

A Pod holds these two containers together. They run on the same machine, called a node.

One Pod
├── App container: writes a message
└── Helper container: reads the message

The helper is called a sidecar because it runs beside the main app and helps it.

For example, the main app might run an online shop. Its sidecar might read the shop’s log files and send them to a logging system. The app and helper have different jobs, but they work together.

2. A Deployment keeps the Pod running

Suppose you want one copy of this Pod running all the time.

A Deployment stores that instruction: “Keep one copy of my Pod running.” If the Pod is deleted, Kubernetes creates a replacement through a controller called a ReplicaSet.

The Deployment also stores the instructions for building the Pod: which containers to run and which volumes to give them. These instructions are called the Pod template.

spec:
  replicas: 1

Here, replicas: 1 means one copy. With replicas: 2, you ask for two Pods, each with its own app and helper.

Keeping the app running and keeping its files are separate jobs. A replacement Pod starts fresh unless you connect it to storage that already holds the files.

3. A volume lets the containers share a file

The app writes to /output/report.log. How can the helper read it?

Containers have separate filesystems. Being in the same Pod does not automatically give them access to each other’s files.

We give both containers the same volume: a place to store files. Each container accesses it through a mount, which makes the volume appear at a directory inside that container.

In our example:

  • The app sees the volume at /output.
  • The helper sees the same volume at /input.
  • The app’s /output/report.log is the helper’s /input/report.log.

Think of two doors opening into the same cupboard. The doors have different names, but the contents are the same.

Open the diagram. On a phone, swipe sideways inside it.

The app writes a message, the shared volume holds it, and the sidecar reads it.

What the YAML means

At Pod level, define a volume:

volumes:
  - name: shared-files
    emptyDir: {}

Inside the app container, connect it to /output:

volumeMounts:
  - name: shared-files
    mountPath: /output

Inside the helper container, connect the same volume to /input:

volumeMounts:
  - name: shared-files
    mountPath: /input
    readOnly: true

The matching name, shared-files, connects both mounts to the same volume. readOnly: true lets the helper read files without changing them through that mount.

These are small pieces of a larger YAML file. The complete example is below.

4. emptyDir keeps files while this Pod exists

emptyDir is a temporary volume. It starts empty when the Pod starts using it.

For our example, it is enough: the app and helper just need a shared working folder.

What happens? Does the file stay?
The app container restarts inside the same Pod Yes.
The helper container restarts inside the same Pod Yes.
The Pod is deleted and replaced No. The new Pod gets an empty volume.

A container restart and a Pod replacement are different. The volume belongs to the Pod, so it survives a container restart inside that Pod. It does not move into a replacement Pod.

Also, two Pods have two separate emptyDir volumes. They do not share one folder.

5. Use a PVC when the files must survive Pod replacement

Imagine the file contains customer uploads. You need those files after the Pod is replaced.

Use persistent storage through a PersistentVolumeClaim, usually shortened to PVC.

The names sound complicated, but their jobs are small:

Name Meaning in plain language
PVC The app’s request: “I need some storage.”
PV The Kubernetes object representing the storage assigned to that request.
StorageClass Instructions for creating storage when a new claim needs it.

The flow is:

App needs storage → PVC requests it → PV provides it → Pod mounts it

A replacement Pod can mount the same claim and use the existing files. The storage system and permissions still need to allow that access.

Open the storage flowchart.

For a temporary report, emptyDir may be fine. For files you must keep, use suitable persistent storage and keep backups. Deleting a PVC can also delete its backing storage, depending on its reclaim policy.

6. Run the small example

You need kubectl connected to a practice Kubernetes cluster. Download report-demo.yaml, then run:

kubectl apply -f report-demo.yaml
kubectl rollout status deployment/report-demo -n sidecar-demo

The file creates a namespace named sidecar-demo and a Deployment named report-demo. A namespace is a named group for Kubernetes resources.

The app repeats this command every five seconds:

echo "Hello from the app" >> /output/report.log

>> adds the message to the end of the file.

The helper waits until the file exists, then reads it continuously:

tail -n+1 -f /input/report.log

Here, -n+1 starts at the first line. -f keeps watching for new lines. The wait matters because either container can start first in this example.

See the complete YAML file
apiVersion: v1
kind: Namespace
metadata:
  name: sidecar-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: report-demo
  namespace: sidecar-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: report-demo
  template:
    metadata:
      labels:
        app: report-demo
    spec:
      containers:
        - name: writer
          image: busybox:1.37.0
          command: ["sh", "-c"]
          args:
            - |
              while true; do
                echo "Hello from the app" >> /output/report.log
                sleep 5
              done
          resources:
            requests:
              cpu: 10m
              memory: 16Mi
            limits:
              memory: 64Mi
          volumeMounts:
            - name: shared-files
              mountPath: /output
        - name: reader
          image: busybox:1.37.0
          command: ["sh", "-c"]
          args:
            - |
              until [ -f /input/report.log ]; do
                sleep 1
              done
              exec tail -n+1 -f /input/report.log
          resources:
            requests:
              cpu: 10m
              memory: 16Mi
            limits:
              memory: 64Mi
          volumeMounts:
            - name: shared-files
              mountPath: /input
              readOnly: true
      volumes:
        - name: shared-files
          emptyDir:
            sizeLimit: 64Mi

The resources settings reserve a little CPU and memory and put a limit on memory use. The volume’s sizeLimit sets a maximum size for this temporary folder. Those settings are included in the download; focus first on containers, volumes, and volumeMounts.

See the helper’s output

kubectl logs deployment/report-demo -c reader -n sidecar-demo --tail=5

You should see repeated messages:

Hello from the app
Hello from the app
Hello from the app

-c reader chooses the helper container. The helper prints the file’s contents to its standard output, which kubectl logs can show. Kubernetes does not automatically show every file in a container as a log.

Prove both containers see the same files

Write a second file through the app:

kubectl exec deployment/report-demo -c writer -n sidecar-demo -- \
  sh -c 'echo shared-file-test > /output/proof.txt'

Read it through the helper:

kubectl exec deployment/report-demo -c reader -n sidecar-demo -- \
  cat /input/proof.txt

Expected output:

shared-file-test

This shows the same file through two different mount paths.

See what happens when the Pod is replaced

In this practice workload, ask the Deployment to replace its Pod:

kubectl rollout restart deployment/report-demo -n sidecar-demo
kubectl rollout status deployment/report-demo -n sidecar-demo

Read the test file again:

kubectl exec deployment/report-demo -c reader -n sidecar-demo -- \
  cat /input/proof.txt

You should get a “No such file or directory” error. The new Pod has a new emptyDir.

The app starts writing report.log again, but it never recreates proof.txt. That is why the test file is useful: it shows that the old files were lost.

When finished, remove the practice Deployment:

kubectl delete deployment report-demo -n sidecar-demo

7. If something does not work

Start with these three checks:

Problem What to check
The Pod does not start Run kubectl get pods -n sidecar-demo, then describe the Pod to read its events.
The helper cannot find the file Check that both containers mount shared-files and use the correct paths.
The file exists but logs are empty Check the reader’s command and use -c reader when reading logs.

For a PVC, Pending means the claim is still waiting for storage or for information needed to assign it. Read the claim’s events with kubectl describe pvc <claim-name> -n <namespace>.

You may also see the word attach. Attaching connects some kinds of storage to a node. Mounting makes that storage available at a directory. Kubernetes can record attachment status in a VolumeAttachment object. You usually inspect it only when an attachment error needs investigation.

Remember the example

The Deployment keeps the Pod running. The Pod holds the app and its helper. The sidecar reads the app’s file. The volume shares that file, and each mount gives a container a path to it.

Use emptyDir when losing the files with the Pod is acceptable. Use a PVC with suitable persistent storage when the files must survive Pod replacement.

For more detail, see the official guides to Deployments, sidecars, volumes, and persistent storage.