Comment utiliser les variables d'environnement dans Docker Composer

218

Je voudrais pouvoir utiliser des variables env dans docker-compose.yml, avec des valeurs passées au moment de docker-compose up. Voici l'exemple. Je le fais aujourd'hui avec la commande de base docker run, qui est enroulée autour de mon propre script. Existe-t-il un moyen de le réaliser avec compose, sans de tels wrappers bash?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
la source
2
Pour différentes options, voir: docs.docker.com/compose/environment-variables
Massood Khaari
2
C'est résolu dans la dernière version de compose, votre exemple fonctionnera tel quel. consultez docs.docker.com/compose/compose-file/#variable-substitution sur la substitution de variables.
natbusa
1
N'oubliez pas l'application docker (depuis juin 2018): stackoverflow.com/a/51007138/6309
VonC

Réponses:

93
  1. Créez un template.yml, qui est votre docker-compose.ymlvariable d'environnement.
  2. Supposons que vos variables d'environnement se trouvent dans un fichier 'env.sh'
  3. Mettez le morceau de code ci-dessous dans un fichier sh et exécutez-le.

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

Un nouveau fichier docker-compose.ymlsera généré avec les valeurs correctes des variables d'environnement.

Exemple de fichier template.yml:

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}

Exemple de fichier 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
Saurabh Kumar
la source
@Meet N'hésitez pas à consulter ma réponse ci-dessous, sous "Solution BASH", où je décris cette approche un peu plus en détail.
modulitos
7
toujours pas de meilleure solution pour le moment?
lvthillo du
13
pourquoi voudriez-vous supprimer récursivement un fichier? (rm -rf docker-compose.yml)
moritzschaefer
@ lorenzvth7 Vous pouvez consulter ma réponse ci-dessous, qui je pense est un peu plus approfondie: stackoverflow.com/a/33186458/1884158
modulitos
5
-1 cette solution ne fait que compliquer les choses et devrait être mise à jour en fonction des nouvelles capacités de docker-compose docs.docker.com/compose/environment-variables/…
Efrat Levitan
240

La solution DOCKER:

Il semble que docker-compose 1.5+ ait activé la substitution de variables: https://github.com/docker/compose/releases

Le dernier Docker Compose vous permet d'accéder aux variables d'environnement à partir de votre fichier de composition. Vous pouvez donc source vos variables d'environnement, puis exécutez Compose comme suit:

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

Ensuite, vous pouvez référencer les variables dans docker-compose.yml en utilisant $ {VARIABLE}, comme ceci:

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

Et voici plus d'informations sur les documents, prises ici: https://docs.docker.com/compose/compose-file/#variable-substitution

Lorsque vous exécutez docker-compose avec cette configuration, Compose recherche la variable d'environnement POSTGRES_VERSION dans le shell et remplace sa valeur par. Pour cet exemple, Compose résout l'image en postgres: 9.3 avant d'exécuter la configuration.

Si aucune variable d'environnement n'est définie, Compose se substitue avec une chaîne vide. Dans l'exemple ci-dessus, si POSTGRES_VERSION n'est pas défini, la valeur de l'option image est postgres :.

La syntaxe $ VARIABLE et $ {VARIABLE} est prise en charge. Les fonctionnalités étendues de style shell, telles que $ {VARIABLE-default} et $ {VARIABLE / foo / bar}, ne sont pas prises en charge.

Si vous devez mettre un signe dollar littéral dans une valeur de configuration, utilisez un signe dollar double ($$).

Et je crois que cette fonctionnalité a été ajoutée dans cette demande de tirage: https://github.com/docker/compose/pull/1765

La solution BASH:

Je remarque que les gens ont des problèmes avec le support des variables d'environnement de Docker. Au lieu de traiter des variables d'environnement dans Docker, revenons aux bases, comme bash! Voici une méthode plus flexible utilisant un script bash et un .envfichier.

