DevOps

Разница env_file и --env-file в Docker Compose: dev/prod

Разница между директивой env_file в docker-compose.yml и опцией --env-file. Организация .env файлов для dev и prod на Ubuntu. Лучшие практики, приоритеты переменных и примеры конфигураций для безопасного запуска.

В чем разница между директивой env_file в docker-compose.yml и запуском docker-compose с опцией --env-file? Как правильно организовать настройки для разработки (dev) и продакшена (prod) в Docker Compose с использованием .env файлов на Ubuntu с последними версиями Docker и Docker Compose, чтобы избежать запуска неправильных настроек? Какие лучшие практики подключения .env файлов считаются стандартными?

Директива env_file в docker-compose.yml загружает переменные окружения прямо в контейнеры сервисов, делая их доступными внутри приложения, в то время как опция --env-file при запуске docker compose --env-file=.env.dev up задаёт файл для интерполяции переменных в самом compose-файле (как основной .env). Для dev и prod на Ubuntu с Docker Compose v2.24+ организуйте отдельные .env.dev и .env.prod, указывайте их явно при запуске (docker compose --env-file .env.dev up), а секреты храните в env_file с опцией required: false и никогда не коммитьте в Git. Это стандартная практика из официальной документации Docker, минимизирующая риски запуска неверных настроек.


Содержание


Разница между env_file и --env-file в Docker Compose

Представьте: вы пишете docker-compose.yml и хотите подсунуть переменные в контейнер. env_file — это директива внутри секции сервиса, типа services: app: env_file: - .env.secrets. Она берёт указанный файл и грубо скидывает все его переменные как environment variables внутрь запущенного контейнера. Приложение внутри увидит их через os.environ или process.env. Плюс, можно несколько файлов — они обрабатываются по порядку, поздние перезаписывают ранние, как указано в документации по env_file.

А --env-file? Это опция командной строки: docker compose --env-file=.env.custom up. Она заменяет дефолтный .env в корне проекта — тот самый файл, который Docker Compose парсит для подстановки ${VAR} прямо в yaml. То есть, интерполяция: ${DB_HOST} в compose превратится в postgres из вашего кастомного файла. Но внутрь контейнера эти переменные не попадут автоматически! Разница огромная: один для контейнера (env_file), другой для парсинга compose (--env-file).

Почему путают? Потому что оба работают с .env-подобными файлами, но контексты разные. В Stack Overflow прямо пишут: env_file — для контейнера, не для сборки или интерполяции compose. А --env-file с docker run вообще для одиночных контейнеров, без compose.

Коротко: env_file = переменные в контейнере. --env-file = переменные для compose-парсера.


Приоритеты переменных (precedence)

Docker Compose не просто берёт переменные — у него строгая иерархия, чтобы избежать хаоса. Вот как это работает по официальным правилам precedence:

  1. environment: в compose (явно заданные в yaml) — топ приоритета.
  2. env_file: — следующие, но перезаписываются environment.
  3. Переменные хоста или дефолтный .env (для интерполяции).
  4. Dockerfile ENV/ARG — только если compose их не трогает.

Хостовые env перебивают .env! Если у вас DB_PASSWORD=secret в терминале, ваш .env с другим значением проиграет. В блоге vsupalov это называют “gotcha”. А в issue GitHub docker/compose разбирают: environment всегда доминирует над env_file.

На практике: для docker compose env file (124 запроса в Yandex) это критично. Тестируйте с docker compose config, чтобы увидеть финальные значения.


Организация .env для dev и prod на Ubuntu

На свежем Ubuntu (скажем, 24.04 с Docker 27+ и Compose v2.24.0 по состоянию на 2026-01-19) схема простая: не держите один .env, а разведите на окружения. Создайте:

  • .env.dev — локалка: DB_HOST=localhost, порты открыты.
  • .env.prod — прод: DB_HOST=prod-db.internal, секреты из Vault или SSM.

Запуск: docker compose --env-file .env.dev up -d. Для прод — --env-file .env.prod up. Добавьте в .gitignore: *.env и .env.* кроме шаблонов.

В docker-compose.yml:

yaml
services:
 app:
 env_file:
 - config/.env.db # общие для всех
 - .env.secrets # optional с required: false (v2.24+)
 environment:
 - DEBUG=true # перезапишет env_file

env_file можно делать опциональным: env_file: required: false. Если файл пропущен — warning, но не краш. Идеально для dev/prod, где секреты подключают по-разному.

А чтобы избежать фейла: скрипт deploy.sh:

bash
#!/bin/bash
ENV=${1:-dev}
docker compose --env-file .env.${ENV} up -d --build

./deploy.sh prod — и никаких сюрпризов.


Практические примеры конфигураций

Давайте кодом. Базовый docker-compose.yml для Node.js app с PostgreSQL:

yaml
version: '3.8'
services:
 db:
 image: postgres:16
 env_file: # внутрь контейнера
 - .env.db
 environment: # приоритет выше
 - POSTGRES_DB=${POSTGRES_DB:-app}
 
 app:
 build: .
 env_file:
 - .env.app
 ports:
 - "${APP_PORT:-3000}:3000" # интерполяция из --env-file или .env

.env.dev:

APP_PORT=3000
DB_HOST=db
POSTGRES_PASSWORD=devpass

.env.prod:

APP_PORT=80
DB_HOST=prod-db.example.com
POSTGRES_PASSWORD=strong_prod_pass

Запуск dev: docker compose --env-file .env.dev up. Prod: то же с .env.prod. В Warp.dev такой подход хвалят за простоту.

Проверьте: docker compose config покажет подстановку, docker compose logs app — переменные внутри.


Лучшие практики подключения .env файлов

Стандарты из сообщества и Build with Matija:

  • Не коммитьте секреты: .env.secrets в .gitignore. Используйте Docker Secrets или внешние менеджеры (AWS SSM, HashiCorp Vault).
  • Группируйте файлы: env_file: - common.env - ${ENV:-dev}.env (но интерполяция в env_file не работает!).
  • Избегайте .env как env_file: Смешивает интерполяцию и контейнер — антипаттерн, по Stack Overflow.
  • Скрипты и Makefile: make dev-up ENV=dev.
  • Тестирование: docker compose --env-file .env.test config | grep DB.
  • Множественные env_file: Порядок: базовые → окружение → секреты.

В The Data Farm подчёркивают: держите локальные .env вне Git.

Для docker compose переменные (94 запроса) — всегда docker compose config перед деплоем.


Безопасность и избежание ошибок

Что если запустите prod-скрипт с dev-.env? Беда: открытый порт, слабый пароль. Решение: в CI/CD проверяйте docker compose config | grep -E 'DEBUG|devpass' и фейлите билд.

required: false в env_file спасает от missing secrets. Нет интерполяции в env_file — не пытайтесь ${VAR} внутри него.

На Ubuntu: sudo docker compose --env-file .env.prod up в systemd или с user namespaces. Мониторьте с docker compose ps.

Риски: хост env overrides — экспортируйте чистый терминал или env -i docker compose up.


Источники

  1. Interpolation | Docker Docs
  2. Set environment variables | Docker Docs
  3. Environment variables precedence in Docker Compose
  4. How can I use environment variables in docker-compose? - Stack Overflow
  5. Specify the env file docker compose uses - Stack Overflow
  6. Using env_file with environment · Issue #1171 · docker/compose
  7. Docker Compose env_file: When to Use vs environment Variables
  8. Docker ARG, ENV and .env - a Complete Guide
  9. A Small Lesson on env Files in docker-compose
  10. Use An .env File in Docker Compose | Warp

Заключение

Разница между env_file (для контейнера) и --env-file (для интерполяции compose) фундаментальна — первая внутри app, вторая для yaml. Для dev/prod на Ubuntu используйте --env-file .env.dev/prod up, группируйте секреты в env_file и проверяйте config. Эти практики из официальной документации Docker и сообщества спасут от фейлов. Начните с шаблонов — и забудьте о случайных деплоях.

Авторы
Проверено модерацией
Модерация
Разница env_file и --env-file в Docker Compose: dev/prod