Emmanuel Frécon
by Emmanuel Frécon
2 min read

Docker volumes plugins have an API. When creating a volume plugin, in addition to implement the API, you will also have to implement the volume API. On the other hand, there are a large number of fuse-based implementations for remote storages of various sorts. This post is about leveraging these implementations as pseudo-volumes, while performing the mount in a container. This comes at the cost and complexity of sharing a well-known directory on the host between the container that will perform the mount, with the container(s) that use the mount.

Capabilities

The first step to manage and understand is how to give away enough rights to the container that will perform the mount so that other processes on the host (outside that container) will be able to access the files and directories. This can be achieved through using the following options for docker run:

  • Give the fuse device to your container through --device /dev/fuse
  • Raise its capabilities to bypass some of the security layers through: --cap-add SYS_ADMIN and --security-opt "apparmor=unconfined"
  • Mount the local host file system into the container in a way that it can be shared back with other processes and containers using rshared.

Unmounting

You also want to properly unmount when the container gracefully terminates. This is achieved through a combination of tini and proper trap in the shell. The reason for this is that your are likely to interface the fuse implementation through some sort of entrypoint

tini

Use tini as the main entrypoint in your Dockerfile and arrange to give it the -g option so that it properly propagates signals to the entire mounting system in the container. tini exists as an Alpine package which can be helpful in keeping down the size of the image.

Cleanup

In order to clean properly, you can arrange for a shell to be called at the end of your entrypoint implementation, perhaps after having checked that the mount performed as it should. This shell will trap the INT and TERM signals, unmount the volume (lazily) and propagate these to the mount process. Without tini, you would never have received these signals, by Docker construction and design.

Examples

I have made available two example images following these principles:

  • webdav-client mounts WebDAV resources and leverages the full potential of davfs2, being able to leverage all the options supported by davfs2. This is in contrast to the davfs volume which also uses davfs2 under the hood, but misses some of the configuration options.
  • s3fs mounts a remote S3 bucket using the fuse implementation with the same name. It supports all the official versions of the original fuse projects through tags