Jak używać zmiennych środowiskowych w komponowaniu dokera

217

Chciałbym móc używać zmiennych env wewnątrz docker-compose.yml, z wartościami przekazywanymi w momencie dokowania-komponowania. To jest przykład. Robię to dzisiaj za pomocą podstawowej komendy uruchamiania dokera, która jest owinięta wokół mojego skryptu. Czy istnieje sposób, aby to osiągnąć za pomocą komponowania bez takich bashów?

proxy:
  hostname: $hostname
  volumes:
    - /mnt/data/logs/$hostname:/logs
    - /mnt/data/$hostname:/data
Dmitry z
źródło
2
Różne opcje można znaleźć na stronie: docs.docker.com/compose/environment-variables
Massood Khaari,
2
Zostało to rozwiązane w ostatniej wersji komponowania, twój przykład będzie działał tak jak jest. sprawdź docs.docker.com/compose/compose-file/#variable-substitution na temat zastępowania zmiennych.
natbusa
1
Nie zapomnij Döcker aplikacji (od czerwca 2018): stackoverflow.com/a/51007138/6309
VonC

Odpowiedzi:

93
  1. Utwórz zmienną środowiskową template.yml, która jest twoja docker-compose.yml.
  2. Załóżmy, że zmienne środowiskowe znajdują się w pliku „env.sh”
  3. Umieść poniższy fragment kodu w pliku sh i uruchom go.

źródło env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

Nowy plik docker-compose.ymlzostanie wygenerowany z poprawnymi wartościami zmiennych środowiskowych.

Przykładowy plik 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}

Przykładowy plik 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
źródło
@ Poznaj Zapraszam do zapoznania się z moją odpowiedzią poniżej w części „Rozwiązanie BASH”, w której nieco bardziej szczegółowo opisuję to podejście.
modulitos
7
nadal nie ma lepszego rozwiązania?
lvthillo
13
dlaczego miałbyś rekurencyjnie usuwać plik? (rm -rf docker-compose.yml)
moritzschaefer
@ lorenzvth7 Możesz sprawdzić moją odpowiedź poniżej, która moim zdaniem jest nieco dokładniejsza: stackoverflow.com/a/33186458/1884158
modulitos
5
-1 to rozwiązanie tylko komplikuje rzeczy i powinno być aktualizowane zgodnie z nowymi umiejętnościami dokera
Efrat Levitan
240

Rozwiązanie DOCKER:

Wygląda na to, że docker-compose 1.5+ ma włączone podstawianie zmiennych: https://github.com/docker/compose/releases

Najnowsza wersja Docker Compose umożliwia dostęp do zmiennych środowiskowych z pliku tworzenia. Możesz więc zdobyć swoje zmienne środowiskowe, a następnie uruchomić Compose w następujący sposób:

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

Następnie możesz odwoływać się do zmiennych w docker-compose.yml za pomocą $ {VARIABLE}, w następujący sposób:

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

A oto więcej informacji z dokumentów, pobranych tutaj: https://docs.docker.com/compose/compose-file/#variable-substitution

Po uruchomieniu docker-compose w tej konfiguracji Compose szuka w powłoce zmiennej środowiskowej POSTGRES_VERSION i zastępuje jej wartość. W tym przykładzie Compose przekształca obraz w postgres: 9.3 przed uruchomieniem konfiguracji.

Jeśli zmienna środowiskowa nie jest ustawiona, Utwórz zastępuje pustym ciągiem. W powyższym przykładzie, jeśli nie ustawiono POSTGRES_VERSION, wartością opcji obrazu jest postgres :.

Obsługiwana jest składnia $ VARIABLE i $ {VARIABLE}. Rozszerzone funkcje w stylu powłoki, takie jak $ {VARIABLE-default} i $ {VARIABLE / foo / bar}, nie są obsługiwane.

Jeśli chcesz wstawić dosłowny znak dolara w wartości konfiguracji, użyj podwójnego znaku dolara ($$).

I uważam, że ta funkcja została dodana w tym żądaniu ściągnięcia: https://github.com/docker/compose/pull/1765

Rozwiązanie BASH:

Zauważyłem, że ludzie mają problemy z obsługą zmiennych środowiskowych Dockera. Zamiast zajmować się zmiennymi środowiskowymi w Dockerze, wróćmy do podstaw, takich jak bash! Oto bardziej elastyczna metoda wykorzystująca skrypt bash i .envplik.

