Each Docker mount point flag serves specific scenarios that can enhance the functionality, security, and efficiency of containerized applications. By understanding and applying these flags appropriately, developers and system administrators can optimize their Docker environments to suit various operational needs, from simple web hosting to complex, distributed applications in a microservices architecture.
1. Read-Only (:ro)
Scenario: Hosting Static Websites Suppose you are deploying a static website using an Nginx Docker container. The website’s files (HTML, CSS, JavaScript) do not need to be modified by the container once deployed.
Example:
docker run -d -p 80:80 -v /host/webdata:/usr/share/nginx/html:ro nginxExplanation:
-
The host directory
/host/webdatacontains the static website files. -
This directory is mounted into the Nginx container at
/usr/share/nginx/html. -
The
:roflag ensures that the Nginx server cannot alter the files, preventing any accidental or malicious modifications.
2. Read-Write (:rw)
Scenario: Application Logging Imagine you have an application that needs to write logs persistently so that logs are retained even after the container restarts or is removed.
Example:
docker run -d -v /host/applogs:/app/logs:rw myappExplanation:
-
The host directory
/host/applogsis used to store log files generated by the application running in the Docker container. -
The
:rwflag allows the application to write new log entries to files within the/app/logsdirectory.
3. Shared (:shared)
Scenario: Development Environment In a development environment, multiple containers might need to access and modify a common set of files, such as source code or resources.
Example:
docker run -d -v /host/project:/workspace:shared coder1docker run -d -v /host/project:/workspace:shared coder2Explanation:
-
Both containers
coder1andcoder2mount the same host directory/host/project. -
The
:sharedflag allows changes made by one container to be immediately visible to the other, facilitating a collaborative development environment.
4. RShared (:rshared)
Scenario: Kubernetes Volume Propagation In a Kubernetes cluster, you might need to ensure that any mounts created by a container in a pod are visible to other pods, possibly on different nodes.
Example:
docker run -d -v /host/data:/data:rshared global-data-providerExplanation:
-
The container
global-data-providermounts/host/data. -
The
:rsharedflag ensures that if this container creates new mounts within/data, these mounts are propagated to all other containers that use any mount under/host/data. -
This is particularly useful in environments where volume sharing across multiple nodes is required.
5. :z and :Z
These flags are used to automatically adjust the SELinux labels of the host files to allow containers to read and write them.
-
:z: This label indicates that the volume content is shared among multiple containers. -
:Z: This label indicates that the volume content is private and specific to that container.
Example:
docker run -v /host/path:/container/path:z nginx6. --mount Option
While not a flag, the --mount syntax provides more explicit and verbose options compared to the -v or --volume syntax. It supports different types of mounts (like volume, bind, or tmpfs), and allows for additional settings such as readonly.
Example:
docker run --mount type=bind,source=/host/path,target=/container/path,readonly nginx7. --tmpfs
This option mounts a temporary file storage in the container’s filesystem. It can be used to store temporary application data without persisting it to disk.
Example:
docker run --tmpfs /tmp nginx8. --volumes-from
This flag allows one container to use the volume of another container. It’s useful for sharing data between containers, especially in complex applications where multiple services need access to the same data.
Example:
docker run --volumes-from other-container nginx9. :nocopy
This modifier can be used with the --mount option for volumes. It tells Docker not to copy data from a container path to a new volume, which can be useful when the default behavior of copying data is not desired.
Example:
docker run --mount type=volume,source=myvolume,target=/app,data:nocopy myappThe Ownership Gotcha That’ll Ruin Your Night
Here’s the thing nobody tells you until you’re staring at a Permission denied error at 11 PM: Docker doesn’t care about your host filesystem permissions when it creates a named volume. When you spin up a container with a named volume for the first time, Docker initializes that volume directory as root:root by default — even if your app inside the container runs as a non-root user.
This bites you hardest with database containers or any image that explicitly switches to an unprivileged user (Postgres runs as postgres, Redis as redis, and so on). You mount a volume, the container starts, and the app immediately crashes because it can’t write to its own data directory.
The fix depends on the situation. For named volumes, the cleanest approach is to let the container’s entrypoint handle ownership — most official images already do this. But for bind mounts, you’re responsible:
# Check what UID the container process runs asdocker run --rm postgres id
# Pre-create the host dir with the right ownersudo mkdir -p /data/postgressudo chown 999:999 /data/postgres # 999 is the postgres UID in the official image
# Now mount itdocker run -d \ -v /data/postgres:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgresIf you don’t know the UID ahead of time, you can also override it at container start with --user, but check the image docs first — some entrypoints break if you do that.
For Compose setups, a volumes: block with a driver_opts entry or an init container that runs chown is the production-grade solution. Ugly? A little. But it beats debugging permission errors during a deploy.
services: db: image: postgres:16 volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: secret
volumes: pgdata:With named volumes like the example above, Postgres’s entrypoint handles ownership automatically — no manual chown needed. That’s one strong reason to prefer named volumes over bind mounts for stateful services unless you have a specific reason to inspect the files directly on the host.