Un exemple de fichier .env:

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

puis exécutez ce script bash dans le même répertoire, qui devrait tout déployer correctement:

#!/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

Il vous suffit de référencer vos variables env dans votre fichier de composition avec la syntaxe bash habituelle (c'est- ${SECRET_KEY}à- dire pour l'insérer à SECRET_KEYpartir du .envfichier).

Notez que le COMPOSE_CONFIGest défini dans mon .envfichier et utilisé dans mon script bash, mais vous pouvez facilement le remplacer {$COMPOSE_CONFIG}par le my-compose-file.ymldans le script bash.

Notez également que j'ai étiqueté ce déploiement en nommant tous mes conteneurs avec le préfixe "myproject". Vous pouvez utiliser le nom de votre choix, mais cela permet d'identifier vos conteneurs afin que vous puissiez facilement les référencer plus tard. En supposant que vos conteneurs sont sans état, comme ils devraient l'être, ce script supprimera et redéploiera rapidement vos conteneurs en fonction de vos paramètres de fichier .env et de votre fichier YAML de composition.

Mise à jour Comme cette réponse semble assez populaire, j'ai écrit un article de blog qui décrit mon flux de travail de déploiement Docker de manière plus approfondie: http://lukeswart.net/2016/03/lets-deploy-part-1/ Cela peut être utile lorsque vous ajoutez plus de complexité à une configuration de déploiement, comme les configurations nginx, les certificats LetsEncrypt et les conteneurs liés.

modulitos
la source
2
Vous pouvez simplement grep foo file.textau lieu de cat file.text | grep foo. Dans mon cas, je devais le faire export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín
"Je remarque que les gens ont des problèmes avec le support des variables d'environnement de Docker" - avez-vous des détails ou un lien vers un ticket?
tleyden
Désolé, je n'ai pas enregistré le problème spécifique que je rencontrais, et il y a si longtemps (~ 6 mois), je ne sais pas s'il est toujours d'actualité. Mais oui, certaines fonctionnalités de la prise en charge des variables d'environnement Docker étaient boguées, et cela a été signalé par plusieurs utilisateurs. Je pense que c'est beaucoup mieux maintenant. Mais lorsque la configuration de déploiement devient considérablement complexe, je préférerais la modulariser en utilisant bash pour gérer la logique de configuration et Docker Compose pour l'orchestration des conteneurs.
modulitos
8
PSA: Cela ne fonctionne qu'avecdocker-compose up et pas avec docker-compose run.
Kriegslustig
5
Il existe cette solution docs.docker.com/compose/compose-file/#envfile que j'utilise lorsque vous ajoutez des variables d'environnement à partir d'un .envsous env_file. Ensuite, vous pouvez référencer les variables en docker-compose.ymlutilisant${VARIABLE}
musale
112

Il semble que docker-compose dispose désormais d'un support natif pour les variables d'environnement par défaut dans le fichier .

il vous suffit de déclarer vos variables dans un fichier nommé .envet elles seront disponibles dans docker-compose.yml.

Par exemple, pour un .envfichier avec contenu:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Vous pouvez accéder à votre variable à l'intérieur docker-compose.ymlou les transférer dans le conteneur:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P
la source
4
C'est la meilleure solution!
Ladenkov Vladislav
4
Cela a également fonctionné pour moi. Je ne sais pas pourquoi mais le nom du fichier devrait être littéralement .env, par exemple config.envn'a pas fonctionné pour moi.
HBAT
1
@HBat le "." signifie un fichier caché - c'est la procédure habituelle pour les fichiers de configuration locaux
Jeremy Hajek
2
La meilleure solution. et nous pourrions ajouter des accessoires / etc / environment et les utiliser comme environnement en utilisant .env. Ce sera plus sûr.
Chinthaka Dinadasa
24

Ce qui suit s'applique à docker-compose 3.x Définir les variables d'environnement à l'intérieur du conteneur

