Como usar variáveis ​​de ambiente na composição do docker

217

Eu gostaria de poder usar variáveis ​​env dentro do docker-compose.yml, com valores passados ​​no momento do docker-compose up. Este é o exemplo. Eu estou fazendo isso hoje com o comando básico docker run, que está envolvido em meu próprio script. Existe uma maneira de conseguir isso com a composição, sem esses invólucros de bash?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
fonte
2
Para opções diferentes ver: docs.docker.com/compose/environment-variables
Massood Khaari
2
Foi resolvido na última versão do compor, seu exemplo funcionará exatamente como está. consulte docs.docker.com/compose/compose-file/#variable-substitution sobre a substituição de variáveis.
Natbusa 31/10/16
1
Não se esqueça do docker-app (desde junho de 2018): stackoverflow.com/a/51007138/6309
VonC

Respostas:

93
  1. Crie um template.yml, qual é a sua docker-compose.ymlvariável de ambiente.
  2. Suponha que suas variáveis ​​de ambiente estejam em um arquivo 'env.sh'
  3. Coloque o trecho de código abaixo em um arquivo sh e execute-o.

fonte env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

Um novo arquivo docker-compose.yml será gerado com os valores corretos das variáveis ​​de ambiente.

Arquivo template.yml de amostra:

oracledb:
        image: ${ORACLE_DB_IMAGE}
        privileged: true
        cpuset: "0"
        ports:
                - "${ORACLE_DB_PORT}:${ORACLE_DB_PORT}"
        command: /bin/sh -c "chmod 777 /tmp/start; /tmp/start"
        container_name: ${ORACLE_DB_CONTAINER_NAME}

Arquivo env.sh de amostra:

#!/bin/bash 
export ORACLE_DB_IMAGE=<image-name> 
export ORACLE_DB_PORT=<port to be exposed> 
export ORACLE_DB_CONTAINER_NAME=ORACLE_DB_SERVER
Saurabh Kumar
fonte
@Meet Sinta-se à vontade para conferir minha resposta abaixo, em "Solução BASH", onde descrevo essa abordagem um pouco mais detalhadamente.
Modulitos
7
Ainda não há solução melhor no momento?
Lvthillo
13
por que você excluiria recursivamente um arquivo? (rm -rf docker-compose.yml)
moritzschaefer
@ lorenzvth7 Você pode conferir minha resposta abaixo, que eu acho que é um pouco mais completa: stackoverflow.com/a/33186458/1884158 #
modulitos
5
-1 esta solução só complica as coisas e deve ser atualizado de acordo com novas habilidades Docker-compor docs.docker.com/compose/environment-variables/...
Efrat Levitan
239

A solução DOCKER:

Parece que o docker-compose 1.5+ ativou a substituição de variáveis: https://github.com/docker/compose/releases

O último Docker Compose permite acessar variáveis ​​de ambiente do seu arquivo de composição. Assim, você pode originar suas variáveis ​​de ambiente e executar o Compose da seguinte maneira:

set -a
source .my-env
docker-compose up -d

Em seguida, você pode fazer referência às variáveis ​​no docker-compose.yml usando $ {VARIABLE}, da seguinte maneira:

db:
  image: "postgres:${POSTGRES_VERSION}"

E aqui estão mais informações dos documentos, obtidas aqui: https://docs.docker.com/compose/compose-file/#variable-substitution

Quando você executa o docker-compose com essa configuração, o Compose procura a variável de ambiente POSTGRES_VERSION no shell e substitui seu valor. Nesse exemplo, o Compose resolve a imagem para o postgres: 9.3 antes de executar a configuração.

Se uma variável de ambiente não estiver configurada, Redigir substituirá por uma sequência vazia. No exemplo acima, se POSTGRES_VERSION não estiver definido, o valor da opção de imagem será postgres :.

A sintaxe $ VARIABLE e $ {VARIABLE} são suportadas. Recursos estendidos no estilo de shell, como $ {VARIABLE-default} e $ {VARIABLE / foo / bar}, não são suportados.

Se você precisar colocar um cifrão literal em um valor de configuração, use um cifrão duplo ($$).

E acredito que esse recurso foi adicionado a esta solicitação de recebimento : https://github.com/docker/compose/pull/1765

A solução BASH:

Percebo que as pessoas têm problemas com o suporte a variáveis ​​de ambiente do Docker. Em vez de lidar com variáveis ​​de ambiente no Docker, vamos voltar ao básico, como o bash! Aqui está um método mais flexível usando um script bash e um .envarquivo.

Um arquivo .env de exemplo:

EXAMPLE_URL=http://example.com
# Note that the variable below is commented out and will not be used:
# EXAMPLE_URL=http://example2.com 
SECRET_KEY=ABDFWEDFSADFWWEFSFSDFM

# You can even define the compose file in an env variable like so:
COMPOSE_CONFIG=my-compose-file.yml
# You can define other compose files, and just comment them out
# when not needed:
# COMPOSE_CONFIG=another-compose-file.yml

