Docker Data Management: Volumes and Bind Mounts – Theory and Practice
This tutorial explains Docker's data management techniques, covering the concepts and hands‑on steps for using volumes and bind mounts, how to back up logs and MongoDB data, and how to restore them, providing a complete guide for reliable container data handling.
Docker Data Management Overview
Data is the core of all applications and services, and after witnessing repeated "delete‑database‑run‑away" incidents, the importance of data storage and backup becomes crystal clear. Docker offers a convenient and powerful way to handle container data. This article guides you through both theory and practical steps to master Docker's two common data management methods—Volumes and Bind Mounts—so you can manage data confidently and keep your applications well‑supported.
Docker Data Management Overview
Welcome back to the "Dream Builder" Docker tutorial series. Previously we introduced Docker images and containers by comparing "work" and "dreaming" and performed small experiments to understand how Docker turns a dream into reality, covering the key concepts of images and containers.
In the earlier article "Networking to Connect Containers," we learned that different containers can communicate via Docker networks.
In this tutorial we will bridge the "dream" (container environment) and the "reality" (host environment). Docker data management mainly consists of three methods:
Volume (the most recommended method)
Bind Mount (an early Docker data management method)
tmpfs Mount (memory‑based data management, not covered in this tutorial)
Note tmpfs mounts are only applicable on Linux operating systems.
We will now walk through a few small experiments; readers already familiar with the concepts can skip directly to the "Hands‑On Practice" section.
Volumes
Basic Commands
As mentioned in the previous article, a volume is a common Docker object type, supporting commands such as create , inspect , ls , prune , and rm .
Let's go through a workflow:
docker volume create my-volumeList all volumes:
docker volume lsThe output shows the newly created my-volume :
local my-volumeInspect the volume details:
docker volume inspect my-volumeThe command returns JSON information about my-volume :
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-volume",
"Options": {},
"Scope": "local"
}
]Tip On non‑Linux systems (Windows and macOS) the directory /var/lib/docker/volumes does not exist on the host file system; it resides inside Docker's virtual machine.
Finally, delete the volume:
docker volume rm my-volumeA single volume alone is not very useful; its purpose is to serve container data. The diagram below (source: Safari Books Online) shows how a volume bridges the host and container environments.
The volume creates a bridge between the host and container, allowing data written inside the container to be automatically stored on the host.
When creating a container with a volume, you have two options: (1) Named Volume and (2) Anonymous Volume . The following sections explain each in detail.
Creating a Named Volume
Run a container with a named volume:
docker run -it -v my-vol:/data --name container1 alpineThe -v (or --volume ) flag maps my-vol:/data , where my-vol is the volume name and /data is the mount point inside the container.
Inside the container, create a file in /data and exit:
# touch /data/file.txt
# exitNote The prompt / # is the default Alpine shell prompt; the actual command to run is touch /data/file.txt .
To verify that the file persisted, remove container1 and start a new container container2 with the same volume:
docker rm container1
docker run -it -v my-vol:/data --name container2 alpine
# ls /data
file.txt
# exitThe file is still present, demonstrating that volumes enable data sharing between containers. Docker also provides the --volumes-from flag to share volumes easily:
docker run -it --volumes-from container2 --name container3 alpine
# ls /data
file.txtContainer container3 can also access the same data.
Creating an Anonymous Volume
Creating an anonymous volume is simpler; omit the volume name:
docker run -v /data --name container4 alpineInspect the container to see the generated random volume name:
docker inspect container4The Mounts field shows details such as Name (a long random string), Source (host path), Destination ( /data ), and RW (read‑write flag).
Using Volumes in a Dockerfile
Declare a volume in a Dockerfile with the VOLUME instruction:
VOLUME /data
# or using a JSON array for multiple volumes
VOLUME ["/data1", "/data2", "/data3"]Two important notes:
Only anonymous volumes can be created this way.
If you later run docker run -v , the Dockerfile's volume configuration will be overridden.
Bind Mounts
Bind mounts were the earliest Docker data management solution. They map a host file system path directly to a container path, making them simple and flexible for data exchange.
Example: mount your desktop into a container:
docker run -it --rm -v ~/Desktop:/desktop alpineThe -v flag maps ~/Desktop (host) to /desktop (container). The --rm flag removes the container after it stops.
Inside the container, list /desktop and create a file to see it appear on the host:
# ls /desktop
# touch /desktop/from-container.txtThe file from-container.txt now exists on your desktop.
Summary
Official documentation diagram:
Volumes store container data in a dedicated area on the host file system.
Bind mounts create a direct mapping between host and container file systems.
tmpfs mounts keep data in memory (not covered here).
When specifying a volume or bind mount, the -v syntax is <source>:<target>:<options> , where the third field (e.g., ro ) makes the mount read‑only.
Tip Since Docker 17.06, the --mount flag provides a more explicit key‑value syntax that mirrors -v functionality.
Hands‑On Practice
Preparation and Goal
We will now deploy a full‑stack todo application (React front‑end, Express back‑end, MongoDB). The goals are to store and back up Express server logs outside the transient container and to back up and restore MongoDB data.
Mount a Volume for the Express Server
Add a VOLUME line to server/Dockerfile and set the LOG_PATH environment variable to /var/log/server/access.log :
# ...
# Set working directory
WORKDIR /usr/src/app
VOLUME /var/log/server
# ...
ENV MONGO_URI=mongodb://dream-db:27017/todos
ENV HOST=0.0.0.0
ENV PORT=4000
ENV LOG_PATH=/var/log/server/access.log
# ...Build the server image:
docker build -t dream-server server/Start the whole stack:
# Create a network for container communication
docker network create dream-net
# Start MongoDB container
docker run --name dream-db --network dream-net -d mongo
# Start Express API container
docker run -p 4000:4000 --name dream-api --network dream-net -d dream-server
# Build and run the React front‑end (Nginx) container
docker build -t dream-client client
docker run -p 8080:80 --name client -d dream-clientVerify all three containers are running with docker ps (screenshot omitted).
Open http://localhost:8080 , create a few todo items (screenshot omitted).
Backing Up Log Data
Because logs are stored in an anonymous volume, we back them up by creating a temporary container that shares the volume and binds a host directory:
docker run -it --rm --volumes-from dream-api -v $(pwd):/backup alpineInside the temporary container, compress the log directory:
# tar cvf /backup/backup.tar /var/log/server/Alternatively, perform the whole operation in one command:
docker run -it --rm --volumes-from dream-api -v $(pwd):/backup alpine tar cvf /backup/backup.tar /var/log/serverDatabase Backup and Restore
We will use MongoDB's mongodump and mongorestore utilities. First backup using a temporary container that shares the dream-db network and binds a host directory:
docker run -it --rm -v $(pwd):/backup --network dream-net mongo shInside the container, run:
# mongodump -v --host dream-db:27017 --archive --gzip > /backup/mongo-backup.gzThe backup file appears in the current host directory.
Alternatively, if the database container was started with a bind mount, you can back up directly with:
docker exec dream-db sh -c 'mongodump -v --archive --gzip > /backup/mongo-backup.gz'If the container was not originally started with a bind mount, this method will not work.
Disaster Recovery Exercise
Delete the database and API containers (including their volumes):
docker rm -f --volumes dream-db
docker rm -f dream-apiRe‑create the database container with a bind mount to the host backup directory:
docker run --name dream-db --network dream-net -v $(pwd):/backup -d mongoRestore the data:
docker exec dream-db sh -c 'mongorestore --archive --gzip < /backup/mongo-backup.gz'Finally, restart the API container:
docker run -p 4000:4000 --name dream-api --network dream-net -d dream-serverVisiting the todo app again should show the restored data.
Recall and Elevation
Another Way to Share Data: docker cp
You can copy files between a container and the host with docker cp :
docker cp dream-api:/var/log/server/access.log .And copy from host to container:
docker cp /path/to/some/file dream-api:/dest/pathWhile convenient for one‑off operations, docker cp requires manual path knowledge and does not scale well for repeated workflows.
Another Backup/Restore Method: docker export/import
Export an entire container's filesystem to a tar archive:
docker export my-container > my-container.tarNote export does not include the contents of data volumes.
Import the tar archive as a new image:
docker import my-container.tarThe command outputs a SHA256 image ID, which can be run or tagged as needed.
Exported tar files can be hundreds of megabytes because they contain the entire container filesystem, not just the application data.
Root Cause: Union File System (UFS)
Docker uses a Union File System to layer read‑only image layers with a writable layer for each container. Data written to the writable layer disappears when the container is removed, which is why volumes and bind mounts are essential for persisting important data.
This article demonstrates how to bypass UFS for reliable data storage, backup, and recovery.
All source code referenced in this article is available on GitHub . If you found this article helpful, please give it a like.
References
[1] "A Cup of Tea to Get Started with Docker": https://juejin.im/post/5e0f43bd5188253aa83e29d2
[2] "Dreams Interconnected: Using Network to Connect Containers": https://juejin.im/post/5e1b1072e51d453c9e1550ff
[3] tmpfs mounts: https://docs.docker.com/storage/tmpfs/
[4] Previous article: https://juejin.im/post/5e1b1072e51d453c9e1550ff
[5] Safari Books Online: https://www.oreilly.com/library/view/continuous-delivery-with/9781787125230/8af8e5f4-66d5-4fe7-8709-2b5e1ae4acdf.xhtml
[6] First article: https://juejin.im/post/5e0f43bd5188253aa83e29d2
[7] Docker documentation on volumes: https://docs.docker.com/storage/volumes
[8] Previous article: https://juejin.im/post/5e1b1072e51d453c9e1550ff
[9] Earlier tutorial: https://juejin.im/post/5e1b1072e51d453c9e1550ff
[10] The Docker Ecosystem: https://legacy.gitbook.com/book/washraf/the-docker-ecosystem/details
[11] GitHub repository: https://github.com/tuture-dev/docker-dream
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.