Full lesson
Explore the full explanation, examples, and visuals at your own pace.
Part 1
Your image ships three config files, but the container sees only one. The image config has three files. After the ConfigMap mount, the Pod view shows settings.yaml only. Then logging.yaml is missing, and the app crashes. The image didn't change. The mount did it.
web Deployment: the mount
Here's the cause, in the Deployment. A ConfigMap is Kubernetes storing config files, and web-config holds only settings.yaml. A volumeMount attaches that storage inside the container at a path. Look at mountPath: it's /app/config, the same directory the image already uses for its three files.
volumes:
- name: app-config
configMap:
name: web-config # holds settings.yaml only
containers:
- name: web
image: myco/web:1.4
volumeMounts:
- name: app-config
mountPath: /app/configStep 1: no mount
Start with a container and no mount. Its filesystem is the image layers, which are read-only, with a thin writable layer stacked on top. The app sees them as one filesystem. So looking at /app/config, it finds all three files: settings.yaml, logging.yaml, and routes.yaml.
Step 2: mount placed on /app/config
Now the ConfigMap mount is placed on /app/config, and it covers the whole directory. The image layers and writable layer are still there underneath, but at that path the app sees only one file, settings.yaml. A mount works like a lid over a directory. The image files sit underneath, hidden.
Three things mounts do
A mount replaces the view of the directory. It never merges, so there's no file-by-file mixing. It's applied before the app starts, so the app never sees the originals. And the image itself stays untouched, with every file still inside.
- Replace the view; never merge
- Applied before the app starts
- Image files stay untouched
Case 2: emptyDir at /app/data
The same rule applies to a second case. Here we mount an emptyDir at /app/data. An emptyDir is a scratch folder that starts out empty. The image's seed.db is still there, but it's hidden under the mount, so the app sees an empty folder and finds no data.
Why it worked on the laptop
On a laptop, a Docker named volume starts empty, and on first use Docker copies the image's content into it. So seed.db shows up. A Kubernetes volume, like emptyDir or a ConfigMap, is mounted as-is. Nothing is copied from the image, and the image files stay hidden underneath.
Laptop success can hide the bug: Kubernetes never copies image files in.
That copy only happens with Docker named volumes, so don't rely on it. Kubernetes never copies image files in. Let's look at three fixes.
Fix 1: dedicated subdirectory
The first fix is to mount the ConfigMap somewhere the image doesn't use, like /app/config/overrides. The lid lands on an empty spot, so the three image files in /app/config stay visible. The trade-off is that your app must be told to read its settings from that new path.
Fix 2: mount one file with subPath
With subPath, the mountPath points at a single file, settings.yaml, instead of the whole directory. Only that file is overlaid, so logging.yaml and routes.yaml from the image stay visible. The trade-off is that subPath mounts don't receive ConfigMap updates automatically. You'd need to restart the Pod.
volumeMounts:
- name: app-config
mountPath: /app/config/settings.yaml
subPath: settings.yamlFix 3: init container copies seed data
Here's the third fix, for the emptyDir case. The kubelet creates an empty emptyDir, then starts an init container from the same image. That container mounts the volume at another path, so seed.db is still visible to copy. When it exits successfully, the app container starts and reads seed.db. The trade-off is extra startup work in every new Pod.
Check: Pod view vs image vs spec
To diagnose this, compare three views. First, list the path inside the running Pod: only settings.yaml appears. Next, list the same path in the image with docker run: all three files show up. Then grep the Pod spec for volumeMounts, and find which mountPath targets that directory. That's your culprit.
$ kubectl exec web-7d9f -- ls /app/config
settings.yaml
$ docker run --rm --entrypoint ls myco/web:1.4 /app/config
logging.yaml routes.yaml settings.yaml
$ kubectl get pod web-7d9f -o yaml | grep -A4 volumeMountsA mount is a lid over a directory; image files sit underneath.
A mount is a lid over a directory; image files sit underneath. Before you deploy, check every mountPath against directories the image already populates.