em seguida, execute este script bash no mesmo diretório, que deve implantar tudo corretamente:

#!/bin/bash

docker rm -f `docker ps -aq -f name=myproject_*`
set -a
source .env
cat ${COMPOSE_CONFIG} | envsubst | docker-compose -f - -p "myproject" up -d

Basta referenciar suas variáveis ​​env no seu arquivo de composição com a sintaxe bash usual (ou seja, ${SECRET_KEY}para inserir a SECRET_KEYdo .envarquivo).

Observe que o arquivo COMPOSE_CONFIGé definido no meu .envarquivo e usado no meu script bash, mas você pode facilmente substituí {$COMPOSE_CONFIG}-lo pelo my-compose-file.ymlscript bash.

Observe também que eu rotulei essa implantação nomeando todos os meus contêineres com o prefixo "myproject". Você pode usar qualquer nome que desejar, mas ajuda a identificar seus contêineres, para que você possa referenciá-los facilmente mais tarde. Supondo que seus contêineres sejam sem estado, como deveriam ser, esse script removerá e reimplementará rapidamente seus contêineres de acordo com os parâmetros de arquivo .env e seu arquivo YAML de composição.

Atualização Como essa resposta parece bastante popular, escrevi uma postagem no blog que descreve meu fluxo de trabalho de implantação do Docker com mais profundidade: http://lukeswart.net/2016/03/lets-deploy-part-1/ Isso pode ser útil quando você adiciona mais complexidade em uma configuração de implantação, como configurações nginx, certificados LetsEncrypt e contêineres vinculados.

modulitos
fonte
2
Você pode simplesmente em grep foo file.textvez de cat file.text | grep foo. No meu caso eu tive que export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín 27/01
"Percebo que as pessoas têm problemas com o suporte a variáveis ​​de ambiente do Docker" - você tem algum detalhe ou link para um ticket?
tleyden 27/02
Desculpe, não registrei o problema específico que estava ocorrendo e, há muito tempo (~ 6 meses), não sei se ele ainda é relevante. Mas sim, alguns recursos no suporte a variáveis ​​de ambiente do Docker estavam com erros e foram relatados por vários usuários. Eu acredito que está muito melhor agora. Mas quando a configuração de implantação se torna significativamente complexa, eu preferiria modularizá-la usando o bash para manipular a lógica de configuração e o Docker Compose para a orquestração de contêiner.
Modulitos
8
PSA: Isso funciona apenas comdocker-compose up e não com docker-compose run.
Kriegslustig
5
Existe esta solução docs.docker.com/compose/compose-file/#envfile que eu uso onde você adiciona variáveis ​​de ambiente de um .envsub env_file. Em seguida, você pode fazer referência às variáveis ​​em docker-compose.ymlusando${VARIABLE}
musale
111

Parece que o docker-compose agora possui suporte nativo para variáveis ​​de ambiente padrão no arquivo .

tudo o que você precisa fazer é declarar suas variáveis ​​em um arquivo chamado .enve elas estarão disponíveis no docker-compose.yml.

Por exemplo, para .envarquivo com conteúdo:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Você pode acessar sua variável dentro docker-compose.ymlou encaminhá-la para o contêiner:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P
fonte
4
essa é a melhor solução!
Ladenkov Vladislav
4
Isso funcionou para mim também. Não sei por que, mas o nome do arquivo deve estar literalmente .env, por exemplo config.env, não funcionou para mim.
HBat 9/03/19
1
@HBat the "." significa um arquivo oculto - este é procedimento usual para arquivos de configuração locais
Jeremy Hajek
2
A melhor solução. e Podemos adicionar adereços / etc / environment e usá-los como um ambiente com o uso de .env. Isso será mais seguro.
Chinthaka Dinadasa 26/06/19
24

O seguinte é aplicável ao conjunto de encaixe 3.x Definir variáveis ​​de ambiente dentro do contêiner

método - 1 método reto

web:
  environment:
    - DEBUG=1
      POSTGRES_PASSWORD: 'postgres'
      POSTGRES_USER: 'postgres'

método - 2 O arquivo ".env"

Crie um arquivo .env no mesmo local que o docker-compose.yml

$ cat .env
TAG=v1.5
POSTGRES_PASSWORD: 'postgres'

e seu arquivo de composição será como

$ cat docker-compose.yml
version: '3'
services:
  web:
    image: "webapp:${TAG}"
    postgres_password: "${POSTGRES_PASSWORD}"

fonte

Gajendra D Ambi
fonte
2
Eu gostaria de ver um exemplo completo do método 1. Não consegui fazer isso funcionar, então acabei usando o arquivo .env (que funcionou bem).
BobHy 25/05/19
20

