Skip to content

NFS shares in Docker

Network File System (NFS) is a widely supported and simple protocol for accessing files over a network as if they were local. This makes it ideal for many Docker (and other container) architectures as container storage is ephemeral and limited. Attaching NFS shares in Docker allows your container to read and write files to persistent network storage.

Creating an NFS share

To demonstrate NFS shares in Docker, I’ll need an NFS share. For this demo, I’ve created a share on my Ubuntu laptop at /mnt/nfs-share:

# Install NFS on local machine
sudo apt-get update
sudo apt install -y nfs-kernel-server

# Create an NFS share on local machine
sudo mkdir /mnt/nfs-share
sudo chown $USER:$(id -gn) /mnt/nfs-share
chmod 777 /mnt/nfs-share
echo "/mnt/nfs-share  127.0.0.1(rw,sync,root_squash,no_subtree_check) 172.17.0.0/16(rw,sync,root_squash,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -a

The /etc/exports file defines what is shared with whom. I’m sharing /mnt/nfs-share with 127.0.0.1(localhost) and with 172.17.0.0/16(default docker network subnet range). We need both for the examples below as I’ll access this share from both the Docker Engine (on localhost) and from inside Docker containers (in the Docker subnet).

Just to test that it works, I’ve mounted the share locally at /mnt/nfs-mount:

# Test NFS share by mounting locally
sudo mkdir /mnt/nfs-mount
sudo chown $USER:$(id -gn) /mnt/nfs-mount
sudo mount -t nfs 127.0.0.1:/mnt/nfs-share /mnt/nfs-mount

# Test it
ls /mnt/nfs-share # no files
touch /mnt/nfs-mount/testfile
ls /mnt/nfs-share # contains testfile

NFS volumes

Docker now has native support for NFS as a volume. NFS shares can be attached as a volume almost as easily as creating a volume on a local drive.

First, use the Docker CLI to create the volume. It has type=nfs, o= defines the NFS options including the remote server address (127.0.0.1) and device= defines the name (path) of the share on the remote server (/mnt/nfs-share):

docker volume create \
  --driver local \
  --opt type=nfs \
  --opt o=addr=127.0.0.1,vers=4,soft \
  --opt device=:/mnt/nfs-share \
  nfs-volume

Test it works by attaching it to a container and writing a file to it:

docker run --rm -v nfs-volume:/mnt/nfs-volume busybox touch /mnt/nfs-volume/file_created_in_docker_nfs_volume
ls /mnt/nfs-share/ # contains file_created_in_docker_nfs_volume

If you prefer Docker Compose, you can define the volume and container in a single compose file:

services:
  container:
    image: alpine
    volumes:
      - nfs-volume:/mnt/nfs-volume
    command: touch /mnt/nfs-volume/file_created_in_docker_nfs_volume

volumes:
  nfs-volume:
    driver: local
    driver_opts:
      type: nfs
      o: "addr=127.0.0.1,vers=4,soft"
      device: ":/mnt/nfs-share"

Run this with docker compose up and sure enough, it writes the file to my NFS share on /mnt/nfs-share.

Mount NFS from a container

An alternative way to access NFS shares in Docker containers is to mount it from inside the container, exactly as you’d mount it from a regular machine. This is not recommended though. Docker runs containers with limited privileges and by default it does not grant permission to mount. We can work around by granting additional privileges but I’d always prefer to let Docker handle NFS as a volume (as above). This is more secure and more idiomatic.

Mounting an NFS share from a container is similar to mounting from a regular machine. Add the required software package (nfs-utils) and then use the mount command.

FROM alpine
RUN mkdir /mnt/nfs-mount-in-docker && \
    apk add nfs-utils
CMD mount -o nolock 172.17.0.1:/mnt/nfs-share /mnt/nfs-mount-in-docker && \
    touch /mnt/nfs-mount-in-docker/file-created-in-docker-nfs-mount

Build as you would any other container image:

docker build -t docker-nfs .

If you try to run this though, it will fail.

docker run --rm docker-nfs
mount.nfs: failed to prepare mount: Operation not permitted
mount: permission denied (are you root?)

Docker refuses the mount permission to the user running the container – yes, it is root. The simplest solution is to run the container in privileged mode. This gives the container full privileges of the host system.

docker run --rm --privileged docker-nfs

The --privileged flag is usually a bad idea. It grants more permissions to the container than it needs just to mount an NFS share. You can instead grant more limited capabilities to the container. The specific capability is CAP_SYS_ADMIN.

docker run --rm --cap-add sys_admin docker-nfs

On my Ubuntu host this still fails.

mount.nfs: access denied by server while mounting 172.17.0.1:/mnt/nfs-share
mount.nfs: access denied by server while mounting 172.17.0.1:/mnt/nfs-share
mount: mounting 172.17.0.1:/mnt/nfs-share on /mnt/nfs-mount-in-docker failed: Permission denied

This time, it’s Ubuntu’s AppArmor system that’s causing trouble. You can disable this too:

docker run --rm --cap-add sys_admin --security-opt apparmor:unconfined docker-nfs

So yes, you can mount an NFS share from inside a container if you really want. However, given that you need to disable multiple security protections and given that the Docker Engine can provide this to you as a volume, I suggest it’s best avoided.

Published inDocker

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *