Docker NFS Implementation für bessere Performance in MacOS 11 (BigSur)

Allem voran: Docker allgemein ist ein sehr beliebtes und bekanntes Tool und bietet viele Möglichkeiten es zu verwenden und zu konfigurieren. Die folgende Beschreibung zeigt einen Weg der für mich eine funktionierende Entwicklungsumgebung in MacOS möglich gemacht hat.

Es ist nun schon einige Zeit bekannt, dass Docker unter MacOS Probleme macht. Meistens geht es um das Thema Performance wo, im Vergleich zu „native Linux“ und auch Windows MacOS sehr weit hinten liegt.

Das Problem

Die Basis des ganzen Problems liegt darin wie MacOS das Dateisystem von Docker Container mounted.

In Linux wird das sogenannte namespacing verwendet um die unterschiedlichen Prozesse und Ressourcen zu „gruppieren“ und damit nur in dieser Gruppe Zugriff aufeinander erhalten. Dieses namespacing Feature ist nur im Linux Kernel vorhanden und MacOS basiert nicht auf Linux.

Daher laufen Docker Container unter Linux quasi wie „native“ Applikationen da diese nicht wirklich „virtualisiert“ werden. Jedoch funktioniert dies eben unter MacOS nicht wie unter Linux, daher entsteht hier Latenz und Performance Probleme.

Folgendes Video (bzw. die Video Serie) von LiveOverflow kann ich definitiv empfehlen falls jemand mehr zum Thema namespacing und warum Linux docker containers keine VMs sind wissen möchte.

Die Lösung

Die folgende Beschreibung habe ich in diesem Blog-Post gefunden:

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

Daher danke an Jeff Geerling.

Zusammenfassend:

Bearbeite/Erstelle die Datei /etc/exports und füge folgende Zeile hinzu:

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

Diese Datei ist eine Konfigurations-Datei für das NFS System welches unter MacOS zur Verfügung steht. Hier wird also der Pfad /System/Volumes/Data inklusive aller Unterordner über den localhost zur Verfügung gestellt.

Hier kann es sein, dass ein Popup auftaucht, welches bzgl Berechtigungen Zugriff erfragt. Bitte dieses aktzeptieren.


Bearbeite/Erstelle die Datei /etc/nfs.conf und füge folgende Zeile hinzu:

nfs.server.mount.require_resv_port = 0

Diese Zeile wird benötigt damit der NFS Daemon über einen beliebigen Port Verbindungen zulässt. Andernfalls kann der Docker keine Verbindung zum NFS Daemon herstellen.


Nun muss der NFS Daemon neu gestartet werden.

sudo nfsd restart

Final muss Full Disk Access zum NFS Daemon gewährt werden.

Hierfür bitte unter System Preferences ==> Security & Privacy ==> Tab Privacy ==> Full Disk Access

Nun unten links auf das Schloss Symbol klicken um das bearbeiten der Einträge freizuschalten.

Danach das + Icon klicken um einen neuen Eintrag hinzuzufügen.

Nun bitte CMD + Shift + G drücken und den absoluten Pfad /sbin/nfsd eingeben und GO drücken

Der nfsd Daemon sollte nun in der Liste für Full Disk Access auftauchen und die Checkbox aktiviert sein.


Der letzte Schritt ist nun nur mehr die eigene docker-compose.yml anzupassen um NFS anstatt des „normalen volume binding“ zu verwenden.

Hier ein Beispiel für das „normalen volume binding“

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:

Wie im web container zu sehen wird das „normalen volume binding“ verwendet um den Inhalt des webvol Ordners des Hosts in den /var/www/html Ordner des Containers zu mounten.

Um dies nun zu ändern bitte ./webvol:/var/www/html:cached ändern auf nfsmount:/var/www/html:cached

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

Hiermit wird Docker gesagt, dass das „named volume“ nfsmount in den angegebenen containers Pfad gemounted werden soll.

Nun müssen wir aber das „named volume“ am Ende der docker-compose.yml noch definieren.

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

Wie hier zu sehen muss nun der verwendete Document Root Pfad in der device config definiert werden

Und damit sind wir fertig!

Zum testen füge eine nfo.php in den webvol Order, starte den Container und öffne localhost/nfo.php. Dieses sollte folgendes anzeigen

Das gesamte Projekt-Template kann HIER heruntergeladen werden.

Docker-Engine Debug-Mode standardmäßig aktiv

Nachdem ich mit einem Freund im BoltCMS Slack über das Docker Performance Problem geredet habe hat mich dieser darauf hingewiesen, dass Docker standardmäßig debugging aktiv hat in der Docker Engine (danke an Simon vom BoltCMS Slack Channel)

Wie hier zu sehen ist dieses hier auf true gesetzt.

Nachdem dieser Wert auf false gesetzt wurde hat sich die Performance meiner container wesentlich verbessert.

Ich habe keine Ahnung warum Docker diesen Wert standardmäßig setzt bzw. aktiviert (zu mindest am MacOS Client) aber diese Änderung in Kombination mit dem NFS mount hat mir einen wesentlichen Performance Schwung gebracht.

Share this post

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

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

The reCAPTCHA verification period has expired. Please reload the page.