410 Stimmen

Zugriff auf Host-Verzeichnis in Docker verweigert

Ich versuche, ein Host-Verzeichnis in Docker zu mounten, aber dann kann ich nicht darauf zugreifen von innerhalb des Containers, auch wenn die Zugriffsberechtigungen gut aussehen.

Ich mache

sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

und dann

ls -al

Es gibt mir:

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

und noch viele weitere Zeilen wie diese (ich glaube, dies ist der relevante Teil).

Wenn ich das mache

cd /Downloads
ls

ist das Ergebnis

ls: kann das Verzeichnis nicht öffnen .: Keine Berechtigung

Der Host ist Fedora 20, mit Docker 1.0.0 und go1.2.2.

Was läuft schief?

356voto

gregswift Punkte 4318

Im diesem Blog-Beitrag von Project Atomic über Volumes und SELinux findest du die ganze Geschichte.

Genauer gesagt:

Dies wurde kürzlich einfacher, da Docker endlich einen Patch eingefügt hat, der in docker-1.7 auftauchen wird (Wir haben den Patch in docker-1.6 auf RHEL, CentOS und Fedora mitgeführt).

Dieser Patch fügt die Unterstützung für "z" und "Z" als Optionen für die Volumenmounts (-v) hinzu.

Zum Beispiel:

docker run -v /var/db:/var/db:z rhel7 /bin/sh

Führt automatisch das chcon -Rt svirt_sandbox_file_t /var/db aus, wie es in der man-Seite beschrieben wird.

Noch besser, du kannst Z verwenden.

docker run -v /var/db:/var/db:Z rhel7 /bin/sh

Dadurch wird der Inhalt innerhalb des Containers mit dem genauen MCS-Label versehen, mit dem der Container ausgeführt wird, im Grunde läuft es auf chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/db wobei s0:c1,c2 für jeden Container unterschiedlich ist.

291voto

user3761313 Punkte 2959

Es handelt sich um ein SELinux Problem.

Sie können vorübergehend den Befehl ausführen

su -c "setenforce 0"

auf dem Host, um darauf zuzugreifen, oder fügen Sie ansonsten eine SELinux-Regel hinzu, indem Sie

chcon -Rt svirt_sandbox_file_t /path/to/volume

92voto

BMitch Punkte 183873

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.

74voto

John Phillips Punkte 916

WARNUNG: Diese Lösung birgt Sicherheitsrisiken.

Versuchen Sie, den Container als privilegiert auszuführen:

sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash

Eine andere Option (die ich nicht ausprobiert habe) wäre, einen privilegierten Container zu erstellen und dann nicht privilegierte Container darin zu erstellen.

40voto

Thomas8 Punkte 1117

Von access.redhat.com: Sharing_Data_Across_Containers:

Host-Volumeneinstellungen sind nicht portabel, da sie von dem Host abhängig sind und auf keiner anderen Maschine funktionieren könnten. Aus diesem Grund gibt es kein Dockerfile-Äquivalent zum Einbinden von Host-Verzeichnissen in den Container. Außerdem ist zu beachten, dass das Host-System keine Kenntnis über die SELinux-Richtlinie des Containers hat. Daher ist das eingebundene Host-Verzeichnis für den Container nicht beschreibbar, unabhängig von der Einstellung rw, wenn die SELinux-Richtlinie durchgesetzt wird. Derzeit können Sie dies umgehen, indem Sie den entsprechenden SELinux-Richtlinientyp dem Host-Verzeichnis zuweisen:

chcon -Rt svirt_sandbox_file_t host_dir

Wo host_dir ein Pfad zum Verzeichnis auf dem Host-System ist, das in den Container eingebunden ist.

Es scheint nur eine Workaround zu sein, aber ich habe es versucht und es funktioniert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X