Длинный RUN стал нечитаемым: многострочный шаг через heredoc Dockerfile
В Dockerfile накопился RUN на двадцать строк с обратными слешами. После очередной правки один перенос исчез, комментарий оказался частью команды, а причину ошибки трудно увидеть в diff. Для связанного многострочного шага современный Dockerfile поддерживает heredoc: тело команды записывается отдельными строками между двумя маркерами.
Польза здесь в читаемости и явном управлении shell, а не в создании нового механизма выполнения. Команды внутри всё равно исполняются во время сборки одной RUN-инструкцией. Если ранняя операция завершилась с ошибкой, последняя успешная команда не должна скрывать её результат.
Один шаг с явным режимом ошибок
Сохраните пример как Dockerfile. Он создаёт текстовый manifest внутри образа и проверяет его содержимое до завершения сборочного шага.
# syntax=docker/dockerfile:1
FROM alpine:3.22
RUN <<'BUILD'
set -eu
mkdir -p /opt/demo
printf '%s\n' 'component=reporter' 'format=1' > /opt/demo/manifest.txt
test -s /opt/demo/manifest.txt
grep -Fx 'format=1' /opt/demo/manifest.txt
BUILD
CMD ["cat", "/opt/demo/manifest.txt"]
Соберите образ командой docker build -t heredoc-demo ., затем вызовите docker run --rm heredoc-demo. В выводе должны быть component=reporter и format=1. Проверка grep внутри RUN подтверждает, что нужная строка появилась до создания итогового образа.
Маркер BUILD в завершающей строке должен стоять отдельно. Кавычки в открывающем маркере управляют раскрытием heredoc при передаче тела. Для сложных сочетаний Dockerfile-подстановки и shell-переменных сначала проверьте маленький пример: совпадающее написание $NAME ещё не говорит, какой уровень его обработает.
Shell внутри образа нужно знать
По умолчанию Linux RUN использует /bin/sh -c, а Alpine обычно предоставляет ash. Bash-массивы и другие Bash-расширения не становятся доступными от появления heredoc. Если сборочный шаг действительно требует Bash, установите нужный интерпретатор и явно выберите его. Но для создания нескольких файлов и простых проверок POSIX-синтаксиса обычно достаточно.
set -eu в примере подходит для последовательности простых команд: незаданные переменные и неуспешные команды должны остановить шаг. Сложные условия, функции и pipeline требуют собственного разбора статусов. Не считайте, что heredoc вместе с set -e автоматически делает надёжным произвольный shell-сценарий.
Весь RUN остаётся одной единицей кэширования. Изменение одной строки тела может потребовать повторить весь шаг. Если часть работы тяжёлая и зависит от другого набора входов, разделите инструкции по реальным зависимостям. Удобство многострочной записи не должно собирать установку зависимостей, копирование кода и выпуск пакета в один бесконтрольный блок.
Когда вынести скрипт в файл
Если шаг нужно запускать локально, проверять линтером и использовать в CI отдельно от Docker, обычный shell-файл в репозитории часто удобнее heredoc. Его можно скопировать в стадию и выполнить. Тогда Dockerfile описывает сборочную последовательность, а длинная предметная логика остаётся в инструменте, который легко открыть и протестировать отдельно.
Heredoc хорошо подходит для короткой тесно связанной подготовки: создать каталог, записать конфигурацию, проверить результат. Назовите маркер по назначению, чтобы в длинном файле были видны границы блока. Не смешивайте несколько вложенных heredoc с одинаковым маркером: такая экономия букв ухудшает сопровождение.
Проверьте отрицательный случай: замените ожидаемую строку grep на отсутствующую. Сборка должна завершиться неуспешно. Этот опыт показывает, что проверка действительно участвует в результате RUN, а не просто украшает лог.
Откройте программу Docker для разработчика. Продолжение — строить понятные образы, где каждый сборочный шаг имеет определённый вход, проверяемый результат и предсказуемый отказ при поломанной подготовке.
Ещё по теме
Продолжить на практике
- Docker и Docker Compose: контейнеризация приложений ↗
Упакуйте приложение в Docker и запустите его с PostgreSQL через Compose. Образы, сети, тома, диагностика поломок, обновление версий и восстановление данных — с практикой и итоговым проектом.
