Verwendung von Umgebungsvariablen in Docker Compose

217

Ich möchte in der Lage sein, env-Variablen in docker-compose.yml zu verwenden, wobei die Werte zum Zeitpunkt der Docker-Komposition übergeben werden. Dies ist das Beispiel. Ich mache dies heute mit dem grundlegenden Docker-Befehl run, der um mein eigenes Skript gewickelt ist. Gibt es eine Möglichkeit, dies mit Compose ohne solche Bash-Wrapper zu erreichen?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
quelle
2
Für verschiedene Optionen siehe: docs.docker.com/compose/environment-variables
Massood Khaari
2
Es wurde in der letzten Version von compose gelöst. Ihr Beispiel funktioniert so wie es ist. Überprüfen Sie docs.docker.com/compose/compose-file/#variable-substitution auf Variablensubstitution.
Natbusa
1
Vergessen Sie nicht die Docker-App (seit Juni 2018): stackoverflow.com/a/51007138/6309
VonC

Antworten:

93
  1. Erstellen Sie eine template.yml, die Ihre docker-compose.ymlmit Umgebungsvariable ist.
  2. Angenommen, Ihre Umgebungsvariablen befinden sich in einer Datei 'env.sh'.
  3. Fügen Sie den folgenden Code in eine sh-Datei ein und führen Sie ihn aus.

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

Eine neue Datei docker-compose.ymlwird mit den korrekten Werten der Umgebungsvariablen generiert.

Beispieldatei 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}

Beispieldatei 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
quelle
@Meet Fühlen Sie sich frei, meine Antwort unten unter "BASH-Lösung" zu lesen, wo ich diesen Ansatz etwas ausführlicher skizziere.
Modulitos
7
im moment noch keine bessere lösung?
lvthillo
13
Warum sollten Sie eine Datei rekursiv löschen? (rm -rf docker-compose.yml)
moritzschaefer
@ Lorenzvth7 Sie können meine Antwort unten überprüfen, die ich etwas gründlicher finde
Modulitos
5
-1 Diese Lösung macht die Sache nur komplizierter und sollte gemäß den neuen Fähigkeiten von Docker-Compose aktualisiert werden. Docs.docker.com/compose/environment-variables/…
Efrat Levitan
239

Die DOCKER-Lösung:

Es sieht so aus, als hätte Docker-Compose 1.5+ die Substitution von Variablen aktiviert: https://github.com/docker/compose/releases

Mit dem neuesten Docker Compose können Sie über Ihre Compose-Datei auf Umgebungsvariablen zugreifen. Sie können also Ihre Umgebungsvariablen als Quelle verwenden und dann Compose wie folgt ausführen:

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

Dann können Sie die Variablen in docker-compose.yml mit $ {VARIABLE} wie folgt referenzieren:

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

Weitere Informationen aus den Dokumenten finden Sie hier: https://docs.docker.com/compose/compose-file/#variable-substitution

Wenn Sie Docker-Compose mit dieser Konfiguration ausführen, sucht Compose in der Shell nach der Umgebungsvariablen POSTGRES_VERSION und ersetzt ihren Wert in. In diesem Beispiel löst Compose das Image in postgres: 9.3 auf, bevor die Konfiguration ausgeführt wird.

Wenn keine Umgebungsvariable festgelegt ist, wird Compose durch eine leere Zeichenfolge ersetzt. Wenn im obigen Beispiel POSTGRES_VERSION nicht festgelegt ist, lautet der Wert für die Bildoption postgres:.

Es wird sowohl die Syntax $ VARIABLE als auch $ {VARIABLE} unterstützt. Erweiterte Funktionen im Shell-Stil wie $ {VARIABLE-default} und $ {VARIABLE / foo / bar} werden nicht unterstützt.

Wenn Sie ein Konfigurationswert mit einem wörtlichen Dollarzeichen versehen müssen, verwenden Sie ein doppeltes Dollarzeichen ($$).

Und ich glaube, diese Funktion wurde in dieser Pull-Anfrage hinzugefügt: https://github.com/docker/compose/pull/1765

Die BASH-Lösung:

Ich stelle fest, dass Leute Probleme mit der Unterstützung von Docker-Umgebungsvariablen haben. Anstatt sich mit Umgebungsvariablen in Docker zu befassen, kehren wir zu den Grundlagen wie bash zurück! Hier ist eine flexiblere Methode mit einem Bash-Skript und einem.env Datei verwendet.

