Як використовувати змінні середовища в docker compose


217

Я хотів би мати можливість використовувати змінні env всередині docker-compose.yml, зі значеннями, переданими під час docker-compose. Це приклад. Я роблю це сьогодні з базовою командою запуску докера, яка обгорнута навколо мого власного сценарію. Чи є спосіб досягти цього за допомогою композиту, без таких башмаків?

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

2
Про різні варіанти дивіться: docs.docker.com/compose/environment-variables
Massood Khaari

2
Це вирішено в останній версії композиту, ваш приклад буде працювати так само, як є. перевірити docs.docker.com/compose/compose-file/#variable-substitution щодо змінної заміни.
natbusa

1
Не забувайте Докер-додаток (з червня 2018 роки): stackoverflow.com/a/51007138/6309
VonC

Відповіді:


93
  1. Створіть а template.yml, який відповідає вашій docker-compose.ymlзмінній оточення.
  2. Припустимо, ваші змінні середовища містяться у файлі 'env.sh'
  3. Помістіть наведений нижче фрагмент коду у файл sh і запустіть його.

джерело env.sh; rm -rf docker-compose.yml; envsubst <"template.yml"> "docker-compose.yml";

Згенерується новий файл docker-compose.ymlз правильними значеннями змінних середовища.

Зразок файлу 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}

Зразок файлу 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 Не соромтеся ознайомитися з моєю відповіддю нижче, у розділі "Рішення BASH", де я детальніше окреслю цей підхід.
modulitos

7
все ще немає кращого рішення на даний момент?
lvthillo

13
чому б ви рекурсивно видаляли файл? (rm -rf docker-compose.yml)
moritzschaefer

@ Lorenzvth7 Ви можете перевірити мою відповідь нижче, який я думаю , це трохи більш ретельно: stackoverflow.com/a/33186458/1884158
modulitos

5
-1 це рішення лише ускладнює речі, і його слід оновлювати відповідно до нових можливостей docs.docker.com/compose/environment-variables/…
Ефрат Левітан

240

Рішення DOCKER:

Схоже, докер-композит 1.5+ і більше включив заміну змінних: https://github.com/docker/compose/releases

Остання версія Docker Compose дозволяє отримати доступ до змінних оточуючих середовищ із композиційного файлу. Таким чином, ви можете джерелом змінних вашого середовища, а потім запустіть Compose так:

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

Тоді ви можете посилатися на змінні в docker-compose.yml, використовуючи $ {VARIABLE}, наприклад:

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

А ось докладнішу інформацію про документи, взяті тут: https://docs.docker.com/compose/compose-file/#variable-substitution

Коли ви запускаєте docker-compose з цією конфігурацією, Compose шукає змінну середовища POSTGRES_VERSION у оболонці та замінює її значення дюйма. У цьому прикладі Compose вирішує зображення на постгреси: 9.3 перед запуском конфігурації.

Якщо змінна середовища не встановлена, Compose замінює порожній рядок. У наведеному вище прикладі, якщо POSTGRES_VERSION не встановлено, значенням параметра зображення є postgres :.

Підтримуються синтаксис $ VARIABLE та $ {VARIABLE}. Розширені функції типу оболонки, такі як $ {VARIABLE-default} та $ {VARIABLE / foo / bar}, не підтримуються.

Якщо вам потрібно встановити буквальний знак долара у значенні конфігурації, використовуйте подвійний знак долара ($$).

І я вважаю, що ця функція була додана в цьому запиті на потяг: https://github.com/docker/compose/pull/1765

Рішення BASH:

Я помічаю, що у людей є проблеми із підтримкою змінних середовища Docker. Замість того, щоб мати справу зі змінними середовища в Docker, повернемося до основ, як bash! Ось більш гнучкий метод, що використовує скрипт bash та .envфайл.

Приклад .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

потім запустіть цей скрипт bash в тому самому каталозі, який повинен все правильно розгорнути:

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

Просто посилайтеся на ваші змінні env у вашому композиційному файлі зі звичайним синтаксисом bash (тобто, ${SECRET_KEY}щоб вставити файл SECRET_KEYіз цього .envфайлу).

Зверніть увагу , що COMPOSE_CONFIGвизначається в моєму .envфайлі і використовувати в моєму БАШЕЄВ скрипті, але ви можете легко замінити тільки {$COMPOSE_CONFIG}з my-compose-file.ymlв сценарії Баша.

Також зауважте, що я позначив це розгортання, називаючи всі мої контейнери префіксом "мій проект". Ви можете використовувати будь-яке ім’я, яке ви хочете, але це допомагає визначити ваші контейнери, щоб ви могли легко посилатися на них пізніше. Якщо припустити, що ваші контейнери без стану, як це має бути, цей скрипт швидко видалить і перерозподілить ваші контейнери відповідно до ваших параметрів файлу .env та ваших композиційних файлів YAML.

Оновлення Оскільки ця відповідь здається досить популярною, я написав допис у блозі, де більш глибоко описується мій робочий процес розгортання Docker: http://lukeswart.net/2016/03/lets-deploy-part-1/ Це може бути корисним при додаванні більша складність конфігурації розгортання, як-от конфігурації nginx, серти LetsEncrypt та пов'язані контейнери.


2
Можна просто grep foo file.textзамість cat file.text | grep foo. У моєму випадку мені довелося export $(grep "^[^#]" .config | xargs) && cat docker-compose.yml | envsubst.
Хорхе Лавін

