Obter valor da variável de ambiente no Dockerfile

254

Estou construindo um contêiner para um aplicativo ruby. A configuração do meu aplicativo está contida em variáveis ​​de ambiente (carregadas dentro do aplicativo com dotenv ).

Uma dessas variáveis ​​de configuração é o IP público do aplicativo, usado internamente para criar links. Eu preciso adicionar uma entrada dnsmasq apontando esse ip para 127.0.0.1 dentro do contêiner, para que ele possa buscar os links do aplicativo como se não estivesse em contêiner.

Portanto, estou tentando definir um ENVno meu Dockerfile que passaria uma variável de ambiente para o contêiner.

Eu tentei algumas coisas.

ENV REQUEST_DOMAIN $REQUEST_DOMAIN
ENV REQUEST_DOMAIN `REQUEST_DOMAIN`

Tudo passa a string "REQUEST_DOMAIN" em vez do valor da variável de ambiente. Existe uma maneira de passar valores de variáveis ​​de ambiente da máquina host para o contêiner?

Damien MATHIEU
fonte

Respostas:

392

Você deve usar a ARGdiretiva no seu Dockerfile, destinada a esse fim.

A ARGinstrução define uma variável que os usuários podem transmitir no momento da construção para o construtor com o comando docker build usando o --build-arg <varname>=<value>sinalizador

Portanto, seu Dockerfile terá esta linha:

ARG request_domain

ou se você preferir um valor padrão:

ARG request_domain=127.0.0.1

Agora você pode fazer referência a essa variável dentro do seu Dockerfile:

ENV request_domain=$request_domain

então você criará seu contêiner da seguinte forma:

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


Nota 1: Sua imagem não será ARGcriada se você tiver feito referência a um arquivo Docker, mas o tiver excluído --build-arg.

Nota 2: Se um usuário especificar um argumento de construção que não foi definido no Dockerfile, a construção emitirá um aviso:

[Aviso] Um ou mais argumentos de construção [foo] não foram consumidos.

Daniel van Flymen
fonte
12
O ARG está disponível no docker v1.9 em diante.
Synesso
isso é suportado para ser construído remotamente no repositório docker?
James Lin
4
Your image will not build if you have referenced an ARG in your Dockerfile but excluded it in --build-argvocê está errado. Você pode criar imagem com referências mesmo sem --build-arg. Além disso, você pode definir o valor padrão para o argumento de construção.
ALex_hha
1
Qual é o objetivo da linha ENV? Para mim --build-arg + ARG foi suficiente.
Phil
3
O ARG define uma variável a ser usada dentro do dockerfile nos comandos subseqüentes. O ENV define uma variável de ambiente que é passada para o contêiner.
Herm
56

Então você pode fazer: cat Dockerfile | envsubst | docker build -t my-target -

Em seguida, tenha um Dockerfile com algo como:

ENV MY_ENV_VAR $MY_ENV_VAR

Acho que pode haver um problema com alguns caracteres especiais, mas isso funciona para a maioria dos casos, pelo menos.

jonasfj
fonte
13
Isso não parece funcionar se você precisar adicionar arquivos do diretório que contém o Dockerfile.
Tom Hennen
2
Solução muito boa! Em um Mac, você pode obter envsubstcomo parte brew install gettext. Porém, devido a possíveis conflitos com o sistema de compilação do BSD, é "somente barril" e nenhum symlnks é feito. No entanto, é seguro ln -s /usr/local/Cellar/gettext/*/bin/envsubst /usr/local/bin/adicionar esse comando ao PATH. (É realmente as bibliotecas que são a preocupação.) Ou você pode usá-lo em sua /usr/local/Cellar/gettext/*/bin/envsubstlocalização
de Bruno Bronosky
1
Para esclarecer o comentário de @ TomHennen, canalizar o Dockerfile para docker build -, especificamente, o que não funciona quando você faz referência a caminhos relativos do Dockerfile, independentemente da substituição do env var.
superEb
4
Re @ comentário de TomHennen, se você não quiser usar comandos dependentes do contexto como cópia em seu Dockerfile você sempre pode redirecionar a saída de envsubst para um arquivo temporário e, em seguida, alimentar isso em docker buildseu lugar. Exemplo cat Dockerfile | envsubst > DockerfileWithEnvVarsdocker build -t my-target -f DockerfileWithEnvVars .rm DockerfileWithEnvVars
:,
Ou você pode usar esponja de pacote moreutilsenvsubst < Dockerfile | sponge Dockerfile
ALex_hha
19

Uma alternativa usando envsubstsem perder a capacidade de usar comandos como COPYou ADDe sem usar arquivos intermediários seria usar a Substituição de Processo do Bash :

docker build -f <(envsubst < Dockerfile) -t my-target .
L. Alberto Giménez
fonte
3
infelizmente isso parece não funcionar (Docker 17.09), recebo o erro #unable to prepare context: the Dockerfile (/dev/fd/63) must be within the build context
Alexander Klimetschek
11

Carregue variáveis ​​de ambiente de um arquivo criado em tempo de execução.

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

... então no Dockerfile

ADD build /build
RUN /build/test.sh

onde test.sh carrega MYVAR do env.sh

#!/bin/bash
. /build/env.sh
echo $MYVAR > /tmp/testfile
Dan C
fonte
4

Se você apenas deseja localizar e substituir todas as variáveis ​​de ambiente ($ ExampleEnvVar) em um Dockerfile, compilá-lo, isso funcionaria:

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

snassr
fonte
A melhor resposta aqui, e com base nisso, foi capaz de fazer: envsubst < ./Dockerfile | docker build -squash -t ${DOCKIMG}:${VERSION} . -f -onde a FROMlinha está usando a variável de ambiente.
mikequentel
-6

adicione -echave para passar variáveis ​​de ambiente para o contêiner. exemplo:

$ 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
fonte
6
Damien está olhando para construir uma imagem. -e trabalha com o comando run.
Andres Restrepo