Course outline · 0% complete

0/29 lessons0%

Course overview →

Volumes and bind mounts

lesson 4-1 · ~13 min · 11/29

From lessons 1-2 and 3-2, a file written by a running container lives in the container's thin writable layer on top of the image.

The image layers are read-only, so every write lands in the container's private writable layer.

That raises this lesson's problem directly. docker rm deletes that layer, and every file in it, permanently.

Containers forget everything

Lesson 2-3 told you to treat containers as disposable: stop, remove, recreate. But the writable layer is deleted with the container. Run a Postgres database in a container, insert a year of customer records, docker rm it, and the data is gone.

The fix is a volume: a chunk of storage that Docker manages outside any container and mounts into one at a path you choose.

docker volume create dbdata
docker run -d --name db -v dbdata:/var/lib/postgresql/data postgres:16

Read -v dbdata:/var/lib/postgresql/data like the -p flag from lesson 2-2: left is the volume name, right is the path inside the container. Postgres writes its files to that path, so they actually land in the volume. Now docker rm -f db and start a fresh container with the same -v flag: all data is still there. The container stays disposable, the data does not.

db container running removed docker rm -f db new container same -v flag volume dbdata lives outside every container, untouched by docker rm
A volume outlives the container that used it. Removing the container deletes only its writable layer, so a replacement container mounting the same volume finds the data intact.

Bind mounts, a host folder instead

A bind mount is the same flag with a path on the left instead of a name:

docker run -d -v "$(pwd)":/app myapp:v1

$(pwd) is your current directory, from the terminal course, so the container's /app is your project folder, live. Editing a file on your laptop makes the container see the change instantly, which is what makes bind mounts the standard dev-mode trick with no rebuild per edit.

PropertyNamed volumeBind mount
Left side of -va name, dbdataa host path, $(pwd)
Managed byDockeryou
Typical usedatabase data in productionlive source code during development

The rule of thumb is volumes for data the app owns, and bind mounts for files you are editing.

Managing volumes

Volumes are real objects with their own lifecycle, separate from any container:

docker volume ls                 # every volume on this machine
docker volume inspect dbdata     # details, including where it lives on the host
docker volume rm dbdata          # delete it (fails while a container uses it)

Two habits that prevent real losses:

  1. Name your volumes. If you write -v /var/lib/postgresql/data with no name on the left, Docker creates an anonymous volume with a random hash name. The data survives, but three months later nobody knows which of the twelve hash-named volumes holds production data
  2. Deleting is explicit. docker rm of the container never removes its named volumes. That is the safety you want, but it also means test volumes accumulate until you clean them up (lesson 4-3 covers cleanup)

Surviving a container removal

Running Postgres with -v dbdata:/var/lib/postgresql/data, removing the container with docker rm -f db, and starting a new one with the same flag leaves all the data intact. The new container sees every row.

The volume lives outside the container, so removing the container deletes only the writable layer.

ObjectRemoved by docker rm -f db
the container and its writable layeryes
the dbdata volumeno
the postgres:16 imageno

Any new container that mounts dbdata at the same path picks up exactly where the old one left off. That separation is the whole point of volumes, and it is what makes a database container safe to replace during an upgrade.

Live-editing source inside a container

For a container whose /app folder should be your live project folder, so that laptop edits appear instantly inside, the right tool is a bind mount, for example -v "$(pwd)":/app.

Bind mounts map a real host folder into the container, and the left side of the -v flag is a host path rather than a name. Named volumes are Docker-managed storage, better suited to data the app owns such as a database's files.

GoalChoice
edit code and see it immediatelybind mount
keep database files across container replacementsnamed volume

The distinction is who owns the files. Anything you edit by hand belongs on the host, and anything the app generates belongs in a volume.