By default, all files created inside a container are stored on a writable container layer. When that container is deleted, the data is destroyed. Docker Volumes solve this by storing data outside the container filesystem.
TL;DR (Quick Summary)#
- Named Volumes: Managed by Docker in
/var/lib/docker/volumes/. Best for production database persistence. - Bind Mounts: Mounts a specific host directory (e.g.,
./src) directly into the container. Best for live development hot-reloading. - tmpfs Mounts: Stores data strictly in host RAM memory. Never writes to disk (great for sensitive secrets or temporary caches).
1. Storage Options Comparison#
| Storage Mechanism | Managed By | Host Location | Typical Use Case |
|---|---|---|---|
| Named Volume | Docker Engine | /var/lib/docker/volumes/<name>/_data | Databases (PostgreSQL, Redis), production assets. |
| Bind Mount | Developer | Any arbitrary host directory (/home/user/app) | Source code hot-reloading during development. |
| tmpfs Mount | Linux Kernel | Host System Memory (RAM) | Session keys, temporary cache, high-speed ephemeral data. |
2. Step-by-Step Lab: Preserving Database State#
Let’s test data persistence across container removals using a Named Volume.
Step 1: Creating a Named Volume#
Create a volume named postgres-data:
docker volume create postgres-dataInspect volume metadata:
docker volume inspect postgres-dataStep 2: Launching Database with Volume Mount#
Launch a PostgreSQL container mounted to postgres-data:
docker run -d \
--name db-instance \
-e POSTGRES_PASSWORD=secret \
-v postgres-data:/var/lib/postgresql/data \
postgres:15-alpineStep 3: Writing Sample Data#
Create a sample table inside PostgreSQL:
docker exec -it db-instance psql -U postgres -c "CREATE TABLE users (id INT, name TEXT);"
docker exec -it db-instance psql -U postgres -c "INSERT INTO users VALUES (1, 'Rachmat');"Step 4: Destroying the Container#
Forcefully remove the database container:
docker rm -f db-instanceStep 5: Restoring Data in a New Container#
Launch a brand new container using the exact same volume:
docker run -d \
--name db-restored \
-e POSTGRES_PASSWORD=secret \
-v postgres-data:/var/lib/postgresql/data \
postgres:15-alpineVerify that the table and records survived:
docker exec -it db-restored psql -U postgres -c "SELECT * FROM users;"Expected Terminal Output:
id | name
----+---------
1 | Rachmat
(1 row)3. Troubleshooting & Common Errors#
Error 1: Permission denied on Bind Mounts#
The Cause: File permissions mismatch between host user UID (e.g., 1000) and container user UID (e.g., 999).
The Fix: Align UIDs when running the container: docker run -u $(id -u):$(id -g) ....
Summary & Next Steps#
In this episode:
- We analyzed Named Volumes, Bind Mounts, and tmpfs mounts.
- We built a persistent database volume and verified data survival across container destruction.
Next, we move to Episode 5: Docker Compose for Local Microservices!

