Files shared between a Docker container and the host are not automatic; they must be explicitly defined using volume mounts or bind mounts in the
docker run command or
docker-compose.yml file. By default, containers have an isolated filesystem, meaning any changes made inside the container are lost when it stops unless you persist data to the host machine. To share specific files or directories, you map a path on your Ubuntu host to a path within the container's filesystem, allowing bidirectional access to those resources.
Understanding Volume Types
There are two primary methods for sharing files between the host and a container: bind mounts and named volumes. Bind mounts map a specific directory or file from the host system directly into the container. This is useful when you want the container to read configuration files, source code, or logs located at exact paths on your host. For example, if you have a web application folder on your desktop, you can mount it so the container serves that live content.
Named volumes, on the other hand, are managed by Docker itself. They are stored in a part of the host filesystem that Docker controls, typically at
/var/lib/docker/volumes/. These are preferred for persistent data like databases because they are easier to back up, migrate, and manage independently of the host's directory structure. While bind mounts rely on the host's existing file permissions, named volumes provide a consistent interface regardless of the underlying host OS.
Using Bind Mounts for File Sharing
Bind mounts allow you to sync files between your Ubuntu host and the container in real-time. When you use a bind mount, any change made to the file on the host is immediately visible inside the container, and vice versa. This is particularly useful for development environments where you edit code on your host machine but need the container to execute it.
To create a bind mount, you use the
-v or
--mount flag with the
docker run command. The syntax requires specifying the host path followed by the container path, separated by a colon. Here is an example command that mounts a local directory called
my-app into the container at
/app:
docker run -it -v $(pwd)/my-app:/app ubuntu bash
In this example,
$(pwd) expands to the current working directory on your host. If you modify a file inside
my-app on your host, the container sees the update instantly. However, be aware that bind mounts inherit the permissions of the host files. If the container runs as a non-root user, it might not have write access to certain host files unless permissions are adjusted correctly.
Managing Permissions and Security
One common issue when sharing files is permission errors. Docker containers often run processes as the root user by default, which can lead to conflicts if the host files are owned by a different user. To resolve this, you can ensure that the user ID (UID) and group ID (GID) of the host user match the user inside the container. Alternatively, you can run the container with the same UID as your host user by passing environment variables or using the
--user flag.
Security is another consideration. Bind mounts give the container direct access to the host filesystem, which can be risky if the container is compromised. It is best practice to mount only the necessary directories and set them to read-only if the container does not need to write to them. You can achieve this by adding
:ro to the end of the mount path in the
-v argument.
Fixing Mutagen/Docker Config Issues with DDEV and Mounting Code to /srv Directory provides further insight into how mounting configurations can impact performance and compatibility in complex setups.
Persisting Data with Named Volumes
For applications that generate data you want to keep, such as databases or logs, named volumes are the recommended approach. Unlike bind mounts, named volumes are not tied to a specific host directory structure, making them more portable. You can create a named volume using the
docker volume create command and then attach it to a container.
docker volume create my-data-volume
docker run -it -v my-data-volume:/data ubuntu bash
This setup ensures that even if the container is removed, the data in
my-data-volume persists. You can inspect these volumes using
docker volume ls and manage them with standard Docker commands. This method abstracts away the host filesystem details, providing a cleaner separation between your application data and the host OS.
Docker Compose Configuration
When managing multiple services,
docker-compose.yml simplifies the process of defining shared files. In the compose file, you define volumes under a top-level
volumes key and reference them in individual services. This approach makes it easy to share configuration files or code across multiple containers without repeating long mount paths.
For instance, you can define a volume for a database and another for application code, linking them to their respective services. This declarative style is easier to maintain and version control than manual
docker run commands. It also allows for more complex configurations, such as mounting the same volume to multiple containers for data sharing.
How to Change Host for Keycloak Docker Container: A Guide demonstrates how external configurations and host mappings interact with containerized applications, highlighting the importance of correct path mapping.
Frequently Asked Questions
Can I share a single file instead of a whole directory?
Yes, you can mount a single file using bind mounts by specifying the full path to the file on the host and the desired path inside the container. This is useful for mounting specific configuration files like
nginx.conf or database credentials. Ensure the file exists on the host before starting the container, as Docker will not create it automatically.
What happens to shared files when the container stops?
If you use a bind mount, the files remain on the host filesystem unchanged, regardless of whether the container is running or stopped. If you use a named volume, the data is preserved in Docker's internal storage area and survives container removal. Only data written to the container's ephemeral layer is lost when the container is deleted, provided no volumes were used.
How do I fix permission denied errors when accessing mounted files?
Permission errors usually occur because the user inside the container does not match the owner of the host file. You can resolve this by changing the file ownership on the host to match the container's user ID, or by running the container with the
--user flag set to your host user's UID. Adjusting file permissions with
chmod on the host can also grant the necessary access.
Is there a performance difference between bind mounts and named volumes?
Bind mounts can sometimes suffer from slower performance on macOS and Windows due to the virtualization layer required to access the host filesystem. On Linux hosts, the performance difference is negligible. Named volumes are generally optimized for I/O operations and are preferred for high-throughput applications like databases, while bind mounts are better suited for development workflows requiring live code updates.
Can I mount a volume from a remote server?
Standard Docker volumes do not support direct mounting from remote servers over network protocols like NFS or SMB out of the box. You would need to set up a network filesystem client on the host machine first. Once the remote directory is mounted on the host, you can then use a bind mount to expose that local mount point to the container, effectively sharing remote files.