Picture this. You spend an afternoon setting up a container, save a few files inside it, then clean up with docker rm. Next morning you start a fresh container and... your files are gone. Docker did not eat them. You just never told Docker where to keep them.
This is the lab I ran on my own Windows laptop to finally get it. It takes about 10 minutes.
TL;DR
- A container is a running copy of an image plus a thin writable layer. Remove the container and that layer goes with it.
- A volume lives outside the container. Remove the container and the volume stays, ready for the next one.
- Containers run as
rootby default, and a few "cleanup" commands delete more than you think. Gotchas at the end.
Table of contents
- 1. Image vs container in one minute
- 2. Run your first container
- 3. Lab: where does my file go without a volume?
- 4. Lab: the same file, with a volume
- 5. Security gotchas
- 6. Checklist
- Sources
1. Image vs container in one minute
Think of a ready-made meal box. The image is the sealed box: code, runtime and libraries, all read-only. A container is the box opened on your table. You can add salt (write files), but that salt lives only on this plate.
| Thing | What it is | Survives docker rm? |
|---|---|---|
| Dockerfile | The recipe (FROM, COPY, RUN, CMD) |
n/a |
| Image | Read-only layers built from the recipe | Yes |
| Container | Image + a thin writable layer, running | No |
| Volume | Storage managed by Docker, outside the container | Yes |
Each Dockerfile instruction adds a layer, so rebuilding only touches the layers that changed. That is why the second build is so much faster than the first.
2. Run your first container
Docker has a tiny sample app for this:
git clone https://github.com/docker/welcome-to-docker
Open the folder in VS Code: the Dockerfile is the recipe, the rest is a small Node app. Build the image from the terminal:
cd welcome-to-docker
docker build -t welcome-to-docker .
Then run it and map a host port to the container port. I picked 8089 because 80 and 8080 are usually taken by something else on a dev laptop.
-p 8089:80 reads as "host 8089 goes to container 80". Open http://localhost:8089 and Docker throws you a little party:
Enjoy the confetti. Now let's lose some data on purpose.
3. Lab: where does my file go without a volume?
Start a container with no volume and write a file:
docker run -it --name novol ubuntu bash
echo "hello" > /root/note.txt
exit
Remove it and start a new one with the same name:
docker rm novol
docker run -it --name novol ubuntu bash
cat /root/note.txt
# cat: /root/note.txt: No such file or directory
The file lived in the writable layer of the first container. docker rm deleted that layer. The new container got a fresh, empty one. Nothing is "broken": this is exactly how containers are supposed to behave.
4. Lab: the same file, with a volume
Step 1. Create a volume and write a file into it
docker volume create lab1
docker run -it -v lab1:/data ubuntu bash
echo "hello volume" > /data/test.txt
exit
Step 2. Delete the container and mount the volume in a new one
docker ps -a --filter volume=lab1 # find the container that used it
docker rm 58637ec992c2 # your ID will differ
docker run -it -v lab1:/data ubuntu bash
ls /data
# test.txt
Step 3. Same test with a named container
docker run -it --name myubuntu2 -v lab1:/data ubuntu bash # write the file, exit
docker start -ai myubuntu2 # still there: same container
docker rm myubuntu2
docker start -ai myubuntu2
# Error response from daemon: No such container: myubuntu2
Step 4. Check who uses the volume, then mount it in a brand-new container
docker ps -a --filter volume=lab1 # empty: no container uses it now
docker run -it -v lab1:/data ubuntu bash
cat /data/test.txt
# hello volume
The container is gone, the file is not. You can attach the same volume to one container, a new one, or several at once, which is why databases, logs and app state belong in volumes.
Small tip: -v is short and fine for labs. Docker's docs prefer --mount for real setups because it is more explicit:
docker run -it --mount source=lab1,target=/data ubuntu bash
5. Security gotchas
Look at the prompt in the screenshots: root@.... That is not decoration.
-
Containers run as root unless you say otherwise. Add a
USERline in your Dockerfile for anything that does not need root. On shared hosts, look at rootless mode. -
docker rm $(docker ps -aq)removes every stopped container on the machine, not just the ones from your lab. Fine on your laptop, scary on a shared build server. -
docker volume pruneonly removes anonymous volumes by default.docker volume prune -aalso removes unused named volumes, likelab1. Read the prompt before you typey. -
A volume is not a backup. It keeps data alive across containers, but
docker volume rm lab1and it is gone too. Back up what matters. - Anything that mounts the volume can read it. Do not drop secrets in a volume that "some other container" also mounts.
- Docker Desktop is free for personal use and small businesses (under 250 employees and under $10M revenue). Bigger companies need a paid plan, which is why many teams use WSL2 + Docker CLI or Podman instead.
6. Checklist
- [ ] I can explain image vs container vs volume in one sentence each
- [ ] I ran a container with
-p host:containerand opened it in the browser - [ ] I lost a file on purpose without a volume
- [ ] I kept a file with
-v lab1:/dataafterdocker rm - [ ] My Dockerfiles set a non-root
USERwhere possible - [ ] I know what
volume prune -adeletes before I run it
What is the most painful "where did my data go" moment you have had with containers? Tell me below, I promise I will not judge (much).








Top comments (0)