Typischerweise liegen Berechtigungsprobleme bei einem Host-Volumenmount vor, weil das UID/GID innerhalb des Containers keinen Zugriff auf die Datei gemäß den UID/GID-Berechtigungen der Datei auf dem Host hat. Dieser spezielle Fall ist jedoch anders.
Der Punkt am Ende des Berechtigungsstrings, drwxr-xr-x.
, zeigt an, dass SELinux konfiguriert ist. Wenn Sie einen Host-Mount mit SELinux verwenden, müssen Sie eine zusätzliche Option am Ende der Volumendefinition übergeben:
- Die Option
z
zeigt an, dass der Bind-Mount-Inhalt zwischen mehreren Containern gemeinsam genutzt wird.
- Die Option
Z
zeigt an, dass der Bind-Mount-Inhalt privat und nicht gemeinsam genutzt wird.
Ihr Volumen-Mount-Befehl sieht dann so aus:
sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
Weitere Informationen zu Host-Mounts mit SELinux finden Sie unter Konfigurieren des Selinux Labels.
Für andere, die dieses Problem mit Containern sehen, die als anderer Benutzer ausgeführt werden, müssen Sie sicherstellen, dass das UID/GID des Benutzers innerhalb des Containers Berechtigungen für die Datei auf dem Host hat. Auf Produktions-Servern wird dies häufig durch die Kontrolle des UID/GID im Image-Build-Prozess erreicht, um mit einem UID/GID auf dem Host übereinzustimmen, der Zugriff auf die Dateien hat (oder noch besser, verwenden Sie keine Host-Mounts in der Produktion).
Ein benanntes Volumen wird oft gegenüber Host-Mounts bevorzugt, da es das Volumenverzeichnis aus dem Bildverzeichnis initialisiert, einschließlich aller Dateibesitzer und Berechtigungen. Dies geschieht, wenn das Volumen leer ist und der Container mit dem benannten Volumen erstellt wird.
MacOS-Benutzer haben jetzt OSXFS, das UID/GID automatisch zwischen dem Mac-Host und den Containern verwaltet. Ein Ort, an dem es nicht hilft, sind Dateien aus der eingebetteten VM, die in den Container eingehängt werden, wie z.B. /var/lib/docker.sock.
In Entwicklungsumgebungen, in denen das Host-UID/GID pro Entwickler variieren kann, ist meine bevorzugte Lösung, den Container mit einem Einstiegspunkt als root zu starten, das UID/GID des Benutzers im Container an das Host-Volume-UID/GID anzupassen und dann gosu
zu verwenden, um vom Root auf den Container-Benutzer zu wechseln, um die Anwendung im Container auszuführen. Das wichtige Skript dafür ist fix-perms
in meinen Basisskripten für Images, die unter folgender Adresse zu finden sind: Docker-Basisbilder von Brandon Mitchell
Der wichtige Teil aus dem Skript fix-perms
ist:
# Update the UID
if [ -n "$opt_u" ]; then
OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
NEW_UID=$(stat -c "%u" "$1")
if [ "$OLD_UID" != "$NEW_UID" ]; then
echo "Ändere UID von $opt_u von $OLD_UID zu $NEW_UID"
usermod -u "$NEW_UID" -o "$opt_u"
if [ -n "$opt_r" ]; then
find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
fi
fi
Damit wird das UID des Benutzers im Container und das UID der Datei abgerufen, und wenn sie nicht übereinstimmen, ruft es usermod
auf, um das UID anzupassen. Zum Schluss wird eine rekursive Suche durchgeführt, um alle Dateien zu reparieren, deren UIDs sich nicht geändert haben. Mir gefällt dies besser als das Ausführen eines Containers mit einer -u $(id -u):$(id -g)
Flagge, weil der oben genannte Einstiegspunktcode nicht erfordert, dass jeder Entwickler ein Skript ausführt, um den Container zu starten, und alle Dateien außerhalb des Volumens, die dem Benutzer gehören, haben ihre Berechtigungen korrigiert.
Sie können Docker auch ein Host-Verzeichnis aus einem Image initialisieren lassen, indem Sie ein benanntes Volumen verwenden, das einen Bind-Mount durchführt. Dieses Verzeichnis muss bereits existieren, und Sie müssen einen absoluten Pfad zum Host-Verzeichnis angeben, im Gegensatz zu Host-Volumes in einer Compose-Datei, für die relative Pfade verwendet werden können. Das Verzeichnis muss auch leer sein, damit Docker es initialisieren kann. Drei verschiedene Optionen für die Definition eines benannten Volumens für einen Bind-Mount sehen wie folgt aus:
# Volumen im Voraus erstellen
$ docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
test_vol
# On-the-fly erstellen mit --mount
$ docker run -it --rm \
--mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
foo
# In einer Docker-Compose-Datei
...
volumes:
bind-test:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/test
...
Zuletzt, wenn Sie versuchen, Benutzernamensräume zu verwenden, werden Sie feststellen, dass Host-Volumes Berechtigungsprobleme haben, weil die UID/GIDs der Container verschoben sind. In diesem Szenario ist es wahrscheinlich am einfachsten, Host-Volumes zu vermeiden und nur benannte Volumen zu verwenden.