
Ich versuche, mein aktuell auf meinem Server laufendes Nginx in einen Container zu packen. Dazu habe ich folgende Docker-Compose-Datei erstellt:
version: "3.8"
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
restart: unless-stopped
group_add: ["33"]
volumes:
- "/etc/nginx-docker:/etc/nginx/conf.d:ro"
- "/run/php:/run/php"
- "/var/www:/var/www:ro"
ports:
- "8111:80"
- "8443:443"
Alles funktioniert einwandfrei, aber das Problem besteht darin, dass auf meinem Hostsystem immer noch php-fpm „nativ“ (nicht dockerisiert) ausgeführt wird und ich deren Sockets für meinen Nginx-Container verwenden möchte (daher die Zeile volumes: - "/run/php:/run/php"
).
Die Berechtigungen der Sockets sind srw-rw---- www-data:www-data
. Daher habe ich den Container-Benutzer zur Gruppe 33 hinzugefügt (das sind www-data auf meinem Host-System -> group_add: ["33"]
). Wenn ich im Container die Gruppen-IDs überprüfe, 33
wird die ID tatsächlich dem aktuell angemeldeten Benutzer hinzugefügt:
/ # id -G
0 1 2 3 4 6 10 11 20 26 27 33
/ # id -u
0
/ # whoami
root
Wenn ich jedoch eine Website aufrufe, die mit PHP betrieben wird, erhalte ich in den Nginx-Protokollen folgende Fehlermeldung:
2024/01/21 08:58:53 [crit] 21#21: *1 connect() to unix:/run/php/php8.2-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.192.68, server: _, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "op---s:8111"
Irgendwelche Hinweise oder Lösungen, was fehlen könnte, damit es funktioniert?
Antwort1
Ich habe ein bisschen gegraben :)
Wenn Sie den Container aufrufen, in dem das Nginx-Image ausgeführt wird, können Sie sehen, dass einige Nginx-Prozesse ausgeführt werden:
docker exec -it 43b5b971c433 /bin/sh
/ # ps -ef |grep nginx
1 root 0:00 nginx: master process nginx -g daemon off;
21 nginx 0:00 nginx: worker process
22 nginx 0:00 nginx: worker process
23 nginx 0:00 nginx: worker process
24 nginx 0:00 nginx: worker process
42 root 0:00 grep nginx
Einige werden als ausgeführt root
, andere als nginx
Benutzer.
root
Sie haben den Benutzer der Gruppe in Ihrer Docker-Compose-Datei hinzugefügt www-data
, aber auch ohne das sollte der Root-Benutzer über alle erforderlichen Berechtigungen für den Zugriff auf den PHP-UNIX-Socket verfügen.
Sie können die Berechtigungen mit dem Befehl testen test
. Geben Sie den Exit-Code aus, um zu sehen, ob der Befehl erfolgreich war oder nicht. Wie Sie sehen, kann der Root-Benutzer die Socket-Datei lesen, aber nicht ausführen:
/run/php # whoami
root
/run/php # test -r php8.1-fpm.sock; echo $?
0
/run/php # test -x php8.1-fpm.sock; echo $?
1
Der permission denied
Fehler wird also wahrscheinlich von dem nginx worker
Prozess verursacht, der als nginx
Benutzer ausgeführt wird.
Lassen Sie uns zuerst die Berechtigungen für die Dateien im Docker-Container überprüfen ...
ls -al
gibt folgende Ausgabe aus:
srw-rw---- 1 xfs xfs 0 Jan 25 08:58 php8.1-fpm.sock
besagt, dass die Socket-Datei dem „xfs“ gehört. Ein kurzer Blick auf die /etc/group
Datei im Container zeigt, dass die ID der xfs
Gruppe 33
mit der ID auf dem Hostcomputer für die Gruppe identisch ist www-data
.
Innerhalb des Containers können Sie den Nginx-Benutzer zur XFS-Gruppe hinzufügen:
addgroup nginx xfs
Das Problem sollte jetzt behoben sein.
Ich bin nicht sicher, wie Sie dies direkt in Ihre Erstellungsdatei einfügen (wie geben Sie an, welcher Benutzer zur Gruppe hinzugefügt werden soll?) – aber Sie könnten es in Ihrer Docker-Datei tun, wenn Sie ein neues Image erstellen können.
Nach dem Neustart des Containers scheinen die Berechtigungen jedoch bestehen zu bleiben.
Antwort2
Bestimmen Sie den Benutzer und die Gruppe, als die PHP-FPM auf dem Host ausgeführt wird. Normalerweise finden Sie diese Informationen in Ihrer PHP-FPM-Konfigurationsdatei (normalerweise unter /etc/php/7.x/fpm/pool.d/www.conf).
Aktualisieren Sie dann Ihr Docker-Compose und fügen Sie Folgendes hinzu
user: "your_php_user:your_php_group"
Antwort3
Alles funktioniert einwandfrei, aber das Problem besteht darin, dass auf meinem Hostsystem immer noch php-fpm „nativ“ (nicht dockerisiert) läuft und ich deren Sockets für meinen Nginx-Container verwenden möchte (daher die Zeilenvolumes: -
"/run/php:/run/php"
).
Dies ist weder möglich noch sinnvoll.
Docker erzeugt seinen eigenen Netzwerk-Namespace, sodass Sie Ihren eigenen Firewall-Stack, IP-Stack und Unix-Netzwerk-Stack erhalten.
Auch wenn Sie das Berechtigungsproblem beheben, nehmen wir beispielsweise an, dass Sie sich manuell mit der Socket-Datei 666 beim Container anmelden docker exec
und chmod
der Kürze halber davon ausgehen, dass auch keine Benutzernamensräume im Weg sind.
Was Sie verlangen, ist das Äquivalent von:
- Ausführen einer
php-fpm
Instanzsystem1
mit einem Unix-Socket/var/run/php-fpm.sock
- Exportieren des
/var/run
Pfads über NFS aufsystem1
. - Montage
system1:/var/run
aufsystem2
. Ein völlig separates System. - Ich versuche,
connect()
den besagten Unix-Socket Socket einzuschaltensystem2
und erwartesystem1
eine Antwort mitphp-fpm
.
So wie Sie das eigentlich machen sollten (sollten Sie eigentlichwollenum dies zu tun, was eine separate Angelegenheit ist) besteht darin, die Instanz über IP abzuhören php-fpm
– sie also host_system:12345
beispielsweise an zu binden. Verwenden Sie dann nginx
in, container
um eine Verbindung herzustellen mit host_system:12345
.
Das ist alles einfach falsch. Hören Sie nicht auf mich. Wenn Sie einen gut benannten Unix-Socket erstellen, der in einem der beiden Namespaces verfügbar ist und dessen Pfad von beiden Namespaces gemeinsam genutzt wird, wird bei einer Verbindung zu diesem Unix-Socket eine Verbindung zum anderen Namespace hergestellt!
https://lore.kernel.org/all/[email geschützt]/T/
Dieser Patch behebt dieses Problem speziell. Als ich das getestet habe, ist es offensichtlich schon sehr lange her! :)
Der einzige Fall, in dem dies nicht der Fall zu sein scheint, ist die anonyme Erstellung von Unix-Sockets. Dies ist jedoch eine ziemlich Linux-spezifische und nicht oft verwendete Funktion von Unix-Sockets.