Docker Storage

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:

ScenarioRecommended Storage
Container needs no persistent dataContainer’s internal filesystem
Temporary data, tied to container lifecycle Anonymous volume
Production data, databases, app stateNamed volume
Development — editing code on the hostBind mount
Passing config files from host to containerBind 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