Переменные окружения в Docker Compose

Практическая настройка переменных окружения в Docker Compose: .env, environment, env_file, проверка подстановки и безопасная работа с секретами.

Переменные окружения позволяют выносить изменяемые параметры из compose.yaml: порты, имена баз данных, режимы работы приложения и другие настройки.

В этой инструкции рассматривается только работа с переменными окружения в Docker Compose: .env, environment, env_file, проверка подстановки и типичные ошибки.

Проверено на: Ubuntu Server 24.04 LTS и Docker Compose Plugin
Уровень сложности: начальный
Время выполнения: около 15 минут
Требуемый доступ: пользователь с доступом к Docker

Что будет рассмотрено

После выполнения инструкции можно будет:

  • использовать переменные в compose.yaml;
  • создавать файл .env;
  • передавать переменные внутрь контейнера;
  • подключать отдельный файл через env_file;
  • задавать значения по умолчанию;
  • проверять итоговую конфигурацию;
  • избегать попадания чувствительных данных в Git.

Создание тестового проекта

Создайте каталог:

mkdir -p ~/compose-env-example
cd ~/compose-env-example

Создайте файл .env:

cat >.env <<'EOF'
WEB_PORT=8080
APP_MODE=production
APP_NAME=compose-example
EOF

Проверьте содержимое:

cat .env

Использование переменной в compose.yaml

Создайте compose.yaml:

cat >compose.yaml <<'EOF'
services:
  web:
    image: nginx:alpine
    ports:
      - "${WEB_PORT}:80"
EOF

Проверьте итоговую конфигурацию:

docker compose config

В выводе значение:

${WEB_PORT}

будет заменено на:

8080

Запуск проекта

docker compose up -d

Проверьте:

docker compose ps

Проверьте Nginx:

curl -I http://127.0.0.1:8080

Для чего используется .env

Файл .env, расположенный рядом с compose.yaml, используется Docker Compose для подстановки значений в сам Compose-файл.

Пример:

ports:
  - "${WEB_PORT}:80"

При этом переменная WEB_PORT не обязательно передаётся внутрь контейнера.

Проверьте:

docker compose exec web env | grep WEB_PORT

Если переменная отдельно не указана в environment, результата не будет.

Передача переменной внутрь контейнера

Измените compose.yaml:

cat >compose.yaml <<'EOF'
services:
  app:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    environment:
      APP_MODE: "${APP_MODE}"
      APP_NAME: "${APP_NAME}"
EOF

Проверьте:

docker compose config

Запустите:

docker compose up -d

Проверьте переменные внутри контейнера:

docker compose exec app env |
grep -E 'APP_MODE|APP_NAME'

Ожидаемый результат:

APP_MODE=production
APP_NAME=compose-example

Краткая форма environment

Можно использовать список:

environment:
  - APP_MODE=${APP_MODE}
  - APP_NAME=${APP_NAME}

Более читаемая форма:

environment:
  APP_MODE: "${APP_MODE}"
  APP_NAME: "${APP_NAME}"

Для больших конфигураций словарь обычно удобнее.

Значение по умолчанию

Если переменная может отсутствовать, задайте значение по умолчанию:

environment:
  APP_MODE: "${APP_MODE:-development}"

Если APP_MODE не задана, будет использовано:

development

Проверка:

docker compose config

Обязательная переменная

Можно потребовать наличие значения:

environment:
  DATABASE_PASSWORD: "${DATABASE_PASSWORD:?DATABASE_PASSWORD is required}"

Если переменная отсутствует, docker compose config завершится ошибкой.

Это полезно для параметров, без которых приложение не должно запускаться.

Разница между :- и -

Пример:

${VARIABLE:-default}

использует значение по умолчанию, если переменная отсутствует или пуста.

Пример:

${VARIABLE-default}

использует значение по умолчанию только если переменная отсутствует.

Для большинства конфигураций удобнее:

:- 

Подключение env_file

Создайте файл:

cat >app.env <<'EOF'
APP_MODE=production
APP_NAME=compose-example
LOG_LEVEL=info
EOF

Используйте его в compose.yaml:

cat >compose.yaml <<'EOF'
services:
  app:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    env_file:
      - app.env
EOF

Проверьте:

docker compose up -d

Посмотрите переменные:

docker compose exec app env |
grep -E 'APP_MODE|APP_NAME|LOG_LEVEL'

Разница между .env и env_file

Файл .env:

  • используется Compose для подстановки значений;
  • влияет на обработку compose.yaml;
  • автоматически читается из каталога проекта.

Параметр env_file:

  • передаёт переменные внутрь контейнера;
  • указывается в конфигурации сервиса;
  • может ссылаться на файл с любым именем.

Это разные механизмы.

Одновременное использование

Пример:

services:
  app:
    image: alpine
    env_file:
      - app.env
    environment:
      APP_MODE: "${APP_MODE}"

В этом случае:

  • app.env передаёт набор переменных;
  • environment может переопределить отдельные значения.

Приоритет environment над env_file

Создайте:

cat >app.env <<'EOF'
APP_MODE=development
EOF

Файл .env:

cat >.env <<'EOF'
APP_MODE=production
EOF

compose.yaml:

