Переменные окружения в 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-среды чувствительные данные лучше хранить в специализированной системе секретов, а не в обычных текстовых файлах.