Come utilizzare le variabili di ambiente nella composizione docker


218

Vorrei essere in grado di utilizzare le variabili env all'interno di docker-compose.yml, con i valori passati al momento della docker-compose up. Questo è l'esempio Lo sto facendo oggi con il comando di base docker run, che è racchiuso nel mio script. C'è un modo per ottenerlo con compose, senza tali involucri bash?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data

2
Per le diverse opzioni, consultare: docs.docker.com/compose/environment-variables
Massood Khaari,

2
È stato risolto nell'ultima versione di compose, il tuo esempio funzionerà esattamente come è. controlla docs.docker.com/compose/compose-file/#variable-substitution per la sostituzione delle variabili.
natbusa,

1
Non dimenticare finestra mobile-app (dal giugno 2018): stackoverflow.com/a/51007138/6309
VonC

Risposte:


93
  1. Crea un template.yml, che è il tuo docker-compose.ymlcon la variabile di ambiente.
  2. Supponiamo che le variabili di ambiente siano in un file 'env.sh'
  3. Metti il ​​pezzo di codice qui sotto in un file sh ed eseguilo.

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

docker-compose.ymlVerrà generato un nuovo file con i valori corretti delle variabili di ambiente.

File template.yml di esempio:

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}

File di esempio env.sh:

#!/bin/bash 
export ORACLE_DB_IMAGE=<image-name> 
export ORACLE_DB_PORT=<port to be exposed> 
export ORACLE_DB_CONTAINER_NAME=ORACLE_DB_SERVER

@Meet Sentiti libero di dare un'occhiata alla mia risposta qui sotto, sotto "Soluzione BASH", dove descrivo questo approccio un po 'più a fondo.
Modulitos,

7
ancora nessuna soluzione migliore al momento?
lvthillo,

13
perché dovresti eliminare ricorsivamente un file? (rm -rf docker-compose.yml)
moritzschaefer,

@ lorenzvth7 È possibile controllare la mia risposta qui di seguito, che credo sia un po 'più approfondita: stackoverflow.com/a/33186458/1884158
modulitos

5
-1 questa soluzione complica solo le cose e dovrebbe essere aggiornata secondo le nuove abilità docker
Efrat Levitan

240

La soluzione DOCKER:

Sembra che docker-compose 1.5+ abbia abilitato la sostituzione delle variabili: https://github.com/docker/compose/releases

L'ultima Docker Compose ti consente di accedere alle variabili di ambiente dal tuo file di composizione. Quindi puoi generare le variabili di ambiente, quindi eseguire Compose in questo modo:

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

Quindi puoi fare riferimento alle variabili in docker-compose.yml usando $ {VARIABLE}, in questo modo:

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

Ed ecco ulteriori informazioni dai documenti, prese qui: https://docs.docker.com/compose/compose-file/#variable-substitution

Quando si esegue docker-compose con questa configurazione, Compose cerca la variabile d'ambiente POSTGRES_VERSION nella shell e ne sostituisce il valore. In questo esempio, Compose risolve l'immagine in postgres: 9.3 prima di eseguire la configurazione.

Se non viene impostata una variabile di ambiente, Componi sostituisce con una stringa vuota. Nell'esempio sopra, se POSTGRES_VERSION non è impostato, il valore per l'opzione image è postgres :.

Sono supportate la sintassi $ VARIABLE e $ {VARIABLE}. Le funzionalità estese in stile shell, come $ {VARIABLE-default} e $ {VARIABLE / foo / bar}, non sono supportate.

Se è necessario inserire un valore letterale in un valore di configurazione, utilizzare un doppio simbolo del dollaro ($$).

E credo che questa funzione sia stata aggiunta in questa richiesta pull: https://github.com/docker/compose/pull/1765

La soluzione BASH:

Ho notato che la gente ha problemi con il supporto delle variabili d'ambiente di Docker. Invece di gestire le variabili di ambiente in Docker, torniamo alle basi, come bash! Ecco un metodo più flessibile che utilizza uno script bash e un .envfile.

Un file .env di esempio:

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

quindi esegui questo script bash nella stessa directory, che dovrebbe distribuire tutto correttamente:

#!/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 fare riferimento alle variabili env nel file di composizione con la solita sintassi bash (cioè ${SECRET_KEY}per inserire il SECRET_KEYdal .envfile).

Nota che COMPOSE_CONFIGè definito nel mio .envfile e usato nel mio script bash, ma puoi semplicemente sostituirlo {$COMPOSE_CONFIG}con my-compose-file.ymlin nello script bash.

Nota anche che ho etichettato questa distribuzione nominando tutti i miei contenitori con il prefisso "myproject". Puoi usare qualsiasi nome tu voglia, ma aiuta a identificare i tuoi contenitori in modo da poterli facilmente consultare in seguito. Supponendo che i contenitori siano apolidi, come dovrebbero essere, questo script rimuoverà e ridistribuirà rapidamente i contenitori in base ai parametri del file .env e al file YAML di composizione.

Aggiornamento Poiché questa risposta sembra piuttosto popolare, ho scritto un post sul blog che descrive il mio flusso di lavoro di distribuzione Docker in modo più approfondito: http://lukeswart.net/2016/03/lets-deploy-part-1/ Questo potrebbe essere utile quando aggiungi maggiore complessità per una configurazione di distribuzione, come config nginx, LetsEncrypt certs e contenitori collegati.


2
Puoi semplicemente grep foo file.textinvece di cat file.text | grep foo. Nel mio caso ho dovuto export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín,

"Ho notato che la gente ha problemi con il supporto delle variabili d'ambiente di Docker" - hai qualche dettaglio o un link a un ticket?
tleyden,

