In der Regel treten Berechtigungsprobleme bei der Bereitstellung eines Host-Volumes auf, weil die UID / GID im Container gemäß den UID / GID-Berechtigungen der Datei auf dem Host keinen Zugriff auf die Datei hat. Dieser spezielle Fall ist jedoch anders.
Der Punkt am Ende der Berechtigungszeichenfolge zeigt an drwxr-xr-x.
, dass SELinux konfiguriert ist. Wenn Sie einen Host-Mount mit SELinux verwenden, müssen Sie eine zusätzliche Option an das Ende der Volume-Definition übergeben:
- Die
z
Option gibt an, dass der Bind-Mount-Inhalt von mehreren Containern gemeinsam genutzt wird.
- Die
Z
Option gibt an, dass der Bind-Mount-Inhalt privat und nicht freigegeben ist.
Ihr Volume Mount-Befehl würde dann folgendermaßen aussehen:
sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
Weitere Informationen zu Host-Mounts mit SELinux finden Sie unter: https://docs.docker.com/storage/#configure-the-selinux-label
Für andere Benutzer, bei denen dieses Problem bei Containern auftritt, die als ein anderer Benutzer ausgeführt werden, müssen Sie sicherstellen, dass die UID / GID des Benutzers im Container über Berechtigungen für die Datei auf dem Host verfügt. Auf Produktionsservern erfolgt dies häufig, indem die UID / GID im Image-Erstellungsprozess so gesteuert wird, dass sie mit einer UID / GID auf dem Host übereinstimmt, der Zugriff auf die Dateien hat (oder, noch besser, keine Host-Mounts in der Produktion verwenden).
Ein benanntes Volume wird häufig Host-Mounts vorgezogen, da es das Volume-Verzeichnis aus dem Image-Verzeichnis initialisiert, einschließlich etwaiger Dateieigentümer und Berechtigungen. Dies geschieht, wenn das Volume leer ist und der Container mit dem benannten Volume erstellt wird.
MacOS-Benutzer haben jetzt OSXFS, das UID / GIDs automatisch zwischen dem Mac-Host und den Containern verarbeitet. Ein Ort, an dem es nicht hilft, sind Dateien aus der eingebetteten VM, die in den Container eingebunden werden, wie /var/lib/docker.sock.
Für Entwicklungsumgebungen, in denen sich die Host-UID / GID pro Entwickler ändern kann, besteht meine bevorzugte Lösung darin, den Container mit einem als Root ausgeführten Einstiegspunkt zu starten, die UID / GID des Benutzers im Container so zu korrigieren, dass sie mit der UID / GID des Host-Volumes übereinstimmt, und Verwenden Sie gosu
diese Option, um vom Root zum Containerbenutzer zu wechseln und die Anwendung im Container auszuführen. Das wichtige Skript dafür befindet sich fix-perms
in meinen Basis-Image-Skripten, die unter https://github.com/sudo-bmitch/docker-base zu finden sind
Das wichtige Bit aus dem fix-perms
Skript 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 "Changing UID of $opt_u from $OLD_UID to $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
fi
Dadurch werden die UID des Benutzers im Container und die UID der Datei usermod
abgerufen. Wenn sie nicht übereinstimmen, wird die UID aufgerufen. Zuletzt wird eine rekursive Suche durchgeführt, um alle Dateien zu reparieren, die die UIDs nicht geändert haben. Ich mag dies besser als das Ausführen eines Containers mit einem -u $(id -u):$(id -g)
Flag, da für den obigen Einstiegspunktcode nicht jeder Entwickler ein Skript ausführen muss, um den Container zu starten, und für alle Dateien außerhalb des Volumes, deren Eigentümer der Benutzer ist, werden die Berechtigungen korrigiert.
Sie können Docker auch ein Hostverzeichnis aus einem Image initialisieren lassen, indem Sie ein benanntes Volume verwenden, das einen Bind-Mount ausführt. Dieses Verzeichnis muss im Voraus vorhanden sein, und Sie müssen einen absoluten Pfad zum Host-Verzeichnis angeben, im Gegensatz zu Host-Volumes in einer Compose-Datei, bei denen es sich um relative Pfade handeln kann. Das Verzeichnis muss auch leer sein, damit Docker es initialisieren kann. Drei verschiedene Optionen zum Definieren eines benannten Volumes für einen Bind-Mount sehen folgendermaßen aus:
# create the volume in advance
$ docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
test_vol
# create on the fly with --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
# inside a docker-compose file
...
volumes:
bind-test:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/test
...
Wenn Sie versuchen, Benutzernamensräume zu verwenden, werden Sie feststellen, dass Host-Volumes Berechtigungsprobleme haben, da die UIDs / GIDs der Container verschoben werden. In diesem Szenario ist es wahrscheinlich am einfachsten, Host-Volumes zu vermeiden und nur benannte Volumes zu verwenden.