Docker Storage Management
Docker containers are designed to be stateless and ephemeral. When a container is removed, any data written inside its filesystem disappears with it. This model works well for stateless microservices, but it creates a problem for stateful workloads such as databases, message queues, or applications that accept user uploads. Docker storage management solves this by decoupling data from the container lifecycle. It defines how containers read and write files, where that data physically resides, and how it can be shared across multiple containers.
Docker images are built from a series of read-only layers. When a container starts, Docker adds a thin writable layer on top of the image stack. Every file creation, modification, or deletion inside the container happens in that writable layer.
- Image layers: Read-only and shareable across many containers.
- Container writable layer: Unique to each container and destroyed when the container is removed.
- Union filesystem: Merges multiple layers into a single coherent view. On most modern Linux systems, the default driver is
overlay2.
This layering model makes images lightweight and reusable, but it also means the container writable layer is a poor place for durable data. If you need data to survive container deletion, you must use a volume or bind mount.
Mount Types: Volumes, Bind Mounts, and tmpfs
Docker supports three primary ways to attach storage to a container.
Named Volumes
Named volumes are managed by Docker and stored under /var/lib/docker/volumes/ on the host. They are the recommended choice for persistent data.
- The volume lifecycle is independent of the container. Deleting the container does not delete the volume.
- Multiple containers can mount the same volume simultaneously.
- Volume drivers allow integration with cloud or network storage.
Example:
docker volume create app-data
docker run -d --name web -v app-data:/usr/share/nginx/html nginx
Bind Mounts
A bind mount maps an existing file or directory on the host directly into the container. This is common in development, where you want changes to source code on the host to reflect immediately inside the container.
docker run -d --name dev -v /home/user/app:/app node:18
Bind mounts offer flexibility but limited portability because they depend on the host's directory structure. A container can also modify files on the host, which introduces security considerations in production.
tmpfs Mounts
tmpfs mounts store data in the host's memory rather than on disk. Nothing is written to the physical storage, and the contents vanish when the container stops.
docker run -d --name cache --tmpfs /tmp:rw,size=64m redis
Use tmpfs for temporary caches or sensitive data that should never touch the disk.
Storage Drivers
The storage driver controls how image layers and the container writable layer are implemented. Most current Linux distributions use overlay2 by default.
To check the active driver:
docker info | grep "Storage Driver"
Common options include:
overlay2: Fast and efficient; the recommended driver for most workloads.devicemapper: An older approach that is being phased out.btrfsandzfs: Filesystem-dependent drivers that support features such as snapshots.
Unless you have a specific requirement, there is rarely a reason to change the storage driver manually.
Managing Volumes with the CLI
Docker provides a dedicated set of commands for volume management.
- List all volumes:
docker volume ls
- Inspect a specific volume:
docker volume inspect app-data
- Remove unused volumes:
docker volume prune
- Mount a volume as read-only:
docker run -d -v app-data:/data:ro nginx
- Share a volume between containers:
docker run -d --name writer -v shared:/data alpine sh -c "echo hello > /data/a.txt"
docker run --rm -v shared:/data alpine cat /data/a.txt
Named volumes are easier to track than anonymous volumes, which Docker creates automatically when you mount a path without a volume name.
Backup and Restore
Docker does not back up volumes automatically, but you can back them up using a temporary container and standard archiving tools.
To back up app-data into the current directory on the host:
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
tar czf /backup/app-data.tar.gz -C /data .
To restore from that archive:
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
sh -c "rm -rf /data/* && tar xzf /backup/app-data.tar.gz -C /data"
This method is application-agnostic and works for most volume types. For critical data, store the backup file outside the host, such as in object storage or a separate backup server.
Best Practices
- Prefer named volumes over bind mounts for production workloads unless you specifically need host file access.
- Always name your volumes. Anonymous volumes are difficult to track and clean up.
- Run
docker volume pruneperiodically to reclaim disk space, but verify that the data is no longer needed first. - Implement a regular backup strategy for stateful applications, and keep backup copies off the host.
- In multi-host environments, combine volume drivers with network storage to share data across nodes.
- Never rely on the container writable layer for databases, user uploads, or any data that must persist beyond the container's lifetime.
Conclusion
Docker storage management centers on persistence and sharing. Understanding image layers, the container writable layer, and the union filesystem lays the groundwork. Mastering named volumes, bind mounts, and tmpfs mounts handles day-to-day operations. Knowing how to back up, restore, and prune volumes protects data and keeps disk usage under control. By matching the mount type to the workload and following established best practices, you can run stable, reliable containerized applications in production.