Uzyskaj wartość zmiennej środowiskowej w Dockerfile

254

Buduję pojemnik na aplikację rubinową. Konfiguracja mojej aplikacji jest zawarta w zmiennych środowiskowych (ładowanych do aplikacji za pomocą dotenv ).

Jedną z tych zmiennych konfiguracyjnych jest publiczny adres IP aplikacji, który jest wykorzystywany wewnętrznie do tworzenia łączy. Muszę dodać pozycję dnsmasq wskazującą ten adres ip na 127.0.0.1 wewnątrz kontenera, aby mógł pobrać linki aplikacji tak, jakby nie były w kontenerze.

Dlatego próbuję ustawić plik ENVDocker, który przekazałby zmienną środowiskową do kontenera.

Próbowałem kilku rzeczy.

ENV REQUEST_DOMAIN $REQUEST_DOMAIN
ENV REQUEST_DOMAIN `REQUEST_DOMAIN`

Wszystko jednak przekazuje ciąg „REQUEST_DOMAIN” zamiast wartości zmiennej środowiskowej. Czy istnieje sposób na przekazanie wartości zmiennych środowiskowych z komputera hosta do kontenera?

Damien MATHIEU
źródło

Odpowiedzi:

392

Powinieneś użyć tej ARGdyrektywy w Dockerfile, który jest przeznaczony do tego celu.

ARGInstrukcja definiuje zmienną, że użytkownicy mogą przechodzić w czasie kompilacji do konstruktora z poleceniem doker kompilacji przy użyciu --build-arg <varname>=<value>flagi.

Twój plik Docker będzie miał następującą linię:

ARG request_domain

lub jeśli wolisz wartość domyślną:

ARG request_domain=127.0.0.1

Teraz możesz odwoływać się do tej zmiennej w swoim pliku Docker:

ENV request_domain=$request_domain

wtedy zbudujesz swój kontener tak:

$ docker build --build-arg request_domain=mydomain Dockerfile


Uwaga 1: Twój obraz nie zbuduje się, jeśli odwoływałeś się ARGdo pliku Docker, ale go wykluczyłeś --build-arg.

Uwaga 2: Jeśli użytkownik określi argument kompilacji, który nie został zdefiniowany w pliku Docker, kompilacja wyświetli ostrzeżenie:

[Ostrzeżenie] Co najmniej jeden argument kompilacji [foo] nie został zużyty.

Daniel van Flymen
źródło
12
ARG jest dostępny od dokera v1.9.
Synesso,
czy jest to obsługiwane do zbudowania zdalnie na repozytorium dokerów?
James Lin
4
Your image will not build if you have referenced an ARG in your Dockerfile but excluded it in --build-argmylisz się. Możesz budować obraz z referencjami nawet bez --build-arg. Ponadto możesz ustawić wartość domyślną dla argumentu build.
ALex_hha
1
Jaki jest cel linii ENV? Dla mnie wystarczyło build-arg + ARG.
Phil
3
ARG definiuje zmienną, która będzie używana wewnątrz pliku dokowania w kolejnych poleceniach. ENV definiuje zmienną środowiskową, która jest przekazywana do kontenera.
herm
56

Możesz więc zrobić: cat Dockerfile | envsubst | docker build -t my-target -

Następnie miej plik Docker z czymś takim jak:

ENV MY_ENV_VAR $MY_ENV_VAR

Myślę, że może być problem z niektórymi postaciami specjalnymi, ale działa to przynajmniej w większości przypadków.

jonasfj
źródło
13
Nie działa to, jeśli musisz DODAĆ pliki z katalogu zawierającego plik Docker.
Tom Hennen
2
Bardzo fajne rozwiązanie! Na komputerze Mac możesz uzyskać envsubstjako część brew install gettext. Ale z powodu możliwych konfliktów z systemem kompilacji BSD jest on „tylko do beczek” i nie są tworzone żadne symlnki. Można jednak bezpiecznie ln -s /usr/local/Cellar/gettext/*/bin/envsubst /usr/local/bin/dodać to jedno polecenie do ŚCIEŻKI. (Naprawdę chodzi o lib.) Lub możesz użyć go w jego /usr/local/Cellar/gettext/*/bin/envsubstlokalizacji
Bruno Bronosky,
1
Aby wyjaśnić komentarz @ TomHennen, potokowanie pliku Docker do docker build -jest w szczególności tym, co nie działa, gdy odwołujesz się do ścieżek względnych z pliku Dockerfile, niezależnie od podstawienia zmiennej env.
superEb
4
Re @ komentarzu TomHennen za, jeśli nie chcesz używać polecenia kontekstowe zależne takie jak kopiowanie w Dockerfile zawsze można przekierować wyjście envsubst do tymczasowego pliku, a następnie karmić, że w docker buildzamian. Przykład: cat Dockerfile | envsubst > DockerfileWithEnvVarsa docker build -t my-target -f DockerfileWithEnvVars .następnierm DockerfileWithEnvVars
snark
Lub możesz użyć gąbki z pakietu envsubst < Dockerfile | sponge Dockerfile
moreutils
19

Alternatywnym zastosowaniem envsubstbez utraty możliwości używania poleceń takich jak COPYlub ADDi bez użycia plików pośrednich byłoby użycie Zastąpienia Procesu Basha :

docker build -f <(envsubst < Dockerfile) -t my-target .
L. Alberto Giménez
źródło
3
niestety to nie działa (Docker 17.09), unable to prepare context: the Dockerfile (/dev/fd/63) must be within the build context
pojawia się
11

Załaduj zmienne środowiskowe z pliku utworzonego w czasie wykonywania.

export MYVAR="my_var_outside"
cat > build/env.sh <<EOF
MYVAR=${MYVAR}
EOF

... następnie w Dockerfile

ADD build /build
RUN /build/test.sh

gdzie test.sh ładuje MYVAR z env.sh

#!/bin/bash
. /build/env.sh
echo $MYVAR > /tmp/testfile
Dan C.
źródło
4

Jeśli chcesz tylko znaleźć i zastąpić wszystkie zmienne środowiskowe ($ ExampleEnvVar) w pliku Docker, skompiluj go, to zadziała:

envsubst < /path/to/Dockerfile | docker build -t myDockerImage . -f -

snassr
źródło
Najlepsza odpowiedź tutaj i na tej podstawie była w stanie zrobić: envsubst < ./Dockerfile | docker build -squash -t ${DOCKIMG}:${VERSION} . -f -gdzie FROMlinia używa zmiennej środowiskowej.
mikequentel
-6

dodaj -eklucz do przekazywania zmiennych środowiskowych do kontenera. przykład:

$ MYSQLHOSTIP=$(sudo docker inspect -format="{{ .NetworkSettings.IPAddress }}" $MYSQL_CONRAINER_ID)
$ sudo docker run -e DBIP=$MYSQLHOSTIP -i -t myimage /bin/bash

root@87f235949a13:/# echo $DBIP
172.17.0.2
Valentin Kantor
źródło
6
Damien chce zbudować obraz. -e zamiast tego działa z poleceniem uruchomienia.
Andres Restrepo,