Bedingte ENV in Dockerfile

76

Ist es möglich, eine ENVVariable in einer Docker-Datei basierend auf dem Wert eines Builds bedingt festzulegen ARG?

Bsp.: So etwas wie

ARG BUILDVAR=sad
ENV SOMEVAR=if $BUILDVAR -eq "SO"; then echo "hello"; else echo "world"; fi

Update: aktuelle Nutzung basierend auf Marios Antwort:

ARG BUILD_ENV=prod
ENV NODE_ENV=production
RUN if [ "${BUILD_ENV}" = "test" ]; then export NODE_ENV=development; fi

Wenn --build-arg BUILD_ENV=testich jedoch mit dem Host renne und dann auf ihn gehe, bekomme ich immer noch

docker run -it mycontainer bin/bash
[root@brbqw1231 /]# echo $NODE_ENV
production
Matthew Herbst
quelle
1
Versuchen Sie es RUN if [ "$BUILD_ENV" = "test" ]; then export NODE_ENV=development; fi. Achten Sie auf die Leerzeichen. Entfernen Sie sie nicht
Alkis Kalogeris
@alkis schien nicht zu helfen, obwohl gute Fang =anstelle voneq
Matthew Herbst
Exportvariable während der Image-Erstellung wird nicht zur Laufzeit des Containers erweitert, sondern verwendenRUN if [ "${BUILD_ENV}" = "test" ] ;then echo BUILD_ENV=development >>/etc/environment ; fi
kyb

Antworten:

46

Ja, es ist möglich, aber Sie müssen Ihr Build-Argument als Flag verwenden. Sie können die Parametererweiterungsfunktion der Shell verwenden, um den Zustand zu überprüfen. Hier ist eine Proof-of-Concept-Docker-Datei:

FROM debian:stable
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set NODE_ENV to 'development' or set to null otherwise.
ENV NODE_ENV=${BUILD_DEVELOPMENT:+development}
# if NODE_ENV is null, set it to 'production' (or leave as is otherwise).
ENV NODE_ENV=${NODE_ENV:-production}

Test Build:

docker build --rm -t env_prod ./
...
docker run -it env_prod bash
root@2a2c93f80ad3:/# echo $NODE_ENV 
production
root@2a2c93f80ad3:/# exit
docker build --rm -t env_dev --build-arg BUILD_DEVELOPMENT=1 ./
...
docker run -it env_dev bash
root@2db6d7931f34:/# echo $NODE_ENV
development
Ruslan Kabalin
quelle
1
Dies scheint die beste Lösung zu sein, insbesondere wenn Sie etwas wie Nuxt.js / next.js erstellen, bei dem NODE_ENV zur Erstellungszeit und nicht zur Laufzeit festgelegt werden muss.
Nick Bolles
Nach etwas mehr Verwendung gibt es einige Einschränkungen bei ARG. Es wird nur für die nächste Stufe (Zeile in der Docker-Datei) verwendet, sodass Sie es mehrmals einfügen
Nick Bolles
1
@ Sup3rb0wlz Bei dieser Warnung handelt es sich um mehrstufige Builds, dh mehrere "FROM ..." - Zeilen. Wenn Sie diese nicht verwenden, wird das ARG in allen zukünftigen Zeilen der Docker-Datei fortgesetzt.
Arthur Tacca
1
Beachten Sie, dass Variablen in Dockerfiles nur eine begrenzte Teilmenge von Erweiterungstypen zulassen , nicht die gesamte Liste in diesem Link (für Bash, nicht für Docker). Grundsätzlich sind nur die beiden Typen + und + zulässig, die in dieser Antwort angezeigt werden.
Arthur Tacca
14

Sie können Bash-Code nicht direkt in der Docker-Datei ausführen , müssen jedoch den RUNBefehl verwenden. So zum Beispiel, können Sie ändern ENVmit RUNund exportieren Sie die Variable in der if, wie unten:

ARG BUILDVAR=sad 
RUN if [ "$BUILDVAR" == "SO" ]; \
    then export SOMEVAR=hello; \
    else export SOMEVAR=world; \
    fi 

