The core idea
A tmpfs mount is a directory that lives in memory. It's fast, it's never written to disk, and it disappears when the container stops. You won't use it often, but it solves two problems neatly: scratch space for files that must never be persisted, and making a read-only container work.
Read-only containers
--read-only makes the container's whole filesystem read-only. An attacker who gets in can't drop files, modify
binaries or plant a backdoor that survives. But many programs need to write somewhere, usually /tmp:
$ docker run --rm --read-only alpine touch /tmp/xtouch: /tmp/x: Read-only file system$ docker run --rm --read-only --tmpfs /tmp:size=16m alpine sh -c 'touch /tmp/x && df -h /tmp'Filesystem Size Used Available Use% Mounted ontmpfs 16.0M 0 16.0M 0% /tmp
Everything is read-only except a 16 MB in-memory /tmp. Add a tmpfs for each path the app really needs to write, and
a volume for anything it needs to keep. You'll apply this to the notes API in 07.01 Run as non-root.
Syntax and limits
# Short form, options after the colon
docker run --tmpfs /tmp:size=64m,mode=1777 ...
# Long form
docker run --mount type=tmpfs,dst=/cache,tmpfs-size=8m ...The size is a hard cap:
$ docker run --rm --mount type=tmpfs,dst=/cache,tmpfs-size=8m alpine \sh -c 'dd if=/dev/zero of=/cache/f bs=1M count=20'dd: error writing '/cache/f': No space left on device
Always set one. Without it, a tmpfs can grow to half of the host's (or Docker Desktop VM's) memory:
$ docker run --rm --memory 64m --tmpfs /scratch alpine df -h /scratchtmpfs 3.8G 0 3.8G 0% /scratch
Even inside a container limited to 64 MB, the tmpfs reports 3.8 GB. Files written there count against the container's memory limit, so filling it can get the container OOM-killed (03.06 CPU and memory limits).
| Volume | Bind mount | tmpfs | |
|---|---|---|---|
| Stored on | disk, managed by Docker | disk, your path | memory |
| Survives the container | yes | yes | no |
| Shared between containers | yes | yes | no |
| Typical use | databases, uploads | dev code, config | scratch, secrets, read-only roots |
An app writes decrypted credentials to a temporary file while it starts. You want to be sure they never reach any disk. Where should that path be?
Run the notes API with --read-only. Does it start? (It only writes to Postgres and stdout.) Then run nginx:alpine with --read-only and read the errors: add --tmpfs mounts for the paths it complains about until it serves pages.
STUCK? ▸
An app that fails under --read-only usually prints the path it tried to write. For nginx:alpine, it's mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system); with --tmpfs /var/cache/nginx --tmpfs /run --tmpfs /tmp it serves pages. (Its startup script also notes it can't edit default.conf, which is harmless.)
Recap
Interview questions
How would you run a container with a read-only filesystem when the app needs to write temporary files?