méthode - 1 méthode droite

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

méthode - 2 Le fichier «.env»

Créez un fichier .env au même emplacement que le docker-compose.yml

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

et votre fichier de composition sera comme

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

la source

Gajendra D Ambi
la source
2
Je voudrais voir un exemple complet de la méthode 1. Je ne pouvais pas faire cela, donc j'ai fini par utiliser le fichier .env (qui fonctionnait bien).
BobHy
20

Lorsque vous utilisez des variables d'environnement pour des volumes, vous avez besoin:

  1. créer un fichier .env dans le même dossier qui contient le docker-compose.yaml fichier

  2. déclarer une variable dans le .envfichier:

    HOSTNAME=your_hostname
    
  3. Changer $hostnamed' ${HOSTNAME}au docker-compose.yaml fichier

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

Bien sûr, vous pouvez le faire dynamiquement sur chaque build comme:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
la source
9
Remarque, selon les documents: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

La meilleure façon est de spécifier des variables d'environnement en dehors du docker-compose.ymlfichier. Vous pouvez utiliser le env_fileparamètre et définir votre fichier d'environnement sur la même ligne. Ensuite, faire à nouveau un docker-compose devrait recréer les conteneurs avec les nouvelles variables d'environnement.

Voici à quoi ressemble mon docker-compose.yml:

services:
  web:
    env_file: variables.env

Remarque: docker-compose attend que chaque ligne d'un fichier env soit au VAR=VALformat. Évitez d'utiliser exportà l'intérieur du .envfichier. En outre, le .envfichier doit être placé dans le dossier où la commande docker-compose est exécutée.

Jibu James
la source
2
La meilleure façon en effet
Dany
NON. Il ne rendra pas automatiquement les variables d'environnement disponibles dans le conteneur Docker. Vous devez toujours les mentionner explicitement dans la section environnement.
kta
6

Vous ne pouvez pas ... encore. Mais c'est une alternative, pensez comme un générateur docker-composer.yml:

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

Fondamentalement, un script shell qui remplacera vos variables. Vous pouvez également utiliser la tâche Grunt pour créer votre fichier de composition Docker à la fin de votre processus CI.

Thomas Decaux
la source
4

J'ai un script bash simple que j'ai créé pour cela, cela signifie simplement l'exécuter sur votre fichier avant utilisation: https://github.com/antonosmond/subber

Fondamentalement, créez simplement votre fichier de composition en utilisant des accolades doubles pour désigner les variables d'environnement, par exemple:

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

Tout élément en double accolade sera remplacé par la variable d'environnement du même nom, donc si j'avais les variables d'environnement suivantes définies:

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

lors de l'exécution subber docker-compose.ymldu fichier résultant ressemblerait à:

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

À ma connaissance, il s'agit d'un travail en cours. Ils veulent le faire, mais ce n'est pas encore sorti. Voir 1377 (le "nouveau" 495 mentionné par @Andy).

J'ai fini par implémenter l'approche "générer .yml dans le cadre de CI" comme proposé par @Thomas.

anroots
la source
1

ajouter env au fichier .env

Tel que

VERSION=1.0.0

puis enregistrez-le dans 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
la source
1

Utilisez le fichier .env pour définir des valeurs dynamiques dans docker-compse.yml. Que ce soit le port ou toute autre valeur.

Exemple de composition de docker:

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}

Dans le fichier .env, vous pouvez définir la valeur de ces variables:

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

Utilisez la version 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"

Je l'ai obtenu à partir de ce lien https://github.com/docker/cli/issues/939

user2851100
la source
1

Depuis 1.25.4, docker-compose prend en charge l'option --env-filequi vous permet de spécifier un fichier contenant des variables.

Le vôtre devrait ressembler à ceci:

hostname=my-host-name

Et la commande:

docker-compose --env-file /path/to/my-env-file config
papillon
la source