Storage
Container filesystems are disposable. Store important state in volumes, bind mounts, external services, or object storage.
Storage choices
Storage |
Use it for |
Watch out for |
|---|---|---|
Image filesystem |
Files baked into the image. |
Changes disappear when the container is removed. |
Named volume |
Database data, caches, local persistent state. |
Ownership must match the runtime user. |
Bind mount |
Source code and host-controlled files. |
Host path layout and OS behavior leak into the container. |
tmpfs |
Temporary sensitive or high-churn files. |
Data disappears when the container stops. |
Named volumes
Use named volumes for container-owned persistent state.
1docker volume create db_data
2docker run -d \
3 --name db \
4 -e MYSQL_ROOT_PASSWORD=change-me \
5 -v db_data:/var/lib/mysql \
6 mysql:latest
Compose example:
1services:
2 db:
3 image: mysql:latest
4 volumes:
5 - db_data:/var/lib/mysql
6
7volumes:
8 db_data:
Bind mounts
Use bind mounts when the host owns the files, such as local source code.
1docker run --rm \
2 --mount type=bind,source="$(pwd)",target=/workspace,readonly \
3 alpine:latest ls /workspace
Prefer --mount over short -v syntax for scripts because it is explicit.
Compose example:
1services:
2 docs:
3 image: python:3-slim
4 working_dir: /workspace
5 volumes:
6 - type: bind
7 source: .
8 target: /workspace
9 read_only: true
tmpfs mounts
Use tmpfs for temporary files that should not be written to disk.
1docker run --rm \
2 --tmpfs /run/secrets:rw,noexec,nosuid,size=1m \
3 alpine:latest sh
Compose example:
1services:
2 api:
3 image: api:local
4 tmpfs:
5 - /tmp
Non-root ownership
Non-root containers need writable mounts owned by the runtime UID or GID. Do not solve ownership failures by running as root.
For files copied into the image, set ownership during the build.
1RUN useradd --uid 10001 --create-home app
2WORKDIR /app
3COPY --chown=10001:10001 . .
4USER 10001:10001
For Kubernetes volumes, use fsGroup when the workload needs group write access.
1securityContext:
2 runAsNonRoot: true
3 runAsUser: 10001
4 runAsGroup: 10001
5 fsGroup: 10001
Back up a volume
Back up a named volume by mounting it into a one-off container.
1docker run --rm \
2 -v db_data:/data:ro \
3 -v "$(pwd)":/backup \
4 alpine:latest \
5 tar czf /backup/db_data.tgz -C /data .
Restore into a new volume.
1docker volume create db_data_restore
2docker run --rm \
3 -v db_data_restore:/data \
4 -v "$(pwd)":/backup \
5 alpine:latest \
6 tar xzf /backup/db_data.tgz -C /data
Practical rules
Treat the image filesystem as read-only application code.
Use named volumes for container-owned state.
Use bind mounts for host-owned source files.
Use read-only mounts by default.
Put temporary writes in
/tmpor an explicit tmpfs mount.Back up named volumes before destructive changes.
Fix UID/GID ownership rather than running the container as root.