Jemand hat mich schon einmal gefragt, ob es möglich ist, Volumes zu mounten, nachdem der Docker-Container gestartet wurde. Angesichts der Funktionsweise des mnt-Namespace dachte ich zunächst, dass dies schwierig zu erreichen wäre. Aber ich denke, jetzt ist es geschafft.
Umounten Sie den im ersten Schritt erstellten temporären Einhängepunkt. Vorsichtsmaßnahmen In den folgenden Beispielen habe ich absichtlich das $-Zeichen eingefügt, um anzuzeigen, dass es sich um eine Shell-Befehlszeilenaufforderung handelt, damit Sie leichter unterscheiden können, was Sie eingeben müssen und was der Computer antwortet. Für einige mehrzeilige Befehle verwende ich weiterhin >. Mir ist bewusst, dass die Befehle in den Beispielen dadurch nicht so einfach kopiert und eingefügt werden können. Wenn Sie den Code kopieren und einfügen möchten, sehen Sie sich das Beispielskript am Ende des Artikels an. Detaillierte Schritte In den folgenden Beispielen wird davon ausgegangen, dass Sie einen einfachen Container namens „Charlie“ mit dem folgenden Befehl gestartet haben: $ docker run --name charlie -ti ubuntu bash Was wir tun müssen, ist, den Hostordner nsenter Zuerst benötigen wir nsenter und das Hilfsskript docker-enter. Warum? Weil wir das Dateisystem aus dem Container mounten wollen. Aus Sicherheitsgründen lässt der Container dies nicht zu. Mit nsenter können wir die oben genannten Sicherheitsbeschränkungen umgehen und beliebige Befehle im Kontext des Containers (genauer gesagt des Namespace) ausführen. Dies erfordert natürlich Root-Rechte auf dem Docker-Host. Die einfachste Möglichkeit, nsenter zu installieren, besteht darin, es zusammen mit dem Skript „docker-enter“ auszuführen: $ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter Weitere Einzelheiten finden Sie auf der Homepage des nsenter-Projekts. Suchen Sie das Dateisystem Wir möchten das Dateisystem, das den Hostordner (/home/jpetazzo/Work/DOCKER/docker) enthält, im Container mounten. Dann müssen wir herausfinden, welches Dateisystem dieses Verzeichnis enthält. Zuerst müssen wir die Datei kanonisieren (oder dereferenzieren), falls es sich um einen symbolischen Link handelt oder ihr Pfad symbolische Links enthält: $ readlink --canonicalize /home/jpetazzo/Arbeit/DOCKER/docker /home/jpetazzo/go/src/github.com/docker/docker Ha, es ist tatsächlich ein symbolischer Link! Lassen Sie uns dies in eine Umgebungsvariable einfügen: $ HOSTPATH=/home/jpetazzo/Arbeit/DOCKER/docker $REALPATH=$(readlink --kanonisieren Sie $HOSTPATH) Als nächstes müssen wir herausfinden, welches Dateisystem diesen Pfad enthält. Wir tun dies mit einem etwas unerwarteten Tool: df: $ df $REALPATH Dateisystem 1K-Blöcke Verwendet Verfügbare Nutzung% Eingebunden auf /sda2 245115308 156692700 86157700 65 % /home/jpetazzo Verwenden Sie das Flag -P (um das POSIX-Format zu erzwingen, falls Sie ein exotisches df haben oder das df einer anderen Person, wenn Sie Docker auf Solaris oder BSD installieren) und fügen Sie das Ergebnis ebenfalls in eine Variable ein: $ FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}') Suchen Sie das Gerät (und das Unterverzeichnis) des Dateisystems Jetzt gibt es keine Bind-Mounts oder BTRFS-Subvolumes auf dem System, wir müssen nur in /proc/mounts nachsehen und das Gerät finden, das dem Dateisystem /home/jpetazzo entspricht. Aber in meinem System ist /home/jpetazzo ein Subvolume des BTRFS-Pools. Um die Subvolume-Informationen (oder Bind-Mount-Informationen) zu erhalten, müssen Sie /proc/self/moutinfo überprüfen. Wenn Sie noch nie von Mountinfo gehört haben, sehen Sie sich die Kerneldokumentation für proc.txt an. Holen Sie sich zunächst die Geräteinformationen des Dateisystems: $ während des Lesens DEV MOUNT JUNK > mache [ $MOUNT = $FILESYS ] und breche ab > fertig </proc/mounts $ echo $DEV /dev/sda2 Als nächstes holen Sie sich die Subroot-Informationen (also den Pfad zum gemounteten Dateisystem): $ während ABC SUBROOT MOUNT JUNK gelesen wird > mache [ $MOUNT = $FILESYS ] und breche ab > fertig < /proc/self/mountinfo $ echo $SUBROOT /jpetazzo sehr gut. Jetzt wissen wir, dass wir $ SUBPATH=$(echo $REALPATH | sed s,^$FILESYS,,) Hinweis: Diese Methode funktioniert nur, wenn der Pfad kein "," enthält. Wenn Ihr Pfad ein „“, „“ enthält und Sie das Verzeichnis mit der Methode in diesem Artikel mounten möchten, lassen Sie es mich bitte wissen. (Um dieses Problem zu lösen, muss ich die Shell-Triade aufrufen: Jessie, Soulshake, Tianon?) Als letztes müssen Sie vor dem Betreten des Containers die Haupt- und Nebennummern des Blockgeräts ermitteln. Sie können stat verwenden: $ stat --format "%t %T" $DEV 8 2 Beachten Sie, dass diese beiden Zahlen im Hexadezimalformat vorliegen. Wir werden sie später im Binärformat benötigen. Dies kann folgendermaßen umgerechnet werden: $ DEVDEC=$(printf "%d %d" $(stat --format "0x%t 0x%T" $DEV)) Zusammenfassen Es gibt noch einen letzten Schritt. Aus einem mir unerklärlichen Grund aktualisieren manche Dateisysteme (einschließlich BTRFS) das Gerätefeld in /proc/mounts, nachdem sie mehrmalig gemountet wurden. Das heißt, wenn wir im Container ein temporäres Blockgerät namens /tmpblkdev erstellen und es zum Mounten unseres eigenen Dateisystems verwenden, wird das Dateisystem (auf dem Hostcomputer!) als /tmpblkdev und nicht als /dev/sda2 angezeigt. Dies mag harmlos klingen, führt in der Praxis jedoch dazu, dass nachfolgende Versuche, auf das Blockgerät des Dateisystems zuzugreifen, fehlschlagen. Kurz gesagt, wir möchten sicherstellen, dass sich die Blockgeräteknoten im Container am gleichen Pfad befinden wie auf dem Hostcomputer. Sie müssen Folgendes tun: $ docker-enter charlie --sh -c \ > "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC" Erstellen Sie einen temporären Einhängepunkt zum Einhängen des Dateisystems: $ docker-enter charlie --mkdir /tmpmnt $ docker-enter charlie --mount $DEV /tmpmnt Stellen Sie sicher, dass der Volume-Einhängepunkt vorhanden ist, und hängen Sie das Volume per Bind-Mount ein: $ docker-enter charlie --mkdir -p /src $ docker-enter charlie --mount -o bind /tmpmnt/$SUBROOT/$SUBPATH /src Löschen Sie den temporären Einhängepunkt: $ docker-enter charlie --umount /tmpmnt $ docker-enter charlie --rmdir /tmpmnt (Wir löschen den Geräteknoten nicht. Es wäre vielleicht überflüssig, zunächst zu prüfen, ob das Gerät überhaupt existiert, aber es ist schon kompliziert genug.) Mission erfüllt! Automatisieren Sie alles Der folgende Absatz kann direkt kopiert und eingefügt werden. #!/bin/sh setze -e CONTAINER=charlie HOSTPATH=/home/jpetazzo/Arbeit/DOCKER/docker CONTPATH=/src REALPATH=$(readlink --kanonisieren Sie $HOSTPATH) FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}') während gelesen DEV MOUNT JUNK mache [ $MOUNT = $FILESYS ] und breche ab fertig </proc/mounts [ $MOUNT = $FILESYS ] # Plausibilitätsprüfung! \während Sie ABC SUBROOT MOUNT JUNK lesen \do [ $MOUNT = $FILESYS ] && break \done < /proc/self/mountinfo [ $MOUNT = $FILESYS ] # Mount-Sanitätsprüfung! SUBPATH=$(echo $REALPATH | sed s,^$FILESYS,,) DEVDEC=$(printf "%d %d" $(stat --format "0x%t 0x%T" $DEV)) docker-enter $CONTAINER -- sh -c \ "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC" docker-enter $CONTAINER --mkdir /tmpmnt docker-enter $CONTAINER --mount $DEV /tmpmnt docker-enter $CONTAINER --mkdir -p $CONTPATH docker-enter $CONTAINER --mount -o bind /tmpmnt/$SUBROOT/$SUBPATH $CONTPATH docker-enter $CONTAINER --umount /tmpmnt docker-enter $CONTAINER --rmdir /tmpmnt Status und Einschränkungen Die obige Methode gilt nicht für Dateisysteme, die nicht auf Blockgeräten basieren. Sie funktioniert nur, wenn /proc/mounts den Blockgeräteknoten korrekt abrufen kann (wie oben erwähnt, ist dies nicht immer möglich). Außerdem habe ich dies nur in meiner eigenen Umgebung getestet, nicht in einer Cloud-Instanz oder so etwas, aber es würde mich interessieren, ob es dort auch zutrifft. Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird. Das könnte Sie auch interessieren:
|
<<: Detaillierte Erklärung des Cocoscreater-Prefabs
>>: Sequenzimplementierungsmethode basierend auf MySQL
In unserer täglichen Arbeit kommen wir oft mit Da...
mktemp Erstellen Sie auf sichere Weise temporäre ...
Verwenden Sie HTML, um eine dynamische Web-Uhr zu...
Wenn die Bildlaufleiste nach unten gezogen wird, ...
Das Docker-Paket ist bereits im Standard-Reposito...
Inhaltsverzeichnis 1. Kartesisches Produktphänome...
Pure js implementiert eine mit einem Klick bearbe...
1. Befehlseinführung Mit dem Befehl ln werden Lin...
MySQL-Version: MySQL Community Edition (GPL) ----...
Hinweis: Der grundlegende Verzeichnispfad für die...
Spiegelung ist auch eine der Kernkomponenten von ...
Ich persönlich denke, dass die dekomprimierte Ver...
Hier ist eine kurze Zusammenfassung der Installat...
Machen Sie sich keine Sorgen, wenn Sie das Wagenr...
1. Schreiben Sie das Dockerfile (1) Klicken Sie m...