ARG, ENV и docker build --build-arg: параметры и секреты сборки
Автор: Казачкин Даниил Михайлович · Обновлено
ARG — параметр рецепта сборки; ENV — переменная окружения, которая может попасть в создаваемые контейнеры. Запрос «docker build args» обычно сводится к двум вопросам: как…
ARG — параметр рецепта сборки; ENV — переменная окружения, которая может попасть в создаваемые контейнеры. Запрос «docker build args» обычно сводится к двум вопросам: как передать значение через --build-arg и почему оно не видно после запуска. Разделение фаз помогает не пересобирать образ ради обычной настройки приложения.
Минимальный эксперимент
Создайте Dockerfile:
FROM alpine:3.22
ARG RELEASE=dev
ENV APP_MODE=demo
RUN printf '%s\n' "$RELEASE" > /release.txt
CMD ["sh", "-c", "cat /release.txt; printf '%s\\n' \"$APP_MODE\""]docker build --build-arg RELEASE=2026.09 -t dk-args:1 .
docker run --rm dk-args:1
docker run --rm -e APP_MODE=test dk-args:1Первый запуск напечатает 2026.09 и demo, второй — 2026.09 и test. RELEASE использован при сборке и записан в файл. APP_MODE имеет значение по умолчанию в образе, но его переопределяет окружение контейнера. docker run -e RELEASE=other не перепишет уже созданный release.txt. Различие ARG и ENV.
Значение --build-arg без подходящей инструкции ARG и её использования не настраивает приложение автоматически. У каждого параметра должно быть конкретное место применения. И наоборот, ENV APP_MODE=demo не становится изменяемым через --build-arg APP_MODE=test без связки ARG и ENV в рецепте.
ARG перед FROM
ARG BASE_VERSION=3.22
FROM alpine:${BASE_VERSION}
ARG BASE_VERSION
RUN printf '%s\n' "$BASE_VERSION" > /base-version.txt
CMD ["cat", "/base-version.txt"]Глобальный ARG позволяет выбирать FROM. Внутри стадии его нужно объявить снова, если значение требуется последующим инструкциям. Соберите docker build --build-arg BASE_VERSION=3.22 -t dk-args:base .: контейнер должен вывести 3.22. В многостадийной сборке области видимости требуют отдельного внимания; наличие аргумента в одной независимой стадии не означает, что он доступен в другой.
Секрет не является build argument
Токен нельзя безопасно скрыть, просто назвав его ARG и удалив файл позднейшим RUN. Значения могут остаться в истории, метаданных или более ранних слоях. Для доступа сборки к приватному ресурсу BuildKit поддерживает secret mount. Он временно предоставляет файл конкретному RUN, но не мешает самой команде случайно вывести или скопировать секрет. Передача build secrets.
Проверим механизм фиктивным, несекретным значением. Создайте Dockerfile.secret:
# syntax=docker/dockerfile:1
FROM alpine:3.22
RUN --mount=type=secret,id=demo,required=true test -s /run/secrets/demo && echo secret-mounted
CMD ["sh", "-c", "test ! -e /run/secrets/demo && echo secret-not-in-image"]В Bash:
DEMO_BUILD_TOKEN=training-only docker build --secret id=demo,env=DEMO_BUILD_TOKEN -f Dockerfile.secret -t dk-secret:1 .
docker run --rm dk-secret:1Сборка покажет secret-mounted, контейнер — secret-not-in-image. Содержимое переменной не печатается. В реальной команде секрет читается утилитой из /run/secrets/demo; нельзя делать cat ради отладки, писать его в итоговый файл или включать shell tracing. Secret mount не заменяет проверку того, какие файлы сохраняет инструмент.
Кэш и частые ошибки
Если сборка сообщает, что secret не найден, проверьте совпадение id в RUN и CLI и наличие переменной в окружении вызывающего процесса. Изменение значения секрета само по себе не обязано инвалидировать кэш шага: для необходимого повторного запроса управляйте кэшем отдельно, не публикуя токен в аргументе ради этой цели.
Практика
Добавьте несекретный ARG EDITION=community и сохраните его рядом с RELEASE. Передайте два --build-arg, затем переопределите только APP_MODE при run. Объясните, какие изменения требуют сборки, а какие — нового контейнера. Дополнительно выполните docker image history dk-args:1 и docker image inspect dk-args:1: это помогает увидеть, почему метаданные образа нельзя считать тайным хранилищем.