DEV Community

Cover image for Using Volumes in Docker
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya Originally published at docs.vultr.com

Using Volumes in Docker

Docker volumes are a persistent storage mechanism that decouples your data from the container lifecycle, letting containers retain data across restarts and removals and allowing multiple containers to share a common data source. Unlike bind mounts, Docker manages volumes internally and stores them under /var/lib/docker/volumes/ on Linux systems. This guide shows how to create and inspect Docker volumes, interact with their contents, use them in Docker Compose workflows, back up and restore volume data, and reference volumes with the VOLUME instruction in a Dockerfile. By the end, you'll have a container with a named, persistent volume that you can inspect, back up, restore, and manage through both the CLI and Docker Compose.


Quick Reference

The following commands demonstrate how to manage persistent data using volumes:

$ docker volume create web_content
$ docker container run -d -v web_content:/app/data --name volume_demo httpd
$ docker volume ls
$ docker volume inspect web_content
$ docker volume rm web_content
$ docker volume prune
Enter fullscreen mode Exit fullscreen mode

When to Use Docker Volumes

Use Docker volumes instead of bind mounts when:

  • You want data to persist across container restarts or removals.
  • You need consistent storage behavior across Linux, macOS, and Windows.
  • You prefer Docker-managed storage lifecycle and internal volume handling.
  • You plan to back up or restore application data regularly.
  • You need to share persistent data between multiple containers.

Bind mounts are more suitable for development environments where code changes on the host need to reflect immediately in the container. For production environments, Docker volumes are the preferred choice due to their portability, safety, and lifecycle integration.

Manually Create and Link Volumes

1. Create a Docker volume:

$ docker volume create web_content
Enter fullscreen mode Exit fullscreen mode

This creates a Docker-managed volume named web_content. Docker stores it internally and tracks its metadata.

Output:

web_content
Enter fullscreen mode Exit fullscreen mode

2. Run a container and mount the volume:

$ docker container run -d -v web_content:/usr/local/apache2/htdocs --name apache_with_volume httpd
Enter fullscreen mode Exit fullscreen mode

This launches a container with the httpd image and mounts the named volume at the web server's root. -d runs the container in detached mode, -v web_content:/usr/local/apache2/htdocs mounts the volume to Apache's web root, and --name apache_with_volume assigns the container a custom name.

Output:

03d0120e51dd822148d4c4c0464473cdad8a916e22ba5685ec495e47573dc722
Enter fullscreen mode Exit fullscreen mode

3. List all volumes:

$ docker volume ls
Enter fullscreen mode Exit fullscreen mode

Output:

DRIVER    VOLUME NAME
local     web_content
Enter fullscreen mode Exit fullscreen mode

4. Inspect the volume:

$ docker volume inspect web_content
Enter fullscreen mode Exit fullscreen mode

This confirms the volume's internal mount path and attributes, useful for debugging and manual access.

Output:

[
   {
       "CreatedAt": "2025-06-06T17:38:52Z",
       "Driver": "local",
       "Labels": null,
       "Mountpoint": "/var/lib/docker/volumes/web_content/_data",
       "Name": "web_content",
       "Options": null,
       "Scope": "local"
   }
]
Enter fullscreen mode Exit fullscreen mode

5. List all containers:

$ docker container ls -a
Enter fullscreen mode Exit fullscreen mode

Output:

CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS     NAMES
03d0120e51dd   httpd     "httpd-foreground"   46 seconds ago   Up 45 seconds   80/tcp    apache_with_volume
Enter fullscreen mode Exit fullscreen mode

6. Check volume usage by container:

$ docker container inspect --format={{.Mounts}} apache_with_volume
Enter fullscreen mode Exit fullscreen mode

This shows where the volume is mounted inside the container, validating its usage path.

Output:

[{volume web_content /var/lib/docker/volumes/web_content/_data /usr/local/apache2/htdocs local z true }]
Enter fullscreen mode Exit fullscreen mode

7. Stop the container:

