Docker Curriculum
On this page
- What Are Volumes
- The Core Problem Volumes Solve
- How Volumes Work Internally
- Volumes vs. the Writable Layer
- Types of Volumes
- Named Volumes
- Anonymous Volumes
- Declaring Volumes in a Dockerfile
- When to Use Volumes
- Always use volumes for:
- Do not use volumes for:
- Volumes in AWS ECS
- ECS on EC2 — Standard Volumes
- ECS + EFS (Elastic File System)
- Summary
What Are Volumes
You have already seen that a container's writable layer is ephemeral. Remove the container, and all data written inside it disappears. For stateless applications — APIs, web servers, workers — this is perfectly fine. But for stateful data — database records, user uploads, session state — you need storage that survives beyond the container's lifecycle.
Docker volumes are the answer. They are the recommended mechanism for persisting data generated by and used by Docker containers. A volume is a dedicated piece of storage that exists outside the container's writable layer and is managed entirely by Docker.
This file explains what volumes are, how they work at the filesystem level, and why they are the correct choice for production persistent storage.
The Core Problem Volumes Solve
Consider a PostgreSQL database container without a volume:
PostgreSQL stores all its data in /var/lib/postgresql/data inside the container. This path is part of the container's writable layer. Every row you insert, every table you create, every index you build — it all lives in that writable layer.
Now you need to update PostgreSQL from version 16 to 17:
When you removed the old container, Docker deleted its writable layer. All your data is gone. Every row, every table, every index — permanently deleted.
With a volume:
PostgreSQL writes data into the volume at /var/lib/postgresql/data. The volume lives outside the container. When you remove the container and recreate it with the new image:
The new container mounts the same volume. All the data is there. The upgrade is complete.
How Volumes Work Internally
A Docker volume is a directory on the Docker host's filesystem, managed by Docker in a dedicated location:
When you mount a volume into a container, Docker bind-mounts the _data directory into the container's filesystem at the path you specify. The container writes to /var/lib/postgresql/data — Docker transparently routes those writes to /var/lib/docker/volumes/pgdata/_data on the host.
The critical difference from a regular bind mount: Docker fully manages this path. You never need to know or care about the /var/lib/docker/volumes/ path. Docker handles creation, permissions, ownership, and cleanup.
Volumes vs. the Writable Layer
Understanding why volumes are architecturally separate from the writable layer is essential.
The performance difference is real. A database writing to a volume avoids the OverlayFS copy-on-write overhead of the writable layer. On write-intensive workloads like databases, this can make a significant difference. PostgreSQL on a volume is measurably faster than PostgreSQL writing to the writable layer.
Types of Volumes
Docker has three main types of volumes based on how they are named and created.
Named Volumes
The recommended approach. You give the volume a specific name. Docker creates and manages the storage location.
The volume named pgdata persists until you explicitly delete it with docker volume rm pgdata. It can be mounted into any container at any time.
Anonymous Volumes
Created when you mount a path without giving it a name. Docker generates a random UUID as the name.
Docker creates a volume with an auto-generated name like 3f4a5b6c7d8e9f0a.... Anonymous volumes survive docker rm but are easy to lose track of. They are cleaned up when you run docker volume prune. Use named volumes instead — they are always explicitly named and intentional.
Declaring Volumes in a Dockerfile
The VOLUME instruction in a Dockerfile declares that a path inside the container should be backed by a volume:
When a container is created from this image without an explicit -v flag, Docker automatically creates an anonymous volume mounted at /var/lib/postgresql/data. This ensures the container's data directory is never accidentally stored in the writable layer.
The official postgres:16 image uses this pattern. It is why running docker run postgres:16 without -v still creates a volume — the Dockerfile mandates it.
When to Use Volumes
Always use volumes for:
Databases — PostgreSQL, MySQL, MongoDB, Redis. Any data that must survive container restarts, deployments, and upgrades.
User-generated content — File uploads, profile pictures, documents. Data created by users that must persist.
Application state — Application-level caches, job queues, session stores (when using a file-based backend).
Do not use volumes for:
Application code — Use the image (COPY in Dockerfile). Volumes are for data, not code.
Configuration files — Use bind mounts or environment variables for config.
Temporary scratch space — Use tmpfs mounts for fast, non-persistent temporary data.
Volumes in AWS ECS
On AWS ECS, volumes behave differently depending on the deployment type.
ECS on EC2 — Standard Volumes
Volume data is stored on the EC2 instance's local storage. When the ECS task moves to a different instance (during autoscaling or instance replacement), it loses its local volume data.
For this reason, local ECS volumes are only appropriate for truly ephemeral data — build caches, temp files. Use EFS for persistent ECS data.
ECS + EFS (Elastic File System)
For persistent, shared storage in ECS, you use AWS EFS. EFS is a managed NFS filesystem that mounts into ECS tasks just like a Docker volume, but the data is stored redundantly in AWS and accessible from any instance.
The ECS task mounts the EFS filesystem into the container exactly where PostgreSQL expects its data. Whether the task runs on EC2 instance A or instance B, it mounts the same EFS data. This is the production-grade persistent storage pattern on AWS ECS.
Summary
- Docker volumes are storage managed by Docker that exists outside the container's ephemeral writable layer — volume data persists when containers are stopped, removed, or replaced
- Internally, a volume is a directory under
/var/lib/docker/volumes/that Docker mounts into the container at the specified path - Volumes bypass the OverlayFS copy-on-write overhead of the writable layer — writes go directly to the host filesystem, making databases significantly faster
- Named volumes are the recommended approach — you specify the name, Docker manages the location
- Always use volumes for stateful data: databases, user uploads, application state
- The
VOLUMEinstruction in a Dockerfile causes Docker to automatically create an anonymous volume at container start if no explicit-vis provided - On AWS ECS, use EFS volumes instead of local volumes for data that must survive instance replacements
In the next file, we cover how to create and use volumes in detail — the complete CLI and Docker Compose workflow.