Ich habe es nicht versucht, sollte aber funktionieren.

Mario Cairone
quelle
15
Beachten Sie, dass ein env var-Set mit RUN exportim resultierenden Bild nicht bestehen bleibt
Bastien Libersa
1
Die exportierte Variable @BastienLibersa bleibt auch außerhalb dieser RUN-Anweisung nicht erhalten, da sie als separate Ebene behandelt wird.
Ruslan Kabalin
1
@holms et al. - Denken Sie daran, dass Sie für Bilder, die auf einigen Linux-Distributionen basieren, z. B. Ubuntu, die Single =anstelle von verwenden müssen ==.
Jakub Kukul
3
Das funktioniert nichtStep 9/11 : RUN if [ "$version" = "show"]; then export runCMD=hello; else export runCMD=world; fi ---> Running in 160b291ca7e4 /bin/sh: 1: [: missing ]
Peter Weyand
1
@ PeterWeyand höchstwahrscheinlich ein fehlendes Leerzeichen vor der schließenden Klammer]
Andre Miras
4

Sie können zwar keine bedingten ENVVariablen festlegen , aber möglicherweise können Sie mit dem RUNBefehl und einer Null-Koaleszenz- Umgebungsvariablen das erreichen, wonach Sie suchen :

RUN node /var/app/current/index.js --env ${BUILD_ENV:-${NODE_ENV:-"development"}}
Steven de Salas
quelle
Ich mag das, aber es ist auf Bedingungen beschränkt, die außerhalb des Containers (zur Laufzeit) bestimmt werden können, weshalb ich es nicht als "die" Antwort akzeptieren werde. Ich denke, eine vollständige Lösung hierfür sollte in der Lage sein, innerhalb des Containers zu funktionieren (es sei denn, es kann gezeigt werden, dass dies nicht möglich ist). Vielen Dank für das Lernen bezüglich Null-Coalescing in Bash!
Matthew Herbst
3

Ihre Logik ist tatsächlich richtig. Das Problem hierbei ist, dass RUN export ...dies in einer Docker-Datei nicht funktioniert, da der exportBefehl nicht für alle Bilder bestehen bleibt. Docker-Dateien erstellen einen temporären Container, um das Image dafür zu generieren. Daher sind die Umgebungsvariablen nicht vorhanden.

ENVAuf der anderen Seite heißt es in der Dokumentation :

Die mit festgelegten Umgebungsvariablen ENVbleiben bestehen, wenn ein Container aus dem resultierenden Image ausgeführt wird.

Die einzige Möglichkeit, dies zu tun, besteht darin, während Ihres docker runBefehls den Container aus Ihrem Bild zu generieren und Ihre Logik darum zu wickeln:

if [ "${BUILD_ENV}" = "test" ]; then
    docker run -e NODE_ENV=development myimage
else
    docker run myimage
fi
Adel Helal
quelle
0

Übergeben von Werten an Dockerfile und dann an das Einstiegspunktskript

Übergeben Sie über die Befehlszeile Ihren gewünschten Wert (TARG).

docker run --env TARG=T1_WS01 -i projects/msbob

Dann Dockerfilesetzen Sie so etwas ein

Dockerfile:
# if $TARG is not set then "entrypoint" defaults to Q0_WS01
CMD ./entrypoint.sh ${TARG} Q0_WS01

Das entrypoint.shSkript liest nur das erste Argument

entrypoint.sh:
#!/bin/bash
[ $1 ] || { echo "usage: entrypoint.sh <$TARG>" ; exit ; }
target_env=$1
Roblogik
quelle
0

Wenn es sich nur um Umgebungsvariablen handelt, legen Sie diese einfach mit der Produktion fest

ENV NODE_ENV prod

Und während des Container-Starts in der Entwicklung können Sie verwenden -e NODE_ENV=dev.

Auf diese Weise wird das Image immer in die Produktion integriert, aber der lokale Container wird in der Entwicklung gestartet.

Sergey Romanov
quelle