Ein Beispiel für eine .env-Datei:

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

Führen Sie dann dieses Bash-Skript im selben Verzeichnis aus, in dem alles ordnungsgemäß bereitgestellt werden soll:

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

Verweisen Sie einfach auf Ihre env-Variablen in Ihrer Compose-Datei mit der üblichen Bash-Syntax (dh ${SECRET_KEY}zum Einfügen der SECRET_KEYaus der.env Datei ).

Beachten Sie, dass das COMPOSE_CONFIGin meiner .envDatei definiert und in meinem Bash-Skript verwendet wird, aber Sie können es einfach durch {$COMPOSE_CONFIG}das ersetzenmy-compose-file.yml im Bash-Skript .

Beachten Sie auch, dass ich diese Bereitstellung gekennzeichnet habe, indem ich alle meine Container mit dem Präfix "myproject" benannt habe. Sie können einen beliebigen Namen verwenden, aber es hilft Ihnen, Ihre Container zu identifizieren, damit Sie später problemlos darauf verweisen können. Angenommen, Ihre Container sind zustandslos, wie sie sein sollten, entfernt dieses Skript Ihre Container schnell und stellt sie gemäß Ihren .env-Dateiparametern und Ihrer komponierten YAML-Datei erneut bereit.

Update Da diese Antwort sehr beliebt zu sein scheint, habe ich einen Blog-Beitrag geschrieben, in dem mein Docker-Bereitstellungsworkflow ausführlicher beschrieben wird: http://lukeswart.net/2016/03/lets-deploy-part-1/ Dies kann beim Hinzufügen hilfreich sein Komplexität einer Bereitstellungskonfiguration wie Nginx-Konfigurationen, LetsEncrypt-Zertifikate und verknüpfte Container.

Modulitos
quelle
2
Sie können einfach grep foo file.textstatt cat file.text | grep foo. In meinem Fall musste ich export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín
"Ich stelle fest, dass Leute Probleme mit der Unterstützung von Docker-Umgebungsvariablen haben" - haben Sie Details oder einen Link zu einem Ticket?
Tleyden
Entschuldigung, ich habe das spezifische Problem, das ich hatte, nicht protokolliert und es ist so lange her (~ 6 Monate), dass ich nicht weiß, ob es noch relevant ist. Aber ja, einige Funktionen in der Unterstützung von Docker-Umgebungsvariablen waren fehlerhaft und wurden von mehreren Benutzern gemeldet. Ich glaube, es ist jetzt viel besser. Wenn die Bereitstellungskonfiguration jedoch erheblich komplexer wird, würde ich es vorziehen, sie durch Verwendung von Bash für die Konfigurationslogik und Docker Compose für die Container-Orchestrierung zu modularisieren.
Modulitos
8
PSA: Dies funktioniert nur mitdocker-compose up und nicht mit docker-compose run.
Kriegslustig
5
Es gibt diese Lösung docs.docker.com/compose/compose-file/#envfile , die ich verwende, wenn Sie Umgebungsvariablen aus einem .envUnter hinzufügen env_file. Dann können Sie die Variablen in docker-compose.ymlusing${VARIABLE}
musale
111

Es scheint, dass Docker-Compose jetzt native Unterstützung für Standardumgebungsvariablen in der Datei bietet .

Alles, was Sie tun müssen, ist, Ihre Variablen in einer Datei mit dem Namen zu deklarieren, .envund sie werden in docker-compose.yml verfügbar sein.

Zum Beispiel für .envDateien mit Inhalten:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Sie können auf Ihre Variable zugreifen docker-compose.ymloder sie in den Container weiterleiten:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P.
quelle
4
Das ist die beste Lösung!
Ladenkov Vladislav
4
Das hat auch bei mir funktioniert. Ich weiß nicht warum, aber der Dateiname sollte wörtlich sein .env, zum Beispiel config.envhat bei mir nicht funktioniert.
HBat
1
@HBat das "." bedeutet eine versteckte Datei - dies ist das übliche Verfahren für lokale Konfigurationsdateien
Jeremy Hajek
2
Die beste Lösung. und Wir könnten / etc / environment-Requisiten hinzufügen und diese als Umgebung mit .env verwenden. Das wird sicherer.
Chinthaka Dinadasa
24

Das Folgende gilt für Docker-Compose 3.x. Legen Sie Umgebungsvariablen im Container fest

Methode - 1 Gerade Methode

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

Methode - 2 Die Datei ".env"

Erstellen Sie eine .env-Datei am selben Speicherort wie die Datei docker-compose.yml

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

und Ihre Erstellungsdatei wird wie sein

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

Quelle

Gajendra D Ambi
quelle
2
Ich würde gerne ein vollständiges Beispiel für Methode 1 sehen. Ich konnte dies nicht zum Laufen bringen und habe daher die .env-Datei verwendet (was gut funktioniert hat).
BobHy
20

Wenn Sie Umgebungsvariablen für Volumes verwenden, benötigen Sie:

  1. Erstellen Sie eine ENV- Datei in demselben Ordner, in dem sich die docker-compose.yaml Datei befindet

  2. Deklarieren Sie die Variable in der .envDatei:

    HOSTNAME=your_hostname
    
  3. Wechseln Sie $hostnamezu ${HOSTNAME}at docker-compose.yaml file

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

Natürlich können Sie dies dynamisch für jeden Build tun, wie:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
quelle
9
Beachten Sie, gemäß den Dokumenten: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

Am besten geben Sie Umgebungsvariablen außerhalb der docker-compose.ymlDatei an. Sie können verwendenenv_file Einstellung verwenden und Ihre Umgebungsdatei in derselben Zeile definieren. Wenn Sie dann ein Docker-Compose erneut ausführen, sollten die Container mit den neuen Umgebungsvariablen neu erstellt werden.

So sieht meine docker-compose.yml aus:

services:
  web:
    env_file: variables.env

Hinweis: Docker-Compose erwartet, dass jede Zeile in einer Env-Datei das VAR=VALFormat hat. Vermeiden Sie die Verwendung exportin der .envDatei. Außerdem sollte die .envDatei in dem Ordner abgelegt werden, in dem der Befehl docker-compose ausgeführt wird.

Jibu James
quelle
2
Der beste Weg in der Tat
Dany
NEIN. Die Umgebungsvariablen werden im Docker-Container nicht automatisch verfügbar gemacht. Sie müssen diese im Abschnitt "Umgebung" noch explizit erwähnen.
kta
6

Du kannst ... noch nicht. Aber dies ist eine Alternative, denken Sie wie ein Docker-Composer.yml-Generator:

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

Grundsätzlich ein Shell-Skript, das Ihre Variablen ersetzt. Sie können auch die Grunt-Aufgabe verwenden, um Ihre Docker-Erstellungsdatei am Ende Ihres CI-Prozesses zu erstellen.

Thomas Decaux
quelle
4

Ich habe ein einfaches Bash-Skript, das ich dafür erstellt habe. Es bedeutet nur, es vor der Verwendung in Ihrer Datei auszuführen: https://github.com/antonosmond/subber

Erstellen Sie einfach Ihre Erstellungsdatei mit doppelten geschweiften Klammern, um Umgebungsvariablen zu kennzeichnen, z.

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

Alles in doppelten geschweiften Klammern wird durch die gleichnamige Umgebungsvariable ersetzt, wenn ich die folgenden Umgebungsvariablen festgelegt hätte:

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

beim Ausführen subber docker-compose.ymlder resultierenden Datei würde wie folgt aussehen:

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

Soweit ich weiß, ist dies ein Work-in-Progress. Sie wollen es tun, aber es ist noch nicht veröffentlicht. Siehe 1377 (die "neue" 495 , die von @Andy erwähnt wurde).

Am Ende habe ich den von @Thomas vorgeschlagenen Ansatz ".yml als Teil von CI generieren" implementiert.

Anroots
quelle
1

füge env zur .env Datei hinzu

Sowie

VERSION=1.0.0

dann speichern Sie es unter 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
quelle
1

Verwenden Sie die ENV-Datei, um dynamische Werte in docker-compse.yml zu definieren. Sei es Port oder irgendein anderer Wert.

Beispiel Docker-Compose:

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}

In der ENV-Datei können Sie den Wert dieser Variablen definieren:

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

Verwenden Sie die 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"

Ich habe es über diesen Link https://github.com/docker/cli/issues/939 erhalten

user2851100
quelle
1

Seit 1.25.4 unterstützt Docker-Compose die Option --env-file, mit der Sie eine Datei mit Variablen angeben können.

Ihre sollte so aussehen:

hostname=my-host-name

Und der Befehl:

docker-compose --env-file /path/to/my-env-file config
Papillon
quelle