Ao usar variáveis ​​de ambiente para volumes, você precisa:

  1. crie o arquivo .env na mesma pasta que contém o docker-compose.yaml arquivo

  2. declarar variável no .envarquivo:

    HOSTNAME=your_hostname
    
  3. Mude $hostnamepara ${HOSTNAME}at docker-compose.yaml file

    proxy:
      hostname: ${HOSTNAME}
      volumes:
        - /mnt/data/logs/${HOSTNAME}:/logs
        - /mnt/data/${HOSTNAME}:/data
    

Claro que você pode fazer isso dinamicamente em cada compilação, como:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
fonte
9
Observe que, de acordo com os documentos:The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.
James Gentes
19

A melhor maneira é especificar variáveis ​​de ambiente fora do docker-compose.ymlarquivo. Você pode usarenv_file configuração e definir seu arquivo de ambiente na mesma linha. Em seguida, fazer uma composição do docker novamente deve recriar os contêineres com as novas variáveis ​​de ambiente.

Aqui está como meu docker-compose.yml se parece:

services:
  web:
    env_file: variables.env

Nota: o docker-compose espera que cada linha em um arquivo env esteja no VAR=VALformato. Evite usar exportdentro do .envarquivo. Além disso, o .envarquivo deve ser colocado na pasta em que o comando docker-compose é executado.

Jibu James
fonte
2
Melhor maneira de fato
Dany
NÃO. Ele não disponibilizará automaticamente as variáveis ​​de ambiente dentro do contêiner do docker. Você ainda precisa mencionar explicitamente esses itens na seção ambiente.
kta 04/06
6

Você não pode ... ainda. Mas essa é uma alternativa, pense como um gerador docker-composer.yml:

https://gist.github.com/Vad1mo/9ab63f28239515d4dafd

Basicamente, um script de shell que substituirá suas variáveis. Além disso, você pode usar a tarefa Grunt para criar seu arquivo de composição do Docker no final do processo de IC.

Thomas Decaux
fonte
4

Eu tenho um script bash simples que criei para isso, apenas significa executá-lo em seu arquivo antes de usar: https://github.com/antonosmond/subber

Basicamente, basta criar seu arquivo de composição usando chaves duplas para indicar variáveis ​​de ambiente, por exemplo:

app:
    build: "{{APP_PATH}}"
ports:
    - "{{APP_PORT_MAP}}"

Qualquer coisa entre chaves duplas será substituída pela variável de ambiente com o mesmo nome; portanto, se eu tivesse as seguintes variáveis ​​de ambiente definidas:

APP_PATH=~/my_app/build
APP_PORT_MAP=5000:5000

na execução subber docker-compose.ymldo arquivo resultante seria semelhante a:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"
Anton
fonte
2

Até onde eu sei, este é um trabalho em andamento. Eles querem fazer isso, mas ainda não foi lançado. Veja 1377 (o "novo" 495 mencionado por @Andy).

Acabei implementando a abordagem "generate .yml como parte do IC", como proposto por @Thomas.

raizes
fonte
1

adicionar env ao arquivo .env

Tal como

VERSION=1.0.0

salve-o em deploy.sh

INPUTFILE=docker-compose.yml
RESULT_NAME=docker-compose.product.yml
NAME=test

prepare() {
        local inFile=$(pwd)/$INPUTFILE
        local outFile=$(pwd)/$RESULT_NAME
        cp $inFile $outFile
        while read -r line; do
            OLD_IFS="$IFS"
            IFS="="
            pair=($line)
            IFS="$OLD_IFS"
               sed -i -e "s/\${${pair[0]}}/${pair[1]}/g" $outFile
            done <.env
     }
       
deploy() {
        docker stack deploy -c $outFile $NAME
}

        
prepare
deploy
    
foxundermon
fonte
1

Use o arquivo .env para definir valores dinâmicos no docker-compse.yml. Seja porta ou qualquer outro valor.

Exemplo de doca-composição:

testcore.web:
       image: xxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/testcore:latest
       volumes: 
            - c:/logs:c:/logs
       ports:
            - ${TEST_CORE_PORT}:80
       environment:
            - CONSUL_URL=http://${CONSUL_IP}:8500 
            - HOST=${HOST_ADDRESS}:${TEST_CORE_PORT}

Dentro do arquivo .env, você pode definir o valor dessas variáveis:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002
sorabzone
fonte
1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Use a versão 3.6:

version: "3.6"
services:
  one:
    image: "nginx:alpine"
    environment:
      foo: "bar"
      SOME_VAR:
      baz: "${OTHER_VAR}"
    labels:
      some-label: "$SOME_VAR"
  two:
    image: "nginx:alpine"
    environment:
      hello: "world"
      world: "${SOME_VAR}"
    labels:
      some-label: "$OTHER_VAR"

Eu consegui este link https://github.com/docker/cli/issues/939

user2851100
fonte
1

Desde 1.25.4, o docker-compose suporta a opção --env-fileque permite especificar um arquivo contendo variáveis.

O seu deve ficar assim:

hostname=my-host-name

E o comando:

docker-compose --env-file /path/to/my-env-file config
papillon
fonte