Table of Contents
First of all: Docker in general is a 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.