Przykładowy plik .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

następnie uruchom ten skrypt bash w tym samym katalogu, który powinien wszystko poprawnie wdrożyć:

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

Po prostu odwołaj się do zmiennych env w pliku tworzenia ze zwykłą składnią bash (tj. ${SECRET_KEY}Aby wstawić plik SECRET_KEYz .envpliku).

Zauważ, że COMPOSE_CONFIGjest zdefiniowany w moim .envpliku i używany w moim skrypcie bash, ale możesz łatwo zastąpić {$COMPOSE_CONFIG}go my-compose-file.ymlw skrypcie bash.

Zauważ też, że opisałem to wdrożenie, nazywając wszystkie moje kontenery przedrostkiem „myproject”. Możesz użyć dowolnej nazwy, ale pomaga to zidentyfikować pojemniki, dzięki czemu możesz łatwo do nich później sięgnąć. Zakładając, że twoje kontenery są bezstanowe, tak jak powinny, ten skrypt szybko usunie i ponownie wdroży twoje kontenery zgodnie z parametrami pliku .env i twoim plikiem YAML.

Aktualizacja Ponieważ ta odpowiedź wydaje się dość popularna, napisałem post na blogu, który bardziej szczegółowo opisuje mój przepływ pracy wdrażania Dockera: http://lukeswart.net/2016/03/lets-deploy-part-1/ Może to być pomocne, gdy dodasz bardziej złożona konfiguracja wdrożenia, taka jak konfiguracje nginx, certyfikaty LetsEncrypt i połączone kontenery.

modulitos
źródło
2
Możesz po prostu grep foo file.textzamiast cat file.text | grep foo. W moim przypadku musiałem export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Jorge Lavín
„Zauważyłem, że ludzie mają problemy z obsługą zmiennych środowiskowych Dockera” - czy masz jakieś szczegóły lub link do zgłoszenia?
tleyden
Przepraszam, nie zarejestrowałem konkretnego problemu, który napotkałem, i to było tak dawno (~ 6 miesięcy), nie wiem, czy to nadal dotyczy. Ale tak, niektóre funkcje obsługi zmiennych środowiskowych Docker były błędne i zgłosiło to wielu użytkowników. Wierzę, że teraz jest znacznie lepiej. Ale gdy konfiguracja wdrażania staje się znacznie złożona, wolałbym ją zmodularyzować, używając bash do obsługi logiki konfiguracji i Docker Compose dla organizacji kontenerów.
modulitos 10.04.16
8
PSA: Działadocker-compose up to tylko z, a nie z docker-compose run.
Kriegslustig
5
Jest to rozwiązanie docs.docker.com/compose/compose-file/#envfile że używam gdzie dodasz zmienne środowiskowe z .envniedostatecznie env_file. Następnie możesz odwołać się do zmiennych w docker-compose.ymlużyciu${VARIABLE}
musale
111

Wygląda na to, że docker-compose ma teraz natywne wsparcie dla domyślnych zmiennych środowiskowych w pliku .

wszystko, co musisz zrobić, to zadeklarować zmienne w pliku o nazwie, .enva będą one dostępne w docker-compose.yml.

Na przykład dla .envpliku z zawartością:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Możesz uzyskać dostęp do zmiennej wewnątrz docker-compose.ymllub przekazać ją do kontenera:

my-service:
  image: ${IMAGE_NAME}
  environment:
    MY_SECRET_KEY: ${MY_SECRET_KEY}
Doody P.
źródło
4
to najlepsze rozwiązanie!
Ladenkov Vladislav
4
To również działało dla mnie. Nie wiem dlaczego, ale nazwa pliku powinna być dosłownie .env, na przykład config.envnie działała dla mnie.
HBat
1
@HBat the „.” oznacza ukryty plik - jest to zwykła procedura dla lokalnych plików konfiguracyjnych
Jeremy Hajek
2
Najlepszym rozwiązaniem. i Możemy dodać rekwizyty / etc / environment i używać ich jako środowiska przy użyciu .env. To będzie bezpieczniejsze.
Chinthaka Dinadasa
24

Poniższe zasady dotyczą kompilowania dokerów 3.x Ustaw zmienne środowiskowe w kontenerze

metoda - 1 metoda prosta

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

method - 2 Plik „.env”

Utwórz plik .env w tej samej lokalizacji, co plik docker-compose.yml

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

