Dockerfile: Festlegen mehrerer Umgebungsvariablen in einer Zeile

75

Ich hatte den Eindruck, dass Umgebungsvariablen wie folgt in einer einzelnen Zeile festgelegt werden können, um Zwischenbilder zu minimieren.

FROM alpine:3.6
ENV RUBY_MAJOR 2.4 \
    RUBY_VERSION 2.4.1 \
    RUBY_DOWNLOAD_SHA256 4fc8a9992de3e90191de369270ea4b6c1b171b7941743614cc50822ddc1fe654 \
    RUBYGEMS_VERSION 2.6.12 \
    BUNDLER_VERSION 1.15.3

Wenn # set |grep RUich jedoch einen Container basierend auf diesem Snippet ausführe und aufrufe, sehe ich, dass die Variablen nicht separat zugewiesen werden, sondern zu einer einzigen Zeichenfolge zusammengefasst werden.

RUBY_MAJOR='2.4     RUBY_VERSION 2.4.1     RUBY_DOWNLOAD_SHA256 4fc8a9992de3e90191de369270ea4b6c1b171b7941743614cc50822ddc1fe654     RUBYGEMS_VERSION 2.6.12     BUNDLER_VERSION 1.15.3'

Wenn ich jedoch jede Variable explizit wie folgt einstelle, erhalte ich die erwartete Ausgabe und es gibt keine Fehler beim Aufrufen der Variablen.

ENV RUBY_MAJOR 2.4
ENV RUBY_VERSION 2.4.1
ENV RUBY_DOWNLOAD_SHA256 4fc8a9992de3e90191de369270ea4b6c1b171b7941743614cc50822ddc1fe654
ENV RUBYGEMS_VERSION 2.6.12
ENV BUNDLER_VERSION 1.15.3

Frage: Ist es möglich, die Einstellung von Umgebungsvariablen in einer einzigen Zeile zu kombinieren? Wenn ja, wie würde ich das machen? Und ist es eine gute Praxis?

Brian Wilson
quelle

Antworten:

132

Es gibt zwei Formate zum Festlegen von Umgebungen. Wenn Sie eine einzelne Variable benötigen, haben Sie das folgende Format

ENV X Y

Dadurch wird X als zugewiesen Y

ENX X Y Z

Dadurch wird X als zugewiesen Y Z

Wenn Sie mehrere Umgebungsvariablen zuweisen müssen, verwenden Sie das andere Format

ENV X=Y Z=A

Dadurch werden X als Yund Z als zugewiesen A. So Dockerfilesolltest du sein

FROM alpine:3.6
ENV RUBY_MAJOR=2.4 \
    RUBY_VERSION=2.4.1 \
    RUBY_DOWNLOAD_SHA256=4fc8a9992de3e90191de369270ea4b6c1b171b7941743614cc50822ddc1fe654 \
    RUBYGEMS_VERSION=2.6.12 \
    BUNDLER_VERSION=1.15.3

RUN env
Tarun Lalwani
quelle
Sie können dies auch mit Anführungszeichen und mit der Erweiterung vorhandener Umgebungsvariablen kombinieren. Zum Beispiel ist es üblich, den Pfad als Teil einer Reihe von Umgebungsvariablen zu erweitern:ENV PATH="$PATH:/app" \ APPVAR="foo"
JeremyDouglass
4
Seltsamerweise habe ich versucht, die erste Var in der zweiten Var zu verwenden, und sie wurde einfach in eine leere Zeichenfolge aufgelöst, egal ob es sich um eine einzeilige oder mehrzeilige handelt
Milosmns
@milosmns Ja, ich habe dieses Verhalten auch bemerkt
Kiran Challa
1
Das würde Argumente erfordern
Tarun Lalwani
2
@milosmns @ kiran-challa Um Taruns Kommentar zu erläutern, wird jede Variable, die für einen bestimmten ENVBefehl deklariert wurde , erst nach Abschluss des Befehls festgelegt, sodass das Verhalten wie erwartet ist (versuchen Sie es echo $V_NOT_SETmit einem * nix-basierten System). Geben Sie Build-Argumente ein. Als Randnotiz export V_NOT_SET="hello" echo $V_NOT_SETwird auch nur Leerzeichen ergeben; Hinzufügen eines exportVorher hilft nicht; Das Einfügen &&(aka AND_IF) zwischen exportund echowird zu helloeinem Echo führen, da jetzt der erste Befehl abgeschlossen sein muss, bevor der zweite ausgewertet wird.
hlongmore
19

Sie müssen sich nicht um viele ENVBefehle kümmern , die jeweils eine neue Zwischenebene für Ihr endgültiges Image erstellen, das von Ihrer Docker-Datei erstellt wurde.

aus Best Practices zum Schreiben von Dockerfiles

Minimieren Sie die Anzahl der Ebenen

Vor Docker 17.05 und noch mehr vor Docker 1.10 war es wichtig, die Anzahl der Ebenen in Ihrem Bild zu minimieren. Die folgenden Verbesserungen haben diesen Bedarf gemindert:

  • In Docker 1.10 und höher, nur RUN, COPYund ADDAnweisungen erstellen Schichten. Andere Anweisungen erstellen temporäre Zwischenbilder und erhöhen die Größe des Builds nicht mehr direkt.

  • Docker 17.05 und höher bietet Unterstützung für mehrstufige Builds , mit denen Sie nur die benötigten Artefakte in das endgültige Image kopieren können. Auf diese Weise können Sie Tools und Debug-Informationen in Ihre Zwischenerstellungsphasen einbeziehen, ohne das endgültige Image zu vergrößern.

Mike Lippert
quelle
Dies ist falsch gemäß: docs.docker.com/develop/develop-images/…
Tomanow
@Tomanow Es ist ein direktes Zitat aus den Docker-Dokumenten (siehe Link), aber ich denke, die Verwirrung ist, dass die von ENV erstellten Ebenen "temporär" sind, was meiner Meinung nach bedeutet, dass sie irgendwann in eine andere Ebene gequetscht werden, aber das ist nur eine Vermutung zur Umsetzung.
Mike Lippert
4
Bei meinen Tests mit Docker 19- ENVZeilen werden keine Ebenen im Bild erstellt. Wenn Sie das Bild erstellen, in dem "Zwischencontainer entfernen" steht, und anschließend die Ebenen mit einem Tauchgang untersuchen, kann ich feststellen, dass keine Ebenen für erstellt wurden ENV.
Stephen Paulger
3
Es ist zwar großartig, dass die ENV-Ebenen gequetscht werden, aber sie müssen erst noch erstellt werden, was auf meinem Laptop eine Weile dauern kann (ist das ungewöhnlich?). Ich denke, es ist besser, den mehrzeiligen Weg zu gehen, um zu sparen Bauzeit.
Chinoto Vokro
Was @ChinotoVokro gesagt hat ... Die Ebenen werden erstellt, die dann zerstört werden ... aber es ist trotzdem ein Schmerz.
Jonathan Alfaro