Spiacenti, non ho registrato il problema specifico che stavo riscontrando ed è stato tanto tempo fa (~ 6 mesi), non so se sia ancora rilevante. Sì, alcune funzionalità del supporto delle variabili di ambiente Docker erano errate ed è stato segnalato da più utenti. Credo che ora sia molto meglio. Ma quando la configurazione di distribuzione diventa significativamente complessa, preferirei modularizzarla usando bash per gestire la logica di configurazione e Docker Compose per l'orchestrazione dei container.
Modulitos,

8
PSA: funziona solo condocker-compose up e non con docker-compose run.
Kriegslustig,

5
C'è questa soluzione docs.docker.com/compose/compose-file/#envfile che utilizzo quando aggiungi variabili d'ambiente da un .envsotto env_file. Quindi puoi fare riferimento alle variabili docker-compose.ymlnell'uso${VARIABLE}
musale

112

Sembra che docker-compose abbia ora il supporto nativo per le variabili di ambiente predefinite nel file .

tutto quello che devi fare è dichiarare le tue variabili in un file chiamato .enve saranno disponibili in docker-compose.yml.

Ad esempio, per .envfile con contenuti:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

È possibile accedere alla variabile all'interno docker-compose.ymlo inoltrarla nel contenitore:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}

4
questa è la soluzione migliore!
Ladenkov Vladislav,

4
Questo ha funzionato anche per me. Non so perché, ma il nome del file dovrebbe essere letteralmente .env, ad esempio config.envnon ha funzionato per me.
HBat

1
@HBat il "." indica un file nascosto - questa è la normale procedura per i file di configurazione locali
Jeremy Hajek,

2
La migliore soluzione. e potremmo aggiungere / etc / environment props e usarli come ambiente usando .env. Sarà più sicuro.
Chinthaka Dinadasa,

24

Quanto segue è applicabile per 3.x Docker-compose Imposta variabili di ambiente all'interno del contenitore

metodo - 1 metodo dritto

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

metodo - 2 Il file ".env"

Creare un file .env nella stessa posizione di docker-compose.yml

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

e il tuo file di composizione sarà simile

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

fonte


2
Mi piacerebbe vedere un esempio completo del metodo 1. Non riuscivo a farlo funzionare, quindi ho finito per usare il file .env (che ha funzionato bene).
Bob,

20

Quando si utilizzano le variabili di ambiente per i volumi è necessario:

  1. crea il file .env nella stessa cartella che contiene il docker-compose.yaml file

  2. dichiarare variabile nel .envfile:

    HOSTNAME=your_hostname
    
  3. Cambiare $hostnamea ${HOSTNAME}al docker-compose.yaml di file

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

Ovviamente puoi farlo in modo dinamico su ogni build come:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up

9
Nota, secondo i documenti: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

Il modo migliore è specificare le variabili di ambiente al di fuori del docker-compose.ymlfile. È possibile utilizzare le env_fileimpostazioni e definire il file di ambiente all'interno della stessa riga. Quindi eseguire nuovamente una composizione docker dovrebbe ricreare i contenitori con le nuove variabili di ambiente.

Ecco come appare il mio docker-compose.yml:

services:
  web:
    env_file: variables.env

Nota: docker-compose prevede che ogni riga in un file env sia nel VAR=VALformato. Evitare di utilizzare exportall'interno del .envfile. Inoltre, il .envfile deve essere collocato nella cartella in cui viene eseguito il comando docker-compose.


2
Il modo migliore in effetti
Dany il

NO. Non renderà automaticamente disponibili le variabili di ambiente all'interno del contenitore finestra mobile. Devi ancora menzionarli esplicitamente nella sezione ambiente.
kta,

6

Non puoi ... ancora. Ma questa è un'alternativa, pensa come un generatore docker-composer.yml:

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

Fondamentalmente uno script di shell che sostituirà le tue variabili. Inoltre, è possibile utilizzare l'attività Grunt per creare il file di composizione della finestra mobile alla fine del processo CI.


4

Ho un semplice script bash che ho creato per questo significa solo eseguirlo sul tuo file prima dell'uso: https://github.com/antonosmond/subber

Fondamentalmente basta creare il tuo file di composizione usando doppie parentesi graffe per indicare le variabili di ambiente, ad esempio:

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

Qualunque cosa tra parentesi graffe doppie verrà sostituita con la variabile di ambiente con lo stesso nome, quindi se avessi impostato le seguenti variabili di ambiente:

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

nell'esecuzione subber docker-compose.ymldel file risultante sarebbe simile a:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"

2

Per quanto ne so, questo è un work-in-progress. Vogliono farlo, ma non è ancora stato rilasciato. Vedi 1377 (il "nuovo" 495 menzionato da @Andy).

Ho finito per implementare l'approccio "generate .yml as part of CI" come proposto da @Thomas.


1

aggiungi env al file .env

Ad esempio

VERSION=1.0.0

quindi salvarlo in 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
    

1

Utilizzare il file .env per definire valori dinamici in docker-compse.yml. Sia esso porta o qualsiasi altro valore.

Composizione docker di esempio:

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}

All'interno del file .env è possibile definire il valore di queste variabili:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002

1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Usa la versione 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"

L'ho preso da questo link https://github.com/docker/cli/issues/939


1

Dalla 1.25.4, docker-compose supporta l'opzione --env-fileche consente di specificare un file contenente variabili.

Il tuo dovrebbe apparire così:

hostname=my-host-name

E il comando:

docker-compose --env-file /path/to/my-env-file config
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.