$ docker container stop apache_with_volume
Enter fullscreen mode Exit fullscreen mode

This halts the container without removing it, preserving the volume and data.

Output:

apache_with_volume
Enter fullscreen mode Exit fullscreen mode

8. Remove the container:

$ docker container rm apache_with_volume
Enter fullscreen mode Exit fullscreen mode

This removes the container while leaving the named volume intact for reuse.

Output:

apache_with_volume
Enter fullscreen mode Exit fullscreen mode

9. Remove the volume:

$ docker volume rm web_content
Enter fullscreen mode Exit fullscreen mode

This permanently removes the volume and its contents.

Output:

web_content
Enter fullscreen mode Exit fullscreen mode

Warning: Removing a volume deletes all stored data. Ensure backups exist before running this command in production environments.

Use Volumes in Dockerfiles

While Dockerfiles can't create named volumes, they can define mount points expected at runtime using the VOLUME instruction. Docker automatically creates an anonymous volume for such paths unless you explicitly mount a named one when running the container.

1. Navigate to the user's home directory and create a docker directory:

$ cd ~
$ mkdir docker
Enter fullscreen mode Exit fullscreen mode

2. Navigate into the new directory:

$ cd docker/
Enter fullscreen mode Exit fullscreen mode

3. Create a Dockerfile:

$ nano Dockerfile
Enter fullscreen mode Exit fullscreen mode

4. Add the following content to the Dockerfile:

FROM httpd
VOLUME ["/usr/local/apache2/htdocs"]
CMD ["httpd-foreground"]
Enter fullscreen mode Exit fullscreen mode

Save and close the file. This Dockerfile builds an Apache-based image that treats /usr/local/apache2/htdocs as a volume path.

5. Build the image:

$ docker image build -t apache_with_volume .
Enter fullscreen mode Exit fullscreen mode

This builds the Dockerfile and creates a new image named apache_with_volume.

Output:

[+] Building 0.1s (5/5) FINISHED                            docker:default
 => [internal] load build definition from Dockerfile        0.0s
 => => transferring dockerfile: 110B                        0.0s
 => [internal] load metadata for docker.io/library/httpd    0.0s
 => => writing image sha256:c886f948f696b...                0.0s
 => => naming to docker.io/library/apache_with_volume       0.0s
Enter fullscreen mode Exit fullscreen mode

6. Run the container:

$ docker container run -d --rm apache_with_volume
Enter fullscreen mode Exit fullscreen mode

-d runs the container in detached mode, and --rm automatically removes the container when it exits. Docker automatically creates an anonymous volume and mounts it at /usr/local/apache2/htdocs, as defined in the Dockerfile.

To use a named volume instead of an anonymous one, pass the -v flag explicitly:

$ docker container run -d --rm -v web_content:/usr/local/apache2/htdocs apache_with_volume
Enter fullscreen mode Exit fullscreen mode

This lets you control the volume lifecycle while still benefiting from Dockerfile-defined mount points.

Interact with Docker Volumes

Docker does not let you directly mount volumes on the host system, but you can access and modify volume contents from within a running container.

1. Start a container with the volume mounted:

$ docker container run -d --name apache_with_volume -v web_content:/usr/local/apache2/htdocs httpd
Enter fullscreen mode Exit fullscreen mode

Output:

03d0120e51dd8221...
Enter fullscreen mode Exit fullscreen mode

2. Create an HTML file on your host machine:

$ echo "<h1>Hello Apache from docker volume</h1>" > index.html
Enter fullscreen mode Exit fullscreen mode

3. Copy the file into the container:

$ docker cp index.html apache_with_volume:/usr/local/apache2/htdocs/
Enter fullscreen mode Exit fullscreen mode

Output:

Successfully copied 2.05kB to apache_with_volume:/usr/local/apache2/htdocs/
Enter fullscreen mode Exit fullscreen mode

4. View the file contents inside the container:

$ docker exec apache_with_volume \
   cat /usr/local/apache2/htdocs/index.html
Enter fullscreen mode Exit fullscreen mode

Output:

