Ursprüngliche Frage: Wie verwende ich die VOLUME-Anweisung in Dockerfile?
Die eigentliche Frage , die ich lösen will , ist - wie Host - Volumes in Docker - Container in Dockerfile während Build zu montieren, dh die mit docker run -v /export:/export
währender Fähigkeit docker build
.
Der Grund dafür ist für mich, dass ich beim Erstellen von Dingen in Docker nicht möchte, dass diese ( apt-get install
) Caches in einem einzigen Docker gesperrt sind, sondern dass sie freigegeben / wiederverwendet werden. Das ist der Hauptgrund, warum ich zu dieser Frage frage.
Neuestes Update:
Vor Docker v18.09 sollte die richtige Antwort folgende sein:
Es gibt eine Möglichkeit, ein Volume während eines Builds bereitzustellen, jedoch ohne Docker-Dateien.
Dies war jedoch eine schlecht formulierte, organisierte und unterstützte Antwort. Bei der Neuinstallation meines Docker-Inhalts bin ich auf folgenden Artikel gestoßen:
Dockerisieren Sie einen apt-cacher-ng-Dienst
https://docs.docker.com/engine/examples/apt-cacher-ng/
Das ist die Lösung des Dockers für diese / meine Frage, nicht direkt, sondern indirekt. Es ist die orthodoxe Art, wie Docker uns vorschlägt. Und ich gebe zu, es ist besser als das, was ich hier fragen wollte.
Ein anderer Weg ist die neu akzeptierte Antwort , z. B. das Buildkit in Version 18.09.
Wählen Sie, was zu Ihnen passt.
War: Es gab eine Lösung - Rocker, der nicht von Docker stammte, aber jetzt, da der Rocker eingestellt wird, setze ich die Antwort wieder auf "Nicht möglich" zurück.
Altes Update: Die Antwort lautet also "Nicht möglich". Ich kann es als Antwort akzeptieren, da ich weiß, dass das Problem unter https://github.com/docker/docker/issues/3156 ausführlich besprochen wurde . Ich kann verstehen, dass Portabilität für Docker-Entwickler von größter Bedeutung ist. Aber als Docker-Benutzer muss ich sagen, dass ich über diese fehlende Funktion sehr enttäuscht bin. Lassen Sie mich mein Argument mit einem Zitat aus der oben genannten Diskussion schließen: " Ich möchte Gentoo als Basis-Image verwenden, möchte aber definitiv nicht, dass sich> 1 GB Portage-Baumdaten in einer der Ebenen befinden, sobald das Image erstellt wurde. Sie könnte einige schöne, kompakte Container haben, wenn nicht der gigantische Portage-Baum während der Installation im Image erscheinen müsste."Ja, ich kann wget oder curl verwenden, um alles herunterzuladen, was ich brauche, aber die Tatsache, dass ich aufgrund einer Portabilitätsüberlegung jetzt gezwungen bin, jedes Mal, wenn ich ein Gentoo-Basis-Image erstelle,> 1 GB Portage-Baum herunterzuladen, ist weder effizient noch benutzerfreundlich Darüber hinaus befindet sich das Paket-Repository IMMER unter / usr / portage und ist daher unter Gentoo IMMER TRAGBAR. Auch hier respektiere ich die Entscheidung, aber bitte erlauben Sie mir, in der Zwischenzeit auch meine Enttäuschung auszudrücken. Danke.
Ursprüngliche Frage im Detail:
Von
Freigeben von Verzeichnissen über Volumes
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/
Es heißt, dass die Datenvolumenfunktion "seit Version 1 der Docker Remote-API verfügbar ist". Mein Docker ist von Version 1.2.0, aber ich habe festgestellt, dass das im obigen Artikel angegebene Beispiel nicht funktioniert:
# BUILD-USING: docker build -t data .
# RUN-USING: docker run -name DATA data
FROM busybox
VOLUME ["/var/volume1", "/var/volume2"]
CMD ["/usr/bin/true"]
Wie kann in Dockerfile Host-gemountete Volumes über den Befehl VOLUME ordnungsgemäß in Docker-Container eingebunden werden?
$ apt-cache policy lxc-docker
lxc-docker:
Installed: 1.2.0
Candidate: 1.2.0
Version table:
*** 1.2.0 0
500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
100 /var/lib/dpkg/status
$ cat Dockerfile
FROM debian:sid
VOLUME ["/export"]
RUN ls -l /export
CMD ls -l /export
$ docker build -t data .
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM debian:sid
---> 77e97a48ce6a
Step 1 : VOLUME ["/export"]
---> Using cache
---> 59b69b65a074
Step 2 : RUN ls -l /export
---> Running in df43c78d74be
total 0
---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
---> Running in 8e4916d3e390
---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551
$ docker run data
total 0
$ ls -l /export | wc
20 162 1131
$ docker -v
Docker version 1.2.0, build fa7b24f
VOLUME ~/host_dir ~/container_dir
. Die Diskussion ist ziemlich umfangreich, gibt es eine kurze Möglichkeit, um zusammenzufassen, was der Grund ist?Antworten:
Um zu antworten: "Warum funktioniert das nicht
VOLUME
?" Wenn SieVOLUME
in der Docker-Datei ein definieren , können Sie nur das Ziel definieren, nicht die Quelle des Volumes. Während des Builds erhalten Sie nur ein anonymes Volume. Dieses anonyme Volume wird bei jedemRUN
Befehl bereitgestellt, mit dem Inhalt des Abbilds vorab ausgefüllt und am Ende desRUN
Befehls verworfen . Es werden nur Änderungen am Container gespeichert, keine Änderungen am Volume.Seit diese Frage gestellt wurde, wurden einige Funktionen veröffentlicht, die möglicherweise hilfreich sind. Das erste sind mehrstufige Builds, mit denen Sie einen ineffizienten Speicherplatz in der ersten Stufe erstellen und nur die erforderliche Ausgabe in die letzte Stufe kopieren können, die Sie ausliefern. Und die zweite Funktion ist Buildkit, das die Art und Weise, wie Bilder erstellt werden, dramatisch verändert und dem Build neue Funktionen hinzufügt.
Bei einem mehrstufigen Build würden Sie mehrere
FROM
Zeilen haben, von denen jede die Erstellung eines separaten Bildes startet. Standardmäßig ist nur das letzte Bild markiert. Sie können jedoch Dateien aus früheren Phasen kopieren. Die Standardverwendung besteht darin, eine Compiler-Umgebung zum Erstellen eines binären oder anderen Anwendungsartefakts und eine Laufzeitumgebung als zweite Stufe zu haben, die über dieses Artefakt kopiert. Du könntest haben:Dies würde zu einem Build führen, der nur die resultierende Binärdatei und nicht das vollständige / export-Verzeichnis enthält.
Buildkit kommt am 18.09 aus dem Experiment heraus. Es handelt sich um eine vollständige Neugestaltung des Erstellungsprozesses, einschließlich der Möglichkeit, den Frontend-Parser zu ändern. Eine dieser Parser-Änderungen hat die
RUN --mount
Option implementiert, mit der Sie ein Cache-Verzeichnis für Ihre Ausführungsbefehle bereitstellen können. Beispiel: Hier ist eines, das einige der Debian-Verzeichnisse bereitstellt (mit einer Neukonfiguration des Debian-Images könnte dies die Neuinstallation von Paketen beschleunigen):Sie würden das Cache-Verzeichnis für jeden Anwendungs-Cache anpassen, z. B. $ HOME / .m2 für Maven oder /root/.cache für Golang.
TL; DR: Antwort ist hier: Damit
RUN --mount
Syntax können Sie auch schreibgeschützte Mount-Verzeichnisse aus dem Build-Kontext binden. Der Ordner muss im Build-Kontext vorhanden sein und darf nicht dem Host oder dem Build-Client zugeordnet werden:Beachten Sie, dass das Verzeichnis, da es über den Kontext bereitgestellt wird, auch schreibgeschützt bereitgestellt wird und Sie Änderungen nicht auf den Host oder Client zurückschieben können. Wenn Sie erstellen, möchten Sie eine 18.09 oder neuere Installation und aktivieren Sie das Buildkit mit
export DOCKER_BUILDKIT=1
.Wenn Sie die Fehlermeldung erhalten, dass das Mount-Flag nicht unterstützt wird, bedeutet dies, dass Sie entweder das Buildkit mit der obigen Variablen nicht aktiviert haben oder dass Sie die experimentelle Syntax mit der Syntaxzeile oben in der Docker-Datei zuvor nicht aktiviert haben alle anderen Zeilen, einschließlich Kommentare. Beachten Sie, dass die Variable zum Umschalten des Buildkits nur funktioniert, wenn in Ihrer Docker-Installation Buildkit-Unterstützung integriert ist, für die Docker Version 18.09 oder höher sowohl auf dem Client als auch auf dem Server erforderlich ist.
quelle
Es ist nicht möglich, die
VOLUME
Anweisung zu verwenden, um Docker mitzuteilen, was gemountet werden soll. Das würde die Portabilität ernsthaft beeinträchtigen. Diese Anweisung teilt Docker mit, dass der Inhalt in diesen Verzeichnissen nicht in Bildern gespeichert ist und über den--volumes-from
Befehlszeilenparameter von anderen Containern aus aufgerufen werden kann. Sie müssen den Container mit ausführen,-v /path/on/host:/path/in/container
um vom Host aus auf Verzeichnisse zuzugreifen.Das Mounten von Host-Volumes während des Builds ist nicht möglich. Es gibt keinen privilegierten Build, und das Mounten des Hosts würde auch die Portabilität ernsthaft beeinträchtigen. Vielleicht möchten Sie versuchen, mit wget oder curl alles herunterzuladen, was Sie für den Build benötigen, und es zu installieren.
quelle
UPDATE: Jemand wird einfach kein Nein als Antwort nehmen, und ich mag es sehr, besonders auf diese spezielle Frage.
GUTE NACHRICHTEN, jetzt gibt es einen Weg -
Die Lösung ist Rocker: https://github.com/grammarly/rocker
John Yani sagte : "IMO, es löst alle Schwachstellen von Dockerfile und macht es für die Entwicklung geeignet."
Rocker
https://github.com/grammarly/rocker
Update: Rocker wurde gemäß dem offiziellen Projekt-Repo auf Github eingestellt
quelle
MOUNT ~/code/docker-app-dev/new-editor/:/src/
und mein Rocker-Build-Befehl lautet wie folgtrocker build -f Dockerfile .
: Was mache ich falsch?~
ist ein Bourne-Shell-Metazeichen.Rocker build
erlaubt keinedocker run
Befehlszeilenoptionen, erlaubt also derzeit keine Dinge wie--privileged
.Es gibt eine Möglichkeit, ein Volume während eines Builds bereitzustellen, jedoch ohne Docker-Dateien.
Die Technik besteht darin , einen Container aus einer beliebigen Basis zu erstellen, die Sie verwenden möchten (Mounten Ihrer Volumes in den Container mit der
-v
Option), ein Shell-Skript auszuführen, um Ihre Image- Erstellung durchzuführen , und dann den Container festzuschreiben als Image festzuschreiben, wenn Sie fertig sind .Dadurch werden nicht nur die überschüssigen Dateien weggelassen, die Sie nicht möchten (dies gilt auch für sichere Dateien wie SSH-Dateien), sondern es wird auch ein einzelnes Image erstellt. Es hat Nachteile: Der Befehl commit unterstützt nicht alle Dockerfile-Anweisungen und lässt Sie nicht abholen, wenn Sie aufgehört haben, wenn Sie Ihr Build-Skript bearbeiten müssen.
AKTUALISIEREN:
Beispielsweise,
quelle
debian:wheezy
und das Shell-Skript istbuild.sh
, welche spezifischen Anweisungen würde man verwenden?Während Sie den Container ausführen, wird ein Verzeichnis auf Ihrem Host erstellt und in den Container eingebunden. Sie können herausfinden, in welchem Verzeichnis sich dies befindet
Wenn Sie ein Verzeichnis von Ihrem Host in Ihrem Container bereitstellen möchten, müssen Sie den
-v
Parameter verwenden und das Verzeichnis angeben. In Ihrem Fall wäre dies:Sie würden also den Hosts-Ordner in Ihrem Container verwenden.
quelle
Ich denke, Sie können tun, was Sie wollen, indem Sie den Build über einen Docker-Befehl ausführen, der selbst in einem Docker-Container ausgeführt wird. Siehe Docker kann jetzt in Docker | ausgeführt werden Docker Blog . Eine Technik wie diese, die jedoch tatsächlich mit einem Container auf den äußeren Docker zugegriffen hat, wurde verwendet, z. B. während untersucht wurde, wie der kleinstmögliche Docker-Container erstellt werden kann Xebia Blog .
Ein weiterer relevanter Artikel ist Optimieren von Docker-Images | CenturyLink Labs erklärt, dass Sie, wenn Sie während eines Builds Inhalte herunterladen, vermeiden können, dass im endgültigen Image Speicherplatz verschwendet wird, indem Sie den Download in einem RUN-Schritt herunterladen, erstellen und löschen.
quelle
Es ist hässlich, aber ich habe einen Anschein davon erreicht:
Dockerfile:
imageBuild.sh:
Ich habe einen Java-Build, der das Universum in /root/.m2 herunterlädt, und das jedes Mal .
imageBuild.sh
Kopiert den Inhalt dieses Ordners nach dem Build auf den Host undDockerfile
kopiert ihn für den nächsten Build zurück in das Image.Dies ist ungefähr so, wie ein Volume funktionieren würde (dh es bleibt zwischen den Builds bestehen).
quelle
Hier ist eine vereinfachte Version des 2-Schritt-Ansatzes mit Build und Commit ohne Shell-Skripte. Es involviert:
Bei relativ geringen Änderungen verlängert der zusätzliche Schritt die Erstellungszeit nur um wenige Sekunden.
Grundsätzlich:
In meinem Anwendungsfall möchte ich eine maven toolchains.xml-Datei vorgenerieren, aber meine vielen JDK-Installationen befinden sich auf einem Volume, das erst zur Laufzeit verfügbar ist. Einige meiner Bilder sind nicht mit allen JDKS kompatibel, daher muss ich die Kompatibilität beim Erstellen testen und die Datei toolchains.xml unter bestimmten Bedingungen füllen. Beachten Sie, dass das Image nicht portabel sein muss. Ich veröffentliche es nicht in Docker Hub.
quelle
Wie viele bereits geantwortet haben, ist das Mounten von Host-Volumes während des Builds nicht möglich. Ich möchte nur einen
docker-compose
Weg hinzufügen , ich denke, es wird schön sein, vor allem für die Entwicklung / TestnutzungDockerfile
docker-compose.yml
Und lassen Sie Ihren Container vorbeifahren
docker-compose up -d --build
quelle