Quick Links

By default, Docker containers are entirely stateless. The data stored on the container is ephemeral, and will be wiped when the container shuts down. This is obviously not ideal for many applications, so Docker provides a few ways of dealing with state.

What Are Volumes?

The simplest way of making Docker data persistent is bind mounts, which literally bind a location on the host's disk to a location on the container's disk. These are simple to create and use, but are a little janky as you need to set up the directories and manage them yourself.

Volumes are like virtual hard drives managed by Docker. Docker handles storing them on disk (usually in /var/lib/docker/volumes/), and gives them an easily memorable single name rather than a directory path. It's easy to create and remove them using the Docker CLI.

These have a few other benefits besides being managed by Docker. They work on both Linux and Windows containers, they can more safely shared among multiple containers, and the volume drivers allow cloud providers to provide remote hosting for the underlying data. Overall, volumes are easier to use than bind mounts, and are recommended by Docker for managing state.

Of course, you should consider if you really need Docker data to be stored on the server. For many applications, using an external remote data store like Amazon S3 or an external database is enough to store the data they use without tying it up on the frontend server.

How Do You Use Them?

You can create a new volume from the command line with the following command:

docker volume create nginx-config

And then, when you go to run your Docker container, link it to the target in the container with the --mount flag:

docker run -d 
    

--name devtest

--mount source=nginx-config,target=/etc/nginx

nginx:latest

If you run docker inspect <name>, you'll see the volume listed under the Mounts section.

If you're using Docker Compose, the setup is easy as well. Simply add a volumes entry for each container service you have, then map a volume name to a location in the guest. You'll also need to provide a list of volumes in a top-level volumes key for Compose to provision.

version: "3.0"
    

services:

web:

image: nginx:latest

ports:

- "80:80"

volumes:

- nginx-config:/etc/nginx/

volumes:

nginx-config:

This will create the volume automatically for this Compose. If you'd like to use a premade volume from outside Compose, specify external: true in the volume configuration:

volumes:
    

cms-content:

external: true

If you'd like to instead simply do a bind mount and not bother with volumes, simply enter in a path name in place of the volume name, and forego defining the volume names.

version: "3.0"
    

services:

web:

image: nginx:latest

ports:

- "80:80"

volumes:

- /docker/nginx-config/:/etc/nginx/

You can read Docker's full documentation on using volumes with Compose if your use case requires something more specific than this.

Transfering Docker Volumes

Docker volumes are just folders created automatically and stored at /var/lib/docker/volumes/, with each volume being stored under ./volumename/_data/. To back up and restore, you can simply backup these volumes directly.

If you'd instead like to use the Docker CLI, they don't provide an easy way to do this unfortunately. To back up a container's volumes, you'll need the container name, as well as the mount location that the data is stored in.

The way to do it is a bit of a hack---you'll need to run a command in a new Docker container, bind mount the current shell directory, mount the volume to that container, then tar the directory into a backup. You'll end up with a backup.tar of the volume:

docker run --rm --volumes-from containername -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /mountlocation

Then, similarly, you can extract the archive in the target directory:

docker run --rm --volumes-from containername -v $(pwd):/backup ubuntu bash -c "cd /mountlocation && tar xvf /backup/backup.tar --strip 1"

This is still better than having to know the host location though, so you can automate this if you want to.