To mount a single local file to the container, we can extend the previous
run
command:
We’ve just created and started a new container mounting our local file. Let’s now take a look at the configuration keys.
The
source
(alternatively –
src
) is the absolute path to the file or directory on the host that should be mounted. We can also use local shell commands to calculate the result.
The
target
(alternatively –
destination, dst
) takes the absolute path where the file or directory is mounted inside the container.
Finally, there’s also a
readonly
option which makes the bind mount read-only. This flag is optional.
In the end, let’s verify the mounting result:
$ docker exec ... cat /file.txt
Hi Baeldung!
We can also inspect container details, using the
docker inspect
command to check all mounts:
"Mounts": [
"Type": "bind",
"Source": ".../file.txt",
"Destination": "/file.txt",
"Mode": "",
"RW": false,
"Propagation": "rprivate"
Now, we can look at common mistakes related to paths. If we provide non-absolute paths, Docker CLI will return an error that terminates the command execution:
docker: Error response from daemon: invalid mount config for type "bind": invalid mount path: 'file.txt+' mount path must be absolute.
Sometimes we provide an absolute source path to a file missing on the host machine. In this case, the container will start mounting an empty directory in the target path. Moreover, if we are working on Windows, we should take care of the path conversions.
3.2. –volume Option
As we mentioned earlier, we can replace –mount and–volume (–v) flags with the same functionality. We must also remember that the syntax is completely different.
The –volume syntax consists of three fields, separated by colon characters. Moreover, the order of the values is significant.
Let’s transform the previous example by using the –v option:
$ docker run -d -it
-v "$(pwd)"/file.txt:/file.txt:ro \
alpine:latest
The result is the same. We’ve just mounted our local file to the container.
As we can see, three values given by the –v option are similar to the keys used with the –mount flag.
The first value, like the source key, specifies the path to a file or directory on the host machine.
The second field provides a path inside the container and the target key.
Finally, we have an optional ro option that specifies the read-only attribute.
After we check the syntax, let’s see some common mistakes. Same as before, we should remember about Windows path separators. Selecting a non-existent file will also result in creating an empty directory.
But there is a slight difference with non-absolute paths. If we provide an invalid path to the second value, same as previously, Docker CLI will return an error. However, if we provide such a path as a source value, the Docker will create a named volume which is another mechanism of persisting files.
In summary, the most significant difference between the –mount and –volume flags is their syntax. We can use both of them interchangeably.
4. Binding Files Using Docker Compose
After we learned how to bind files using the Docker CLI, let’s now check if we can still get the same result with docker-compose files.
As we know, docker-compose is a convenient way of creating containers by providing configuration files. For each service, we can declare a volumes section to configure binding options. The volumes section can be specified using either the long syntax or the short one, which has lots in common with –mount and –volumes flags, respectively.
4.1. Long Syntax
The long syntax allows us to configure each key separately to specify the volume mount. With the same example, let’s prepare a docker-compose entry:
services:
alpine:
image: alpine:latest
tty: true
volumes:
- type: bind
source: ./file.txt
target: file.txt
read_only: true
Same as with the Docker CLI, our container is now preconfigured to mount a local file in it. We use type, source, target, and the optional read_only keys to determine the configuration, just like we use the –mount flag. Additionally, we can use a relative path as the source value, calculated from the docker-compose file.
4.2. Short Syntax
The short syntax uses a single string value separated by colons to specify a volume mount:
services:
alpine:
image: alpine:latest
tty: true
volumes:
- ./file.txt:/file.txt:ro
The string is almost the same as the –volume flag. The first two values represent the source and target paths, respectively. The last part specifies additional flags, where we can specify the read-only attribute. As with the long syntax, we can also use a relative source path.
We must remember that the long form allows us to configure additional fields that can’t be expressed in the short syntax. Moreover, we can mix both syntaxes in the single volumes section.
5. Conclusion
In this article, we’ve just covered a part of data persistence in Docker. We tried to mount a single local file in a container using both the Docker CLI and docker-compose files.
The Docker CLI provides the –mount and –volume options with a run command to bind a single file or directory. Both flags work similarly but have different syntaxes. As a result, we can use them interchangeably.
We can also reach the same result using docker-compose files. Inside the volumes section for each service, we can configure a volume mount using either a long or short syntax. Same as before, these syntaxes interchangeably produce the same result.