A common misconception about container bind mounts is that mounting a host directory over a container directory combines the contents of both locations. It does not. The mount replaces the directory’s visible view for as long as the mount exists.
Suppose an image contains these files:
/app/config/default.yaml
/app/config/schema.json
The container is then started with a host directory mounted at /app/config:
docker run --mount type=bind,src=/srv/config,dst=/app/config example
If /srv/config contains only production.yaml, the container sees:
/app/config/production.yaml
It does not also see default.yaml or schema.json. Those image files have not been deleted, copied, or overwritten. They are merely obscured by the mount.
This behavior comes from Linux mount semantics rather than a container-specific merge algorithm. A mount attaches one filesystem tree at a mount point. Path lookup beneath that point proceeds through the mounted tree, so the directory entries from the underlying image layer are no longer reachable through their original paths.
That distinction explains a frequent failure mode: an application works when launched directly from its image, then fails after a configuration directory is mounted. The operator expected to override one file, but mounting the directory hid every image-provided file under that path.
A bind mount also differs from the image’s layered filesystem. Image layers can contribute files to a combined container root filesystem, but a bind mount is applied afterward at a particular path. It does not become another union layer whose entries are merged with the directory underneath.
If only one file should be replaced, mount that file instead of its parent directory:
docker run \
--mount type=bind,src=/srv/config/production.yaml,dst=/app/config/default.yaml,readonly \
example
Another option is to place defaults outside the mount point and have an entrypoint copy them into a writable directory before starting the application. The exact design depends on whether configuration should be immutable, generated, or persistent.
Stopping and removing the container removes the mount relationship, not the underlying image files. A new container started without that bind mount sees the original files again.
The corrected claim is precise: a bind mount does not merge host and container directory contents. It makes the mounted source the visible filesystem tree at the destination, hiding whatever was previously visible there.
Top comments (2)
This is one of those things that only bites you once before you never forget it. I have seen the failure mode described here happen with a mounted config directory where the app booted fine from the image, then failed in a compose stack because the volume hid the default config. The advice to mount the single file instead of the directory is the practical takeaway. The only case where that gets annoying is when the file needs to be edited live, since some editors replace the file instead of writing to it and the mount then points at a stale inode.
Good point about atomic saves and stale inodes! That's an important caveat when using single-file bind mounts.