services:
  app:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    env_file:
      - app.env
    environment:
      APP_MODE: "${APP_MODE}"

Внутри контейнера будет:

APP_MODE=production

Значение из environment переопределяет env_file.

Передача файла с другим именем

Compose можно запустить с отдельным файлом переменных:

docker compose   --env-file .env.production   up -d

Пример файла:

cat >.env.production <<'EOF'
WEB_PORT=8080
APP_MODE=production
EOF

Проверка:

docker compose   --env-file .env.production   config

Переменные оболочки

Переменные текущей shell-сессии также могут использоваться:

export WEB_PORT=9090

Проверьте:

docker compose config

После завершения сессии значение может исчезнуть.

Удалить переменную:

unset WEB_PORT

Проверка подстановки

Основная команда:

docker compose config

Она показывает итоговый Compose-файл после подстановки значений.

Проверка без вывода:

docker compose config --quiet

Проверка конкретной переменной внутри контейнера:

docker compose exec app printenv APP_MODE

Кавычки в .env

Допустимые варианты:

APP_NAME=SysNotes
APP_TITLE="Docker Compose example"
APP_MESSAGE='Hello world'

Для простых значений кавычки не обязательны.

Если значение содержит пробелы, безопаснее использовать кавычки.

Пустые значения

Пример:

OPTIONAL_VALUE=

Переменная существует, но содержит пустую строку.

Проверьте:

docker compose config

Не путайте пустое значение с полностью отсутствующей переменной.

Комментарии в .env

# Порт веб-приложения
WEB_PORT=8080

Комментарии должны начинаться с #.

Экранирование знака доллара

Если приложению нужно передать буквальный символ $, используйте:

$$

Пример:

command:
  - sh
  - -c
  - echo $$HOME

Одинарный $ Docker Compose воспринимает как начало подстановки.

Секреты и .env

Файл .env удобен, но не является защищённым хранилищем секретов.

Не размещайте в публичном репозитории:

  • пароли баз данных;
  • API-токены;
  • приватные ключи;
  • SMTP-пароли;
  • access token;
  • секреты JWT.

Добавьте в .gitignore:

cat >>.gitignore <<'EOF'
.env
.env.*
app.env
EOF

При этом шаблон можно хранить отдельно:

.env.example

Пример:

cat >.env.example <<'EOF'
WEB_PORT=8080
APP_MODE=production
DATABASE_PASSWORD=CHANGE_ME
EOF

Проверка Git

Посмотрите статус:

git status

Проверьте, отслеживается ли .env:

git ls-files .env

Если файл уже добавлен в Git:

git rm --cached .env

После этого смените все секреты, которые могли попасть в историю репозитория.

Права на файл

Ограничьте доступ:

chmod 600 .env

Проверьте:

ls -l .env

Ожидаемый режим:

-rw-------

Изменение переменных

После изменения .env или env_file контейнер обычно нужно пересоздать:

docker compose up -d --force-recreate

Проверьте:

docker compose exec app env |
grep APP_MODE

Обычный docker compose restart не пересоздаёт конфигурацию контейнера и может не применить новые значения.

Типичные проблемы

Переменная не подставилась

Проверьте:

docker compose config

Убедитесь, что:

  • .env находится в каталоге проекта;
  • имя переменной совпадает;
  • в строке нет лишних пробелов;
  • используется правильный Compose-файл.

В контейнере нет переменной из .env

.env сам по себе не передаёт все значения внутрь контейнера.

Добавьте:

environment:
  VARIABLE_NAME: "${VARIABLE_NAME}"

или используйте:

env_file:
  - app.env

После изменения осталось старое значение

Пересоздайте контейнер:

docker compose up -d --force-recreate

Compose сообщает, что переменная не установлена

Задайте её в .env:

VARIABLE_NAME=value

Либо используйте значение по умолчанию:

${VARIABLE_NAME:-default}

Значение обрезается или интерпретируется неправильно

Проверьте кавычки и специальные символы.

Для сложных паролей и строк лучше избегать ручной подстановки в YAML и использовать отдельное секрет-хранилище.

Быстрый пример

.env:

WEB_PORT=8080
APP_MODE=production

compose.yaml:

services:
  app:
    image: nginx:alpine
    ports:
      - "${WEB_PORT}:80"
    environment:
      APP_MODE: "${APP_MODE}"

Проверка:

docker compose config

Запуск:

docker compose up -d

Проверка переменной:

docker compose exec app printenv APP_MODE

Удаление тестового проекта

cd ~/compose-env-example
docker compose down
cd ~
rm -rf ~/compose-env-example

Итог

После выполнения инструкции:

  • настроена подстановка через .env;
  • переменные переданы внутрь контейнера;
  • использован отдельный env_file;
  • рассмотрены значения по умолчанию и обязательные переменные;
  • проверена итоговая конфигурация;
  • показана безопасная работа с Git;
  • объяснено, когда требуется пересоздание контейнера.

Для production-среды чувствительные данные лучше хранить в специализированной системе секретов, а не в обычных текстовых файлах.

← Предыдущая статья Сети Docker: базовая настройка связи между контейнерами Следующая статья → Healthcheck в Docker Compose