Docker provides tools to bridge the filesystems of containers and the host operating system running the container, such as bind mounts and volumes. These can be very useful both in development and production environments.
Why Mount From The Host?
Generally, with Docker, you’d want images to run independently of the host system. If you wanted to, for example, update an app’s code or configuration files, you’d likely want to build a new version of the container and re-deploy. This allows you to quickly scale and move images without worrying about the hardware they run on.
However, in a dev environment, being able to directly mount a directory to enable hot-reloading of config or code can be very useful. For example, you may be working on a JS file or PHP plugin that you can just drag-and-drop into the container. Or you may want to mount an entire NGINX config directory to work on your website. Whatever your use case, mounting files isn’t a bad solution.
It’s also useful in production, if you have host services that depend on files in containers. For example, you may have a log ingestion and aggregation service that would prefer if the container’s log files were in a directory accessible from the host. While there are likely some pure in-Docker solutions to your problems, sometimes it’s simpler to just mount a volume.
Note: since mounts are handled through the Docker API, they will work regardless of the host OS. However, macOS has extra protections, and mounts outside of a few host directories may fail with “mounts denied” at runtime. This includes
/Users, which covers most operations, but if you need to you can fix this in the Docker settings under Preferences > Resources > File Sharing by adding the target directory to the list.
Mounting a Host Directory
Creating a bind mount is pretty simple. Add it with the
--mount type=bind flag at startup, specifying a source and target directory to mount to.
docker run -d \ -it \ --name container \ --mount type=bind,source=/nginxconfig,target=/etc/nginx \ nginx:latest
Bind mounts are the simplest, but Docker does provide the Volume API for managing these kinds of mounts a little better. The data stored will be managed by Docker, and the volume directory will be created automatically in Docker’s directory. This may not be what you want if you have an existing directory in mind, but this method is better since it doesn’t depend on the file structure of the host OS.
docker volume create nginx-config docker run -d \ --name devtest \ --mount source=nginx-config,target=/etc/nginx \ nginx:latest
You can also use Docker Compose to define volumes:
version: "3.0" services: web: image: nginx:latest ports: - "80:80" volumes: - nginx-config:/etc/nginx/ volumes: nginx-config:
These are stored in a standard format accessible to Linux:
However, on macOS, you will need to connect to the Docker virtual machine to be able to view volumes.
Mounting Single Files
Mounting entire directories works well when you want to edit a lot of config/code files that are stored on the host. However, sometimes you might just want to mount a single file to edit, without touching the other files.
To do this, you can run the container with a bind mount, which support individual files if you specify the path:
docker run -it \ --mount type=bind,source=/path/file.cfg,target=/etc/example/file.cfg \ nginx sh
If you have a lot of files to mount this way, you can put them all in the same host directory, and mount that directory to a different location in the container. You can then use symlinks inside the container to link files in the mounted directory to the proper location.