By default, all files created inside a Docker container are stored in the container’s writable layer. This has two major problems:
Docker solves this with three types of storage mounts that persist or share data outside the container lifecycle:
Host Machine
├── /var/lib/docker/volumes/ ← Named Volumes (managed by Docker)
├── /any/host/path/ ← Bind Mounts (managed by you)
└── RAM (tmpfs) ← tmpfs Mounts (in-memory, temporary)
| Type | Managed By | Persists After Container Stops? | Use Case |
|---|---|---|---|
| Volume | Docker | Yes | Databases, app data, sharing between containers |
| Bind Mount | You (host path) | Yes (it’s a host folder) | Dev workflow, config files, source code |
| tmpfs | OS (RAM) | No (lost on stop) | Secrets, sensitive temp data, performance |
Rule: Use volumes for production data. Use bind mounts for development. Use tmpfs for sensitive/temporary data you never want on disk.
docker volume
Output:
Usage: docker volume COMMAND
Manage volumes
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove unused local volumes
rm Remove one or more volumes
Run 'docker volume COMMAND --help' for more information on a command.
Explanation:
Running docker volume with no sub-command prints the help menu listing all available volume management commands. This is useful for quickly checking what operations are available.
docker volume create testcolume01
Output:
testcolume01
Explanation:
This creates a named volume called testcolume01. Docker stores it at /var/lib/docker/volumes/testcolume01/_data on the host. The volume name is echoed back on success.
Note: The volume name testcolume01 has a typo (should be testvolume01) but Docker accepts any valid string as a volume name — this is not an error.
docker volume ls
Output:
DRIVER VOLUME NAME
local testcolume01
Explanation:
Lists all volumes currently managed by Docker. The local driver means the volume is stored on the local host filesystem (the default). At this point only testcolume01 exists.
docker run -it --rm -v testvolume01:/home/app ubuntu
Inside the container:
root@2db51a71a801:/# cd /home/app
root@2db51a71a801:/home/app# echo "my sap id: 500124385" > sapid.txt
root@2db51a71a801:/home/app# cat sapid.txt
my sap id: 500124385
root@2db51a71a801:/home/app# exit
Explanation of flags:
| Flag | Meaning |
|---|---|
-it |
Interactive terminal — attach to container’s shell |
--rm |
Automatically remove the container when it exits |
-v testvolume01:/home/app |
Mount named volume testvolume01 at /home/app inside the container |
ubuntu |
Use the Ubuntu image |
What happened step by step:
testvolume01 was mounted at /home/appsapid.txt was created with content my sap id: 500124385--rm)Key insight: --rm deletes the container, NOT the volume. Volume data outlives the container.
docker run -it --rm -v testvolume01:/home/app2 ubuntu
Inside the container:
root@1f7adc478e4e:/# cd home/app2/
root@1f7adc478e4e:/home/app2# ls
sapid.txt
root@1f7adc478e4e:/home/app2# cat sapid.txt
my sap id: 500124385
root@1f7adc478e4e:/home/app2# echo testsdata > dummy.txt
root@1f7adc478e4e:/home/app2# ls
dummy.txt sapid.txt
root@1f7adc478e4e:/home/app2# exit
Explanation:
This is a completely new, different container (note the different hostname 1f7adc478e4e vs 2db51a71a801), but the same volume testvolume01 is mounted — this time at /home/app2 instead of /home/app. The mount point name on the container side can be anything.
Results:
sapid.txt from the previous container is still there — proving data persistencedummy.txt was added — it will persist for the next container toodocker run -it --rm -v testvolume01:/home/app:ro ubuntu
Inside the container:
root@4eb7a6c53ff4:/# cd home/app/
root@4eb7a6c53ff4:/home/app# ls
dummy.txt sapid.txt
root@4eb7a6c53ff4:/home/app# cat dummy.txt
testsdata
root@4eb7a6c53ff4:/home/app# exit
Explanation:
The :ro suffix added to the -v flag makes the volume read-only inside this container. Both files from the previous steps (dummy.txt and sapid.txt) are visible and readable, but the container cannot write or modify anything in /home/app.
Syntax breakdown:
-v testvolume01 : /home/app : ro
volume name mount path read-only
Use case: Mount a shared config or secrets volume as read-only for app containers so they can read but never accidentally overwrite shared data.
docker run -it --rm --mount type=volume,source=testvolume01,target=/home/app:ro ubuntu
Inside the container:
root@0afaebca1855:/# cd home/app:ro/
root@0afaebca1855:/home/app:ro# cd /home/app
bash: cd: /home/app: No such file or directory
root@0afaebca1855:/home/app:ro# ls
dummy.txt sapid.txt
root@0afaebca1855:/home/app:ro# exit
Explanation:
The --mount flag is a more explicit, verbose alternative to -v. However, the :ro suffix was incorrectly placed inside the target= value, causing Docker to mount the volume at the literal path /home/app:ro instead of /home/app with read-only mode.
Wrong:
--mount type=volume,source=testvolume01,target=/home/app:ro
Correct syntax for read-only with –mount:
--mount type=volume,source=testvolume01,target=/home/app,readonly
| Syntax Style | Read-Only Flag |
|---|---|
-v flag |
-v volume:/path:ro |
--mount flag |
--mount ...,readonly |
docker run -it --rm -v ./testdir2:/home/app:ro ubuntu
Inside the container:
root@dea7729260c1:/# cd /home/app/
root@dea7729260c1:/home/app# echo test > test
bash: test: Read-only file system
root@dea7729260c1:/home/app# exit
Explanation:
This is a bind mount — it maps a directory from the host (./testdir2) directly into the container at /home/app. The :ro flag makes it read-only, so any write attempt fails with Read-only file system.
Volume vs Bind Mount:
Named Volume: -v testvolume01:/home/app ← Docker manages storage location
Bind Mount: -v ./testdir2:/home/app ← You control the host path
Note: ./testdir2 is a relative path. Docker resolves it relative to the current working directory on the host.
docker run -it --rm --mount type=tmpfs,target=/home/app ubuntu
Inside the container:
root@51772b4cd608:/# exit
Explanation:
A tmpfs mount stores data in the host’s RAM, not on disk. The data is available only while the container is running — once the container stops, all tmpfs data is gone permanently, with no trace on disk.
When to use tmpfs:
tmpfs is not for persistence — it is the opposite of a volume. Use it specifically when you want data to disappear.
docker run -it --rm --mount type=bind,source=./testdir22,target=/home/app ubuntu
Error Output:
docker: Error response from daemon: invalid mount config for type "bind":
bind source path does not exist: /mnt/d/ccvt/sem 6/devops/testdir22
Cause: Unlike named volumes (which Docker creates automatically), bind mounts require the host directory to already exist. testdir22 had not been created.
Fix: Create the directory first, then run:
mkdir testdir22
docker run -it --rm --mount type=bind,source=$(pwd)/testdir22,target=/home/app ubuntu
$(pwd) Expansion Breaks –mount Parsing (Path with Spaces)docker run -it --rm --mount type=bind,source=$(pwd)/testdir22,target=/home/app ubuntu
Error Output:
invalid argument "type=bind,source=/mnt/d/ccvt/sem" for "--mount" flag: target is required
Cause: The working directory path contains a space (sem 6/devops). When $(pwd) expands, the shell splits on the space — --mount receives type=bind,source=/mnt/d/ccvt/sem as one argument and 6/devops/testdir22,target=/home/app as another, breaking the parsing.
Fix: Quote the entire --mount value:
docker run -it --rm --mount "type=bind,source=$(pwd)/testdir22,target=/home/app" ubuntu
| Observation | What It Proves |
|---|---|
sapid.txt survived after container with --rm exited |
Volumes persist independently of container lifecycle |
Second container found sapid.txt without any special steps |
Same volume can be shared across multiple containers |
:ro prevented echo test > test from writing |
Read-only mounts are enforced at the OS level |
Bind mount failed because testdir22 didn’t exist |
Docker doesn’t auto-create bind mount source directories |
$(pwd) broke with spaces in path |
Paths with spaces must be quoted in shell commands |
tempfs caused “mount type unknown” |
Docker type names are case-sensitive and exact |
--mount target=/home/app:ro created a literal :ro path |
:ro is -v syntax only; --mount uses readonly keyword |
| Feature | Named Volume | Bind Mount | tmpfs |
|---|---|---|---|
| Storage location | Docker-managed (/var/lib/docker/volumes/) |
Any host path you specify | Host RAM only |
| Created automatically | Yes | No (must exist first) | Yes (in memory) |
| Persists after container stops | Yes | Yes | No |
| Shareable between containers | Yes | Yes | No |
| Works on all platforms | Yes | Path issues on Windows/WSL | Yes (Linux only) |
| Best for | Production data, databases | Dev source code, configs | Secrets, sensitive temp data |
| Mount syntax | -v volname:/path |
-v ./hostpath:/path |
--mount type=tmpfs,target=/path |
| Syntax | Description |
|---|---|
-v myvolume:/container/path |
Mount named volume (read-write) |
-v myvolume:/container/path:ro |
Mount named volume (read-only) |
-v ./hostdir:/container/path |
Bind mount host directory |
-v ./hostdir:/container/path:ro |
Bind mount read-only |
--mount type=volume,source=myvol,target=/path |
Named volume (–mount style) |
--mount type=volume,source=myvol,target=/path,readonly |
Named volume read-only |
--mount type=bind,source=/host/path,target=/path |
Bind mount (–mount style) |
--mount type=tmpfs,target=/path |
tmpfs in-memory mount |
| Scenario | Recommended Syntax |
|---|---|
| Quick single mount | -v (shorter) |
| Production / scripts | --mount (explicit, less error-prone) |
| Read-only volume | -v vol:/path:ro OR --mount ...,readonly |
| Path with spaces | --mount "type=bind,source=$(pwd)/my dir,target=/app" |
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker volume
Usage: docker volume COMMAND
Manage volumes
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove unused local volumes
rm Remove one or more volumes
Run 'docker volume COMMAND --help' for more information on a command.
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker voulme create testcolume01
docker: unknown command: docker voulme
Run 'docker --help' for more information
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker volume create testcolume01
testcolume01
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker volume ls
DRIVER VOLUME NAME
local testcolume01
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm -v testvolume01:/home/app ubuntu
root@2db51a71a801:/# cd /home/app
root@2db51a71a801:/home/app# echo "my sap id: 500124385" > sapid.txt
root@2db51a71a801:/home/app# cat sapid.txt
my sap id: 500124385
root@2db51a71a801:/home/app# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b973c8400a01 nginx "/docker-entrypoint.…" 3 days ago Exited (0) 3 days ago cranky_wilbur
072d0a0360ed sapid-checker:500124385 "python app.py" 5 days ago Exited (0) 5 days ago amazing_shamir
c907b5626bda sapid-checker:500124385 "python app.py" 5 days ago Exited (1) 5 days ago eloquent_fermi
9dda3b3dd60b sapid-checker:500124385 "python app.py" 5 days ago Exited (0) 5 days ago wonderful_blackwell
c9d26a2f2d20 hello-c-app "/hello" 5 days ago Exited (0) 5 days ago intelligent_rubin
acc3227fbfb0 my-flask-app:v1 "python /app/app.py" 6 days ago Exited (255) 5 days ago 0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp my-flask
3dc6fee2455d b3/java-app:3.0 "bash" 2 weeks ago Exited (0) 2 weeks ago compassionate_bohr
b65389cf84cb myrepo/java-app:1.0 "bash" 2 weeks ago Exited (127) 2 weeks ago reverent_swartz
b5334b76c24b ubuntu:22.04 "bash" 2 weeks ago Exited (0) 2 weeks ago java_lab
0ded4732b3fb c881927c4077 "/docker-entrypoint.…" 3 weeks ago Exited (0) 3 weeks ago festive_hopper
81870169556e ubuntu "/bin/bash" 3 weeks ago Exited (0) 3 weeks ago dockerclass
26101d4f3ed4 ubuntu "/bin/bash" 3 weeks ago Exited (0) 3 weeks ago eager_sutherland
e30f8bb4bdfe ubuntu "/bin/bash" 3 weeks ago Exited (0) 3 weeks ago eloquent_blackwell
9e0dba4e3626 c881927c4077 "/docker-entrypoint.…" 3 weeks ago Exited (0) 3 weeks ago nginx-container
c7595ae5f6b2 c881927c4077 "/docker-entrypoint.…" 3 weeks ago Exited (0) 3 weeks ago sharp_brahmagupta
f7a439271847 c881927c4077 "/docker-entrypoint.…" 3 weeks ago Exited (0) 3 weeks ago kind_yalow
0cadda32442f hello-world "/hello" 3 weeks ago Exited (0) 3 weeks ago dazzling_lehmann
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm -v testvolume01:/home/app2 ubuntu
root@1f7adc478e4e:/# cd home/
root@1f7adc478e4e:/home# cd app2/
root@1f7adc478e4e:/home/app2# ls
sapid.txt
root@1f7adc478e4e:/home/app2# cat sapid.txt
my sap id: 500124385
root@1f7adc478e4e:/home/app2# echo testsdata > dummy.txt
root@1f7adc478e4e:/home/app2# ls
dummy.txt sapid.txt
root@1f7adc478e4e:/home/app2# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm -v testvolume01:/home/app:ro ubuntu
root@4eb7a6c53ff4:/# cd home/app/
root@4eb7a6c53ff4:/home/app# ls
dummy.txt sapid.txt
root@4eb7a6c53ff4:/home/app# cat dummy.txt
testsdata
root@4eb7a6c53ff4:/home/app# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm --mount type=volume,source=testvolume01,target=/home/app:ro ubuntu
root@0afaebca1855:/# cd home/app\:ro/
root@0afaebca1855:/home/app:ro# cd /home/app
bash: cd: /home/app: No such file or directory
root@0afaebca1855:/home/app:ro# ls
dummy.txt sapid.txt
root@0afaebca1855:/home/app:ro# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ ls
container.tar flask-docker-project flask-lab image.tar java-app.tar sapid-test
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ mkdir testdir
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ cd testdir/
aniket@Aniket:/mnt/d/ccvt/sem 6/devops/testdir$ cd ..
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm -v ./testdir2:/home/app:ro ubuntu
root@dea7729260c1:/# cd /home/app/
root@dea7729260c1:/home/app# echo test > test
bash: test: Read-only file system
root@dea7729260c1:/home/app# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm -mount type=bind,source=./testdir22,target=/home/app ubuntu
invalid argument "ount" for "-m, --memory" flag: invalid size: 'ount'
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run 'docker run --help' for more information
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm --mount type=bind,source=./testdir22,target=/home/app ubuntu
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /mnt/d/ccvt/sem 6/devops/testdir22
Run 'docker run --help' for more information
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm --mount type=bind,source=$(pwd)/testdir22,target=/home/app ubuntu
invalid argument "type=bind,source=/mnt/d/ccvt/sem" for "--mount" flag: target is required
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run 'docker run --help' for more information
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm --mount type=tempfs,target=/home/app ubuntu
docker: Error response from daemon: invalid mount config for type "tempfs": mount type unknown
Run 'docker run --help' for more information
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$ docker run -it --rm --mount type=tmpfs,target=/home/app ubuntu
root@51772b4cd608:/# exit
exit
aniket@Aniket:/mnt/d/ccvt/sem 6/devops$