Skip to content

Docker Mounting

  • All data written inside a container’s writable layer is ephemeral - it disappears when the container is removed.
  • To persist data or share it between containers and the host, you attach external storage via a mount.
  • Three main mount types: Volumes (Docker-managed), Bind Mounts (host path), tmpfs (memory-only).
TypeManaged byPersists after docker rmPerformanceBest For
VolumeDockerYesNativeProduction data, database storage
Bind MountHost OSYes (host file)NativeDevelopment, config injection
tmpfsKernel (memory)NoFastestSecrets at runtime, temp caches
  • Volumes are the recommended way to persist data in production. Docker creates a directory on the host (typically /var/lib/docker/volumes/<name>/_data) and manages it independently of the container lifecycle.
  • Volumes can be shared across multiple containers and survive container removal.
Terminal window
# Create a named volume
docker volume create db-data
# List volumes
docker volume ls
# Inspect a volume (find its host path)
docker volume inspect db-data
# Mount a volume at container run time
docker run -d \
-v db-data:/var/lib/postgresql/data \ # named volume syntax
postgres:16-alpine
# Same with --mount (more explicit, preferred in scripts)
docker run -d \
--mount type=volume,src=db-data,dst=/var/lib/postgresql/data \
postgres:16-alpine
# Read-only volume
docker run -d \
--mount type=volume,src=config-vol,dst=/etc/app,ro \
my-app
# Remove a volume (only when no containers use it)
docker volume rm db-data
# Remove all unused volumes
docker volume prune

[!important] docker compose down does NOT remove named volumes. Use docker compose down -v to also remove volumes. This is intentional - protecting production data from accidental down commands.

On Linux: /var/lib/docker/volumes/<volume-name>/_data

On Docker Desktop (macOS/Windows), Docker runs inside a Linux VM. Volume data is inside that VM’s filesystem - not directly accessible from your Mac/Windows filesystem. To inspect it:

Terminal window
# Access the Docker Desktop VM filesystem (use this exact pinned image - security)
docker run -it --rm --privileged --pid=host \
justincormack/nsenter1@sha256:5af0be5e42ebd55eea2c593e4622f810065c3f45bb805eaacf43f08f3d06ffd8
# Then navigate to the volume data inside the VM
ls /var/lib/docker/volumes/db-data/_data
  • Maps a specific host path directly into the container. Changes are immediately visible on both sides.
  • Ideal for development (mount source code into a container so edits are reflected live) or injecting configuration files.
  • Not portable - depends on a specific host path existing. Avoid in production images.
Terminal window
# Bind mount the current directory to /app in the container
docker run -d \
-v $(pwd):/app \ # short syntax
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \ # read-only
my-app
# --mount equivalent (clearer for CI/CD scripts)
docker run -d \
--mount type=bind,src=$(pwd),dst=/app \
my-app

[!caution] Changes in a bind mount are immediate and bidirectional. Deleting files in the container deletes them on the host. Be careful in development with bind mounts on directories containing important data.

  • Data stored in memory only - never written to disk. Lost when the container stops or restarts.
  • Use for sensitive data (tokens, API keys at runtime) that must not be persisted to disk, or for high-speed temporary caches.
Terminal window
# Mount a tmpfs at /tmp/cache in the container
docker run -d \
--mount type=tmpfs,dst=/tmp/cache \
my-app
# With size and mode options
# tmpfs-mode=1700 = octal 0o1700 = sticky bit + rwx for owner only (no group/other access)
docker run -d \
--mount type=tmpfs,dst=/tmp/secrets,tmpfs-size=64m,tmpfs-mode=1700 \
my-app

[!important] If the host runs out of memory, the kernel may swap tmpfs to disk, defeating the purpose. Monitor memory usage if relying on tmpfs for secret isolation.

  • Secrets and Configs are Docker Swarm primitives for distributing sensitive data to services without embedding it in images or environment variables.
  • Only available in Swarm mode - not in standalone docker run or Compose without Swarm.
Terminal window
# Create a secret from a file
echo "supersecretpassword" | docker secret create db_password -
# Use in a Swarm service
docker service create \
--name my-app \
--secret db_password \
my-app-image
# Secret is mounted at: /run/secrets/db_password
  • In Compose with Swarm, use the secrets: key. For non-Swarm Compose, use environment variables from .env files or bind-mount config files instead.

By default, volumes are stored on the local host filesystem. Volume drivers let you back a named volume with remote or distributed storage:

Terminal window
# Example: NFS-backed volume (useful with AWS EFS on EC2)
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=efs.example.com,rw \
--opt device=:/ \
efs-data

Cloud-native alternatives: AWS EFS CSI driver (EKS), Azure Files (AKS), GCS Fuse — these are typically configured at the orchestrator level, not directly with Docker.

  • Databases and stateful services in production → Named Volume
  • Source code in development → Bind Mount (live reload)
  • Config files → Bind Mount (read-only) or Docker Secret (Swarm)
  • Build artifacts or temp files → tmpfs or anonymous volume
  • Sharing data between containers → Named Volume
  • Cross-host persistence (multi-node) → Volume with NFS/cloud driver or orchestrator CSI