1.3 · Volumes: persisting data beyond containers

Level 1 · Containers: images, volumes, networks

1.3Volumes: persisting data beyond containers

Goal: making data survive container deletion with volumes.
Estimated time: 13 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • The container is ephemeral: everything it writes inside itself dies with it (rm = all lost) — for a database, that is unacceptable: store outside the container.
  • Named for data, bind for code: -v pgdata:/var/lib/postgresql/data (Docker-managed volume, portable) for data; -v ./site:/usr/share/nginx/html (machine folder) for code in dev.
  • The test that saves: delete the container, relaunch on the same volume — the data must be there; docker volume ls inventories, rm deletes (final).

Running mini-case — Idir (almost) loses a database

Idir launched the demo database with no volume « to go fast ». In the evening, he deletes the container to start clean — and realizes the test data entered in the afternoon vanished with it. The next day, he relaunches with -v pgdata:/var/lib/postgresql/data, recreates the data, deletes the container, relaunches on the same volume: everything is there. He turned a scare into a reflex: data = named volume, verified by an rm + relaunch test before every serious start.

Continuation of cases 1.1-1.2 — Idir moves from throwaway containers to surviving data.

1. The tragedy of the ephemeral container

By default, everything a container writes inside itself dies with it (rm = all lost). For a database, that is unacceptable. The solution: store outside the container, in a Docker-managed volume or a mounted folder of the machine.

Beware the false friend: stop erases nothing, rm erases everything not mounted. Believing the reverse is the most classic level-1 data loss.

2. Named volume vs bind mount

The named volume (-v pgdata:/var/lib/postgresql/data) is stored by Docker, portable and backup-friendly: the choice for data. The bind mount (-v ./site:/usr/share/nginx/html) links a folder of your machine: the choice for code in development (edit a file, the container sees it at once).

The trap is the wrong internal path: mounting next to the directory where the application really writes means persisting emptiness. Check the path in the image documentation.

3. The reflex that saves: testing deletion

The test of truth: delete the container, relaunch one on the same volume — the data must be there. docker volume ls inventories, docker volume rm deletes (careful, final). Orphan volumes are purged with prune, with caution.

Idir made it a ritual: no data service goes on demo without passing the rm + relaunch test.

Common misinterpretation: « stop erases my data, and a randomly mounted folder is enough to save it ». Wrong both ways: stop keeps everything (only rm destroys), and mounting at the wrong internal path persists emptiness while the application writes elsewhere. Named volume at the right path, then rm + relaunch test to prove it.
Persistent data The container dies, the volume survives Ephemeral container Allinside dies on rmNamed volume Managed byDocker, portableIdentical relaunch Same dataon the same volume
The container dies, the volume survives
Text version of the diagram (SEO / screen readers / translation): 1) Observe: Idir deletes his container with no volume and loses his data — the ephemeral punishes. 2) Mount: he relaunches with -v pgdata:/var/lib/postgresql/data, at the documented path of the image. 3) Prove: rm of the container then relaunch on pgdata — the data is still there. Lesson: without -v, the same sequence erases everything; the rm + relaunch test is the only proof that counts.

🔎 Concrete example — 🔎 Concrete example — Postgres surviving rm

Idir's database, before and after: with a volume, nothing is lost.

docker run -d --name bdd -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data postgres:16.4
# ... create some data ...
docker rm -f bdd
docker run -d --name bdd2 -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data postgres:16.4
# the data is still there

Reading: the pgdata volume survived the container deletion.

Lesson: without -v, the same sequence would have erased everything.

Section vocabulary

Named volume
Storage space managed by Docker, persistent outside containers, portable and backup-friendly.

Simple example: pgdata keeps Idir's database between bdd and bdd2.

What it is not: a file written in the container with no mount.

Reflex: data = named volume.

Bind mount
A machine folder mounted as-is in the container; ideal for code in development.

Simple example: -v ./site:/usr/share/nginx/html: Idir edits, the container sees it at once.

What it is not: portable storage for a production database.

Reflex: dev code = bind, prod data = named volume.

Mount point
The internal path where the volume appears in the container; it must be where the application writes.

Simple example: /var/lib/postgresql/data for postgres:16.4.

What it is not: some random folder picked by chance.

Reflex: check the path in the image docs.

prune
Cleaning unused resources, orphan volumes included — final deletion.

Simple example: Idir purges volumes from his throwaway tries, never pgdata.

What it is not: a trash bin you can restore from.

Reflex: check the list before any prune.

In practice — In practice — Proving persistence

  1. Launch postgres WITH a named volume and create a table.
  2. Delete the container (rm -f) without touching the volume.
  3. Relaunch a container on the same volume and check the table.
  4. Redo the try WITHOUT a volume: observe the loss.
You will never lose a database again: the volume is a reflex.

Script ready to say — securing a database (30 s)

« My data goes in a named volume: -v pgdata:/var/lib/postgresql/data, at the documented path of the image. I prove it: I delete the container, I relaunch on the same volume, the data is there. Without a volume, the same sequence erases everything. »

Say while running the rm + relaunch live; show the table still present.

Copy-paste template — persistent database

docker run -d --name bdd \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16.4
# Proof: docker rm -f bdd, relaunch the same with --name bdd2, verify.
# Never: docker volume rm pgdata (final) nor prune without checking.

Idir's database on demo

As above: pgdata named like the service, rm + relaunch test passed before showing anything to the manager.

Website in dev

-v ./site:/usr/share/nginx/html: Idir edits his pages on his machine, the Nginx container serves them at once — bind mount, not named volume.

Recovery after a scare

Database launched with no volume by mistake: create the volume, relaunch with -v, re-enter — and engrave the « data = named volume » reflex.

Cleaning up tries

docker volume ls to inventory, targeted rm for test volumes, prune only after checking — never on pgdata.

Caution: A deleted volume (docker volume rm, or prune too fast) is lost forever: no trash bin. Before any cleanup, list (docker volume ls), identify the volume of each running service, and purge only verified orphans — never blindly on a shared machine.

✓ Best practices

  • Data = named volume, dev code = bind mount.
  • Test rm + relaunch before believing.
  • Name volumes like services (pgdata).

✗ Common pitfalls

  • Believing stop erases (no) and rm keeps (no).
  • Mounting at the wrong internal path (data next door).
  • Purging volumes (prune) without checking.

Key takeaways

  • Without a volume, rm = total loss.
  • Named volume for data, bind for code.
  • The rm + relaunch test proves persistence.
  • prune with caution: final deletion.

48h challenge — apply tomorrow

Launch postgres with a named volume, create a table, do rm -f + relaunch and check. Then redo without a volume: observe the loss — and never forget it.

Section exit checklist
  • I mount a named volume for any data that matters.
  • I tell named volume (data) from bind mount (dev code).
  • I prove persistence via rm + relaunch before serious use.
Self-assessment 1-5: does each data container have its named volume at the right path?did I pass the rm + relaunch test?

Frequently asked questions

Where are volumes on my disk?

In Docker's space (docker volume inspect pgdata gives the path). We do not handle them by hand: we go through containers or backups.

Bind mount or volume for a prod database?

Named volume: portable, backup-friendly, independent of the machine's tree. Bind is reserved for dev and config files.

Check your understanding

A postgres container with no volume is deleted (rm). What happens to its data?

Additional resources (optional, to go further)

Level 1 examFresh, harder questions to test what you've learned