Dockerfile - defina ENV para o resultado do comando

93

É possível definir uma variável docker ENV para o resultado de um comando? Gostar:

ENV MY_VAR whoami

eu quero que MY_VAR obtenha o valor "root" ou o que quer que whoami retorne

Sultanen
fonte

Respostas:

21

Como um complemento à resposta DarkSideF.

Você deve estar ciente de que cada linha / comando no Dockerfile é executado em outro contêiner.

Você pode fazer algo assim:

RUN export bleah=$(hostname -f);echo $bleah;

Isso é executado em um único contêiner.

Dimitrie Mititelu
fonte
15
Só para esclarecer - não$bleah está disponível em nenhum lugar fora deste comando RUN, nem mesmo na próxima linha no mesmo dockerfile, muito menos em outra imagem em que se baseia. Recurso ausente realmente óbvio do docker aqui, parece que escrever e ler de um arquivo é a única maneira de realmente armazenar variáveis ​​(dinâmicas) em imagens e passá-las entre imagens, o que parece super hacky.
davnicwil,
17

Eu tive o mesmo problema e encontrei uma maneira de definir a variável de ambiente como resultado da função usando o comando RUN no dockerfile.

Por exemplo, eu preciso definir SECRET_KEY_BASE para o aplicativo Rails apenas uma vez, sem alterar como faria quando eu executo:

docker run  -e SECRET_KEY_BASE="$(openssl rand -hex 64)"

Em vez disso, escrevo na string do Dockerfile como:

RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'

e minha variável env disponível a partir do root, mesmo após o login do bash. ou talvez

RUN /bin/bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" > /etc/profile.d/docker_init.sh'

então ele variável disponível nos comandos CMD e ENTRYPOINT

O Docker armazena em cache como camada e muda apenas se você alterar algumas strings antes dele.

Você também pode tentar maneiras diferentes de definir a variável de ambiente.

DarkSideF
fonte
/Etc/profile.d/docker_init.sh ainda é uma coisa? Esta resposta é a única menção que posso encontrar com o Google, e não funciona para mim. Foi talvez parte de um mecanismo de execução do Docker em 2016 que não é mais atual?
SigmaX de
1
@SigmaX Não é uma coisa do docker, é mais uma coisa do Linux . Qualquer *.sharquivo dentro /etc/profile.d/é usado para
popular
7

Esta resposta é uma resposta a @DarkSideF ,

O método que ele está propondo é o seguinte, em Dockerfile:

RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'

( adicionando uma exportação no/etc/bash.bashrc )

É bom, mas a variável de ambiente só estará disponível para o processo /bin/bash, e se você tentar executar seu aplicativo docker, por exemplo, um aplicativo Node.js, /etc/bash.bashrcserá completamente ignorado e seu aplicativo não terá uma única pista do que SECRET_KEY_BASEestá ao tentar para acessar process.env.SECRET_KEY_BASE.

Essa é a razão pela qual ENVpalavra-chave é o que todos estão tentando usar com um comando dinâmico, porque toda vez que você executa seu contêiner ou usa um execcomando, o Docker verifica ENVe canaliza cada valor no processo executado atualmente (semelhante a -e).

Uma solução é usar um wrapper (crédito para @duglin neste problema do github ). Tenha um arquivo wrapper (por exemplo envwrapper) na raiz do projeto contendo:

#!/bin/bash
export SECRET_KEY_BASE="$(openssl rand -hex 64)"
export ANOTHER_ENV "hello world"
$*

e então em seu Dockerfile:

...
COPY . .
RUN mv envwrapper /bin/.
RUN chmod 755 /bin/envwrapper
CMD envwrapper myapp
vdegenne
fonte
4

Além da resposta de @ DarkSideF, se quiser reutilizar o resultado de um comando anterior Dockerfile durante o processo de compilação , você pode usar a seguinte solução alternativa:

  1. execute um comando, armazene o resultado em um arquivo
  2. use a substituição de comando para obter o resultado anterior desse arquivo em outro comando

Por exemplo :

RUN echo "bla" > ./result
RUN echo $(cat ./result)

Para algo mais limpo, você também pode usar a seguinte essência, que fornece uma pequena CLI chamada envstore.py:

RUN envstore.py set MY_VAR bla
RUN echo $(envstore.py get MY_VAR)

Ou você pode usar a biblioteca python-dotenv que possui uma CLI semelhante.

sebpiq
fonte
2

Não tenho certeza se é isso que você estava procurando, mas para injetar ENV vars ou ARGS em seu .Dockerfile, esse padrão funciona.

em seu my_build.sh:

echo getting version of osbase image to build from
OSBASE=$(grep "osbase_version" .version | sed 's/^.*: //')

echo building docker
docker build -f \
--build-arg ARTIFACT_TAG=$OSBASE \
PATH_TO_MY.Dockerfile \
-t my_artifact_home_url/bucketname:$TAG .

para obter um ARG em seu .Dockerfile, o snippet pode ter a seguinte aparência:

FROM scratch
ARG ARTIFACT_TAG
FROM my_artifact_home_url/bucketname:${ARTIFACT_TAG}

como alternativa, para obter um ENV em seu .Dockerfile, o snippet pode ter a seguinte aparência:

FROM someimage:latest
ARG ARTIFACT_TAG
ENV ARTIFACT_TAG=${ARTIFACT_TAG}

a ideia é que você execute o script de shell e isso chama o .Dockerfile com os args passados ​​como opções na construção.

Kat
fonte