<h1>Hello Apache from docker volume</h1>
Enter fullscreen mode Exit fullscreen mode

5. Back up the volume from inside the container:

$ docker exec apache_with_volume \
   tar czf /usr/local/apache2/htdocs/httpd_backup.tar.gz -C /usr/local/apache2/htdocs .
Enter fullscreen mode Exit fullscreen mode

This creates a compressed .tar.gz archive of the volume's contents inside the container.

6. Copy the backup file from the container to the host:

$ docker cp apache_with_volume:/usr/local/apache2/htdocs/httpd_backup.tar.gz .
Enter fullscreen mode Exit fullscreen mode

Output:

Successfully copied 2.05kB to /home/john/docker/.
Enter fullscreen mode Exit fullscreen mode

7. Restore the volume by copying the archive back and extracting it:

$ docker cp httpd_backup.tar.gz apache_with_volume:/usr/local/apache2/htdocs/
Enter fullscreen mode Exit fullscreen mode
$ docker exec apache_with_volume \
   tar xzf /usr/local/apache2/htdocs/httpd_backup.tar.gz -C /usr/local/apache2/htdocs
Enter fullscreen mode Exit fullscreen mode

The first command copies the backup archive into the container, and the second extracts its contents into the volume directory.

Use Volumes with Docker Compose

Docker Compose supports named volumes natively — they're automatically created and managed alongside the service lifecycle.

1. Create a docker-compose directory in your home path:

$ cd ~
$ mkdir docker-compose
Enter fullscreen mode Exit fullscreen mode

2. Navigate to the new directory:

$ cd docker-compose/
Enter fullscreen mode Exit fullscreen mode

3. Create a docker-compose.yml manifest:

$ nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

4. Add the following YAML content to the file:

services:
   web:
       image: httpd
       volumes:
           - web_content:/usr/local/apache2/htdocs

volumes:
   web_content:
Enter fullscreen mode Exit fullscreen mode

This tells Docker Compose to create a volume named web_content and mount it to the container at /usr/local/apache2/htdocs.

5. Start the service:

$ docker compose up -d
Enter fullscreen mode Exit fullscreen mode

This builds and runs the container while automatically creating the declared volume and network.

Output:

[+] Running 3/3
✔ Network docker-compose_default       Created                    0.2s 
✔ Volume "docker-compose_web_content"  Created                    0.0s 
✔ Container docker-compose-web-1       Started                    0.6s
Enter fullscreen mode Exit fullscreen mode

6. Inspect the volume created by Docker Compose:

$ docker volume inspect docker-compose_web_content
Enter fullscreen mode Exit fullscreen mode

Replace docker-compose_web_content with the name of your Docker Compose volume. This confirms that the named volume declared in the Compose file was created and is mounted as expected.

Output:

[
    {
        "Name": "docker-compose_web_content",
        "Mountpoint": "/var/lib/docker/volumes/docker-compose_web_content/_data",
        ...
    }
]
Enter fullscreen mode Exit fullscreen mode

7. Shut down the service and remove the volume:

$ docker compose down -v
Enter fullscreen mode Exit fullscreen mode

down stops and removes containers, networks, and volumes, and -v ensures that named volumes declared in the Compose file are also deleted.

Output:

[+] Running 3/3
✔ Container docker-compose-web-1     Removed                      1.3s 
✔ Network docker-compose_default     Removed                      0.2s 
✔ Volume docker-compose_web_content  Removed                      0.0s
Enter fullscreen mode Exit fullscreen mode

Next Steps

  • Move your own stateful services (databases, CMS uploads, app data) from bind mounts to named volumes for safer, more portable persistence.
  • Script the backup/restore workflow (tar inside the container + docker cp) into a reusable shell script you can run on a schedule.
  • Add volume definitions to an existing Docker Compose project instead of managing volumes manually with the CLI.
  • Review docker volume prune to clean up unused volumes once you're comfortable with which ones are safe to remove.

For the full guide with additional tips, visit the original article on Vultr Docs.

Top comments (0)