"Я помічаю, що у людей є проблеми із підтримкою змінних середовища Докера" - чи є у вас якісь деталі чи посилання на квиток?
tleyden

Вибачте, я не зафіксував конкретну проблему, яку я відчував, і це було так давно (~ 6 місяців), я не знаю, чи це все ще актуально. Але так, деякі функції в підтримці змінної середовища Docker були баггі, і про це повідомляли кілька користувачів. Я вважаю, що зараз це набагато краще. Але коли конфігурація розгортання стає значно складною, я вважаю за краще би модулювати її за допомогою bash для обробки логіки конфігурації та Docker Compose для оркестрації контейнерів.
modulitos

8
PSA: Це працює лише з,docker-compose up а не з docker-compose run.
Kriegslustig

5
Існує це рішення docs.docker.com/compose/compose-file/#envfile, яке я використовую, коли ви додаєте змінні середовища з .envпід env_file. Тоді ви можете посилатися на змінні у docker-compose.ymlвикористанні${VARIABLE}
musale

112

Здається, що докер-композит має вбудовану підтримку змінних середовища за замовчуванням у файлі .

все, що вам потрібно зробити, це оголосити свої змінні у файлі з назвою, .envі вони будуть доступні в docker-compose.yml.

Наприклад, для .envфайлів із вмістом:

MY_SECRET_KEY=SOME_SECRET
IMAGE_NAME=docker_image

Ви можете отримати доступ до змінної всередині docker-compose.ymlабо переслати їх у контейнер:

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

4
це найкраще рішення!
Ладенков Владислав

4
Це працювало і для мене. Я не знаю чому, але назва файлу має бути буквально .env, наприклад config.env, для мене це не працювало.
HBat

1
@HBat "." означає прихований файл - це звичайна процедура для локальних файлів конфігурацій
Jeremy Hajek

2
Найкраще рішення. і ми можемо додати / etc / Environment реквізити і використовувати їх як середовище з використанням .env. Це буде більш безпечно.
Чінтхака Дінадаса

24

Наступне стосується докер-композиту 3.x Встановити змінні середовища всередині контейнера

метод - 1 Прямий метод

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

метод - 2 Файл ".env"

Створіть .env файл у тому самому місці, що і docker-compose.yml

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

і ваш композиційний файл буде подібний

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

джерело


2
Я хотів би побачити повний приклад способу 1. Я не зміг зробити цю роботу, тому в кінцевому рахунку використовував файл .env (який працював чудово).
BobHy

20

Використовуючи змінні середовища для томів, вам потрібно:

  1. створити .env файл у тій самій папці, в якій міститься docker-compose.yaml файл

  2. оголосити змінну у .envфайлі:

    HOSTNAME=your_hostname
    
  3. Зміна $hostnameв ${HOSTNAME}в docker-compose.yaml файлі

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

Звичайно, ви можете робити це динамічно для кожної збірки, наприклад:

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

9
Зауважте, згідно з документами:The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy.
Джеймс Гентес

19

Найкращий спосіб - вказати змінні середовища за межами docker-compose.ymlфайлу. Ви можете скористатися env_fileналаштуваннями та визначити ваш файл середовища в одному рядку. Потім повторне створення докер-композиції повинно відтворити контейнери з новими змінними середовища.

Ось як виглядає мій docker-compose.yml:

services:
  web:
    env_file: variables.env

Примітка: docker-compose очікує, що кожен рядок у файлі env має VAR=VALформат. Уникайте використання exportвсередині .envфайлу. Також .envфайл слід розмістити в папці, де виконується команда docker-compose.


2
Найкращий спосіб справді
Dany

НЕМАЄ. Він автоматично не зробить змінні середовища доступними всередині контейнера докера. Вам все одно потрібно чітко згадати про це в розділі навколишнього середовища.
kta

6

Ви не можете ... ще. Але це альтернатива, подумайте, як генератор docker-composer.yml:

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

В основному сценарій оболонки, який замінить ваші змінні. Крім того, ви можете використовувати завдання Grunt, щоб створити ваш файл для створення докерів в кінці процесу CI.


4

У мене є простий скрипт bash, який я створив для цього, це просто означає запустити його у вашому файлі перед використанням: https://github.com/antonosmond/subber

В основному просто створіть свій композиційний файл, використовуючи подвійні фігурні дужки, щоб позначити змінні середовища, наприклад:

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

Все, що є в подвійних фігурних дужках, буде замінено на однойменну змінну середовища, тому якщо у мене встановлені такі змінні середовища:

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

при запуску subber docker-compose.ymlотриманого файлу буде виглядати так:

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

2

Наскільки мені відомо, це незавершена робота. Вони хочуть це зробити, але це ще не випущено. Дивіться 1377 ("новий" 495, який згадував @Andy).

Я в кінцевому підсумку реалізував підхід "генерувати .yml як частину CI", запропонований @Thomas.


1

додати env у .env файл

Як от

VERSION=1.0.0

потім збережіть його 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

Використовуйте .env файл для визначення динамічних значень у docker-compse.yml. Будь то порт або будь-яке інше значення.

Зразок докер-композиції:

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}

Всередині .env-файла можна визначити значення цих змінних:

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

Використовуйте версію 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"

Я отримав його за цим посиланням https://github.com/docker/cli/isissue/939


1

Починаючи з 1.25.4, docker-compose підтримує опцію, --env-fileяка дозволяє вказати файл, що містить змінні.

Ваше має виглядати так:

hostname=my-host-name

І команда:

docker-compose --env-file /path/to/my-env-file config
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.