Docker Storage

Containers are ephemeral by nature. When you remove one, everything inside it goes with it. Logs, databases, configuration, all of it.
For many containers that’s fine. A short-lived task container doesn’t need to leave anything behind. But for anything that handles real data, like a database, a file server, a password manager, you need storage that outlasts the container itself.
Docker gives you a few ways to handle this.
Persistent vs Non-Persistent Storage
By default, any file a container writes is stored inside the container’s own filesystem. This is non-persistent storage.
When the container is removed, those files are gone. They don’t survive a docker rm. This is intentional, as containers are meant to be disposable.
Persistent storage is stored outside the container. The container can be stopped, removed, and recreated, and the data remains untouched. You can even have multiple containers sharing access to the same persistent storage.
Docker provides two main ways to get persistent storage. These are volumes and bind mounts.
Volumes
A Docker volume is a storage area that Docker creates and manages itself. You don’t choose where it lives on the host filesystem, as Docker handles that internally.
To create one:
docker volume create myVolume
To see your volumes:
docker volume ls
To get more detail, including where Docker is actually storing it on the host:
docker volume inspect myVolume
The `Mountpoint` field in that output shows the directory on the host where the volume data lives. You don’t usually need to touch this directly. Docker manages it for you.
Using a Volume with a Container
Attach a volume when starting a container using --volume:
docker run -it --name myContainer --volume myVolume:/data ubuntu
The format is volume_name:mount_point. So myVolume:/data mounts the volume at /data inside the container. Any files written to /data are actually stored in the volume, not in the container’s internal filesystem.
If the container is removed, the volume, and all its data, remains.
You can also mount a volume as read-only if you want to protect the data from being changed:
docker run -it --volume myVolume:/data:ro ubuntu
The :ro suffix at the end of the mount point makes it read-only.
Named vs Anonymous Volumes
The volumes we’ve looked at so far are named volumes. You create them, give them a name, and assign them to a container.
Anonymous volumes are created automatically when a container starts, without a pre-existing name. You create one by giving only the mount point, not a volume name:
docker run -it --volume /data ubuntu
Docker creates the volume in the background and mounts it at /data. But unlike named volumes, anonymous volumes are tied to the container’s lifecycle. When the container is removed (particularly with --rm), the anonymous volume is removed too.
Anonymous volumes are really only useful for temporary data. Named volumes are what you’ll want for anything important.
Why Use Volumes?
- Simple to manage via the Docker CLI or API
- Safe to share between multiple containers
- Good performance — no special copy-on-write overhead for reads and writes
- Portable — volumes can be backed up and moved
Bind Mounts
A bind mount is different. Instead of Docker managing a storage area, you pick a specific file or directory on the host and mount it directly into the container.
docker run -it --name myContainer --volume /home/luke/config:/app/config ubuntu
The left side is the path on the host. The right side is where it appears inside the container. Both sides see exactly the same files . Changes made from either side are reflected immediately on the other.
If you’re on Windows, the host path uses Windows-style formatting:
docker run -it --volume C:\Users\luke\config:/app/config ubuntu
When to Use Bind Mounts
Bind mounts are particularly useful for:
- Development — Mount your source code directory into a container so changes on the host are immediately visible inside the container, no rebuild needed.
- Passing configuration — Mount a config file from the host into the container. Edit the file on the host, restart the container, and the container picks up the new config.
- Accessing container files from the host — Make container output visible on the host without copying files out manually.
A Word of Caution
Bind mounts expose host files to the container directly. If the mount point is configured incorrectly, you could overwrite important locations inside the container. And if sensitive host directories are mounted, a compromised container could access them.
Bind mounts are useful, but use them deliberately. Know exactly what you’re mounting and why.
Choosing the Right Storage Type
Here’s a quick way to think about it:
| Scenario | Recommended Storage |
| Container needs no persistent data | Container’s internal filesystem |
| Temporary data, tied to container lifecycle | Anonymous volume |
| Production data, databases, app state | Named volume |
| Development — editing code on the host | Bind mount |
| Passing config files from host to container | Bind mount |
Default to named volumes for persistent data. Reach for bind mounts when you specifically need the host and container to share files.
A Practical Note on Syntax
The --volume flag is the most common way to attach storage. There’s also a --mount flag that’s more verbose but very explicit:
docker run -it --mount type=volume,src=myVolume,dst=/data ubuntu
Both work. --mount makes the intent clearer, which is useful in compose files and scripts. --volume is shorter and common in quick commands. Pick whichever you prefer.
Where to Go Next
The full course includes hands-on demos of volumes, bind mounts, and how they fit into real Docker deployments:
Watch the free YouTube course → COMING SOON
Enrol in the full Udemy course → COMING SOON