Docker NFS Implementation for better performance in MacOS 11 (Big Sur)

First of all: Docker in general is very popular topic and has many ways how it can be used, configured and worked with. The following statements are how I interpreted the whole docker ecosystem and how I personally got a working docker environment with MacOS.

It has been known for a long time, that Docker has performance issues under MacOS. You can also find many other tutorials online which seem to improve the performance but in my experience most of them didn’t.

The Problem

Basically Docker for MacOS doesn’t “mount” the filesystem of the container the same way as Linux does.

In Linux Docker basically “separates” all its containers via namespacing. This namespacing feature is present in the Linux kernel but MacOS is not based on Linux.

Therefore in Linux there is no difference between files on the host and container system but MacOS has to circumvent this feature “somehow”. And this “somehow” basically creates a whole lot of latency which reduces the performance dramatically.

I can definitely recommend this whole series from LiveOverflow where he goes deeper into the whole namespacing topic and why linux docker containers are not VMs (if you are interested)

The solution

I found the following blog article which basically has the solution + performance benchmarks in them:

https://www.jeffgeerling.com/blog/2020/revisiting-docker-macs-performance-nfs-volumes

So definitely kudos to him!

To summarise:

Edit/Add the file /etc/exports and add the following line:

/System/Volumes/Data -alldirs -mapall=501:20 localhost

This file is a config file used by the NFS system available under MacOS. So therefore this line exports the directory /System/Volumes/Data including all subdirectories to the localhost.

It could be that a permission popup shows while saving this file. Please accept that.


Edit/add the file /etc/nfs.conf and add the following line:

nfs.server.mount.require_resv_port = 0

This line is required to tell the NFS daemon to allow connections from any port. Otherwise Docker’s NFS connections may be blocked.


Now restart the NFS Daemon to reload the new config

sudo nfsd restart

Finally I had to add Full Disk Access to the NFS Daemon.

Go to System Preferences ==> Security & Privacy ==> Tab Privacy ==> Full Disk Access

Click the lock at the bottom left to allow editing the entries.

Then click on the + icon to add a new entry.

Now press CMD + Shift + G to enter the absolute path /sbin/nfsd and klick GO

The nfsd should now appear in the list of apps which should have Full Disk Access and the checkbox next to it should be checked.


The last step is to adjust your docker-compose.yml to actually use NFS instead of the normal volume binding.

Here is an example of an “old” docker-compose.yml

version: "3.8"
services:
  web:
    container_name: sl_web
    build:
      context: .
      dockerfile: docker/web/Dockerfile
    ports:
      # 'host:container'
      - '80:80'
    networks:
      - frontend
      - backend
    volumes:
      - ./webvol:/var/www/html:cached

  mysql:
    container_name: sl_db
    image: mysql:5.7
    command: mysqld
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --init-connect='SET NAMES UTF8;'
    ports:
      # 'host:container'
      - '3306:3306'
    networks:
      - backend
    environment:
      - MYSQL_ROOT_PASSWORD=sl_db_root_password
      - MYSQL_DATABASE=sl_db_name
      - MYSQL_USER=sl_db_user
      - MYSQL_PASSWORD=sl_db_password

  phpmyadmin:
    container_name: sl_pma
    image: phpmyadmin/phpmyadmin
    networks:
      - frontend
      - backend
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: root
      PMA_PASSWORD: root
    ports:
      # 'host:container'
      - '8080:80'

networks:
  frontend:
  backend:

As you can see the web container uses a normal volume binding to mount the hosts webvol folder to the containers /var/www/html folder

And here are the main changes which need to be done for the NFS implementation

Adjust the volume mount from ./webvol:/var/www/html:cached to nfsmount:/var/www/html:cached

  web:
    ...
    volumes:
      - nfsmount:/var/www/html:cached

This tells docker to use the “named volume” nfsmount to mount into the containers path.

Now we have to define the “named volume” at the bottom of our docker-compose.yml

volumes:
  nfsmount:
      driver: local
      driver_opts:
          type: nfs
          o: addr=host.docker.internal,rw,nolock,hard,nointr,nfsvers=3
          device: ":$PWD/webvol"

As you can see the adjusted document root path is now being set in the device config of the volume definition.

And with that we should be fine.

Adding a nfo.php to the webvol folder, starting the docker instance and browsing localhost/nfo.php should result it.

You can download this whole project template HERE.

Docker-Engine Debug-Mode default on

After talking about docker performance issues with a friend of mine (thanks Simon from BoltCMS Slack) he told me, that Docker itself has a debug mode which drastically reduces performance.

And as you can see here this setting is set to true.

After setting that to false and recreating my containers my performance had drastically increased.

I have no idea why this is a default setting Docker sets (for at leat the MacOS Client) but this in combination with the NFS mount was the solution to my performance problems I had Docker on MacOS.

Share this post

Leave a Reply

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.