a Twój plik tworzenia będzie podobny

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

źródło

Gajendra D Ambi
źródło
2
Chciałbym zobaczyć pełny przykład metody 1. Nie mogłem tego zrobić, więc skończyło się na pliku .env (który działał dobrze).
BobHy,
20

Podczas korzystania ze zmiennych środowiskowych dla woluminów potrzebujesz:

  1. utwórz plik .env w tym samym folderze, który zawiera docker-compose.yaml plik

  2. zadeklaruj zmienną w .envpliku:

    HOSTNAME=your_hostname
    
  3. Zmień $hostnamena ${HOSTNAME}w docker-compose.yaml pliku

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

Oczywiście możesz to zrobić dynamicznie na każdej kompilacji, np .:

echo "HOSTNAME=your_hostname" > .env && sudo docker-compose up
Nerijus Gedrimas
źródło
9
Uwaga, zgodnie z dokumentami: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

Najlepszym sposobem jest określenie zmiennych środowiskowych poza docker-compose.ymlplikiem. Możesz użyć env_fileustawienia i zdefiniować plik środowiska w tym samym wierszu. Następnie ponowne skomponowanie dokera powinno ponownie utworzyć kontenery z nowymi zmiennymi środowiskowymi.

Oto jak wygląda mój docker-compose.yml:

services:
  web:
    env_file: variables.env

Uwaga: docker-compose oczekuje, że każda linia w pliku env będzie miała VAR=VALformat. Unikaj używania exportw .envpliku. Ponadto .envplik powinien zostać umieszczony w folderze, w którym wykonywane jest polecenie docker-compose.

Jibu James
źródło
2
Rzeczywiście najlepszy sposób
Dany
NIE. Nie spowoduje to automatycznego udostępnienia zmiennych środowiskowych w kontenerze dokera. Nadal musisz je wyraźnie wymienić w sekcji dotyczącej środowiska.
kta
6

Nie możesz ... jeszcze. Ale jest to alternatywa, pomyśl jak generator docker-composer.yml:

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

Zasadniczo skrypt powłoki, który zastąpi twoje zmienne. Możesz także użyć zadania Grunt, aby skompilować plik redakcji dokera na końcu procesu CI.

Thomas Decaux
źródło
4

Mam prosty skrypt bash, który dla tego stworzyłem, oznacza to po prostu uruchomienie go w pliku przed użyciem: https://github.com/antonosmond/subber

Zasadniczo wystarczy utworzyć plik tworzenia przy użyciu podwójnych nawiasów klamrowych, aby wskazać zmienne środowiskowe, np .:

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

Wszystko w podwójnych nawiasach klamrowych zostanie zastąpione zmienną środowiskową o tej samej nazwie, więc gdybym miał ustawione następujące zmienne środowiskowe:

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

po uruchomieniu subber docker-compose.ymlwynikowy plik wyglądałby następująco:

app:
    build: "~/my_app/build"
ports:
    - "5000:5000"
Anton
źródło
2

O ile mi wiadomo, jest to praca w toku. Chcą to zrobić, ale nie zostało jeszcze wydane. Zobacz 1377 („nowy” 495 wspomniany przez @Andy).

W końcu wdrożyłem podejście „generuj .yml jako część CI” zaproponowane przez @Thomas.

anroots
źródło
1

dodaj env do pliku .env

Jak na przykład

VERSION=1.0.0

następnie zapisz to w 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
źródło
1

Użyj pliku .env, aby zdefiniować wartości dynamiczne w docker-compse.yml. Może to być port lub inna wartość.

Przykładowa kompozycja dokowania:

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}

Wewnątrz pliku .env możesz zdefiniować wartość tych zmiennych:

CONSUL_IP=172.31.28.151
HOST_ADDRESS=172.31.16.221
TEST_CORE_PORT=10002
sorabzon
źródło
1
env SOME_VAR="I am some var" OTHER_VAR="I am other var" docker stack deploy -c docker-compose.yml

Użyj wersji 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"

Mam go z tego linku https://github.com/docker/cli/issues/939

użytkownik2851100
źródło
1

Od wersji 1.25.4 funkcja docker-compose obsługuje opcję --env-fileumożliwiającą określenie pliku zawierającego zmienne.

Twój powinien wyglądać tak:

hostname=my-host-name

I polecenie:

docker-compose --env-file /path/to/my-env-file config
papillon
źródło