Почему подстановка переменных не работает при использовании нескольких env_files в docker-compose.yml?

Я пытаюсь получить файл, содержащий docker, работающий с несколькими .env файлами, и мне не повезло. Я пытаюсь установить три .env файла:

  • глобальные параметры, одинаковые для всех экземпляров контейнера.
  • настройки, зависящие от среды (материал только для теста или разработчика)
  • локальные настройки - переопределяемые вещи, которые разработчик может потребовать изменить, если у них есть конфликты, например, с номером порта

Мой docker-compose.yml файл выглядит следующим образом:

version: '2'
services:
  db:
    env_file:
      - ./.env
      - ./.env.${ENV}
      - ./.env.local
    image: postgres
    ports:
      - ${POSTGRES_PORT}:5432

.env выглядит следующим образом:

POSTGRES_USER=myapp

и .env.development выглядит следующим образом:

POSTGRES_PASSWORD=supersecretpassword
POSTGRES_HOST=localhost
POSTGRES_PORT=25432
POSTGRES_DB=myapp_development

.env.local в этом случае не существует.

После запуска ENV=development docker-compose up я получаю следующий вывод:

$ ENV=development docker-compose up
WARNING: The POSTGRES_PASSWORD variable is not set. Defaulting to a blank string.
WARNING: The POSTGRES_DB variable is not set. Defaulting to a blank string.
WARNING: The POSTGRES_PORT variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.db.ports is invalid: Invalid port ":5432", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]

Из этого сообщения об ошибке выглядит, что ни одна из моих переменных среды не используется. Я просто обновился до новейшей доступной документации докеры - также - те же ошибки:

$ docker-compose --version
docker-compose version 1.8.0-rc1, build 9bf6bc6

Любые идеи здесь? Было бы неплохо иметь один docker-compose.yml, который будет работать в нескольких средах.

Ответ 1

Имейте в виду, что существуют две разные среды, в которых вы определяете переменные. Хост-компьютер, на котором выполняется команда создания докеры, и сам контейнер (запуск службы db в вашем случае).

В вашем файле docker-compose.yml есть доступ к вашим переменным среды хоста. Следовательно, ENV доступен из команды docker-compose, но не в ваших файлах .env.

Наоборот, значение для ENV недоступно внутри контейнера, но все переменные, определенные в ваших файлах .env, будут.

Я не знаю, действительно ли вам нужен ваш контейнер db для доступа к переменным, определенным на вашем .env.development. Но, по крайней мере, кажется, что ваша хост-машина должна иметь содержимое этого файла, поэтому, когда вызывается команда docker-compose, определяется переменная POSTGRES_PORT.

Чтобы исправить вашу конкретную проблему, вам нужно будет также определять переменные среды на вашей главной машине, а не только для контейнера. Вы можете сделать что-то вроде этого:

#Set for host
ENV=development

#Also sets the variables on the host 
source ./.env.$ENV

#POSTGRES_PORT defined in .env.development is used here
docker-compose up

#since env_file also contains .env.development, the variables will be reachable from the container.

Надеюсь, что это поможет.

Ответ 2

Чтобы применить разные/несколько env_files в зависимости от рабочей среды, такой как разработка/подготовка/производство, я думаю, что лучший способ для docker-compose - это использовать несколько docker-compose yml файлов.

Например:

1. Начните с базового файла, который определяет каноническую конфигурацию для сервисов.

docker-compose.yml

web:
  image: example/my_web_app:latest
  env_file:
    - .env

2. Добавить файл переопределения для разработки, как следует из его названия, может содержать переопределения конфигурации для существующих служб или совершенно новых служб.

докер-compose.override.yml

web:
  build: .
  volumes:
    - '.:/code'
  ports:
    - 8883:80
  env_file:
    - .env.dev

Когда вы запускаете docker-compose up он автоматически читает переопределения.

3. Создайте другой файл переопределения для продакшен среды.

докер-compose.prod.yml

web:
  ports:
    - 80:80
  env_file:
    - .env.prod

Для развертывания с этим рабочим файлом Compose вы можете запустить

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

Заметка

Моя версия Docker:

$ docker -v
Docker version 18.06.1-ce, build e68fc7a

$ docker-compose -v
docker-compose version 1.22.0, build f46880fe

Ссылка: https://docs.docker.com/compose/extends/

Ответ 3

во время чтения этой страницы: https://docs.docker.com/compose/environment-variables/

и, исходя из моего понимания, вы должны сделать следующее:

для глобальных переменных (которые не должны меняться), создайте файл env следующим образом:

VAR1=VALUE1
VAR2=VALUE2

а для остальных (которые могут измениться) вы должны добавить свое имя в среду в файле docker-compose.yml следующим образом:

environment:
    - VAR1
    - VAR2

это приведет к значениям VAR1 и VAR2 из оболочки, в которой вы выполняете компоновку docker.

Надеюсь, это поможет.

Ответ 4

Существует неверное представление о файле .env и опции env_file в docker-compose.yml, поскольку это очень неоднозначно. Шин очень хорошо отмечает это в проблеме с github. Docker-compose не использует env_file. Я просто процитирую его резюме:

  • Подстановка переменных в вашем файле docker-compose.yml будет извлечена (в порядке убывания приоритета) из вашей оболочки и вашего файла .env.

  • Переменные, доступные в вашем контейнере, представляют собой комбинацию значений, найденных в ваших файлах env_file, и значений, описанных в разделе среды службы.

  • Это два совершенно разных набора функций.