Как собрать Docker-образ из Dockerfile: команда docker build и её ключевые параметры | AdminWiki

Как собрать Docker-образ из Dockerfile: команда docker build и её ключевые параметры

26 сентября 2026 8 мин. чтения

Что делает docker build и когда её использовать

Команда docker build собирает образ из двух частей: файла Dockerfile с инструкциями и контекста сборки, то есть набора файлов, доступных сборщику. Она читает Dockerfile сверху вниз, выполняет каждую инструкцию в отдельном слое и сохраняет результат в локальном хранилище образов. В типовой установке Docker по умолчанию работает сборщик BuildKit: он параллелит независимые шаги, аккуратнее использует кэш и печатает компактный лог.

Запуск выглядит так:

docker build -t myapp:latest .

Точка в конце - это контекст сборки, текущая директория. Всё, что лежит в ней, отправляется на демон Docker и может попасть в образ через COPY или ADD. Имя и тег задаёт флаг -t. После успешной сборки образ появляется в списке docker images под этим тегом.

Минимальный Dockerfile и первая сборка

Самый короткий рабочий пример из трёх инструкций:

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl
CMD ["bash"]

Разбор по строкам:

  • FROM ubuntu:22.04 задаёт базовый образ и наследует его файлы и настройки. Без FROM не обходится ни один Dockerfile - как Docker описывает наследование базового образа.
  • RUN выполняет команду в слое поверх базового образа. Здесь мы обновляем индексы пакетов и ставим curl.
  • CMD задаёт команду по умолчанию, которая запускается при старте контейнера.

Сохраните файл как Dockerfile в текущей директории и соберите образ:

docker build -t myapp:latest .

После завершения проверьте результат командой docker images. В списке появится строка с репозиторием myapp, тегом latest, идентификатором IMAGE ID, временем создания и размером.

Контекст сборки: что попадает в образ

docker build отправляет демону весь контекст, а не только Dockerfile. Если в директории лежат node_modules, .git или .env с секретами, они уйдут в сборку, и COPY сможет их прочитать. Отсекает их не .gitignore, а .dockerignore.

Создайте .dockerignore рядом с Dockerfile:

.git
node_modules
.env
*.log

Каждая строка - шаблон для исключения. Файлы и папки из .dockerignore не отправляются в контекст, поэтому COPY и ADD их просто не видят. Так вы одновременно ускоряете сборку (контекст меньше) и снижаете риск утечки секретов в слой. Правило простое: если файл не нужен внутри образа, добавьте его в .dockerignore.

Ключевые параметры docker build: -t, -f, --build-arg, --no-cache

Четыре флага закрывают большинство ежедневных сценариев: имя образа, выбор Dockerfile, передачу переменных и управление кэшем. Разберём каждый с примером.

Как задать имя и тег через -t

Флаг -t (длинная форма --tag) присваивает образу имя в формате name:tag. Без явного тега Docker подставит latest.

docker build -t registry.example.com/team/myapp:1.0.0 .

Здесь registry.example.com/team/myapp - имя репозитория, 1.0.0 - тег. Тег участвует в docker run и docker push, поэтому задавайте осмысленные версии, а не складывайте всё в latest. Один образ можно тегировать несколько раз, повторно запуская сборку с другим -t.

Указание альтернативного Dockerfile через -f

Если в проекте несколько Dockerfile, например для dev и prod, выберите нужный флагом -f:

docker build -f docker/Dockerfile.prod -t myapp:prod .

Путь к Dockerfile указывается относительно контекста, а сам контекст передаётся целиком. Поэтому .dockerignore нужен и при -f: без него весь проект уйдёт на демон, даже когда собирается один prod-файл.

Передача переменных через --build-arg

Переменные, объявленные в Dockerfile через ARG, принимают значения из командной строки. В Dockerfile:

FROM ubuntu:22.04
ARG VERSION=dev
RUN echo "build $VERSION"

Команда сборки:

docker build --build-arg VERSION=1.2 -t myapp .

ARG действует только на этапе сборки и не сохраняется в окружении контейнера. ENV, наоборот, попадает в образ и доступна процессу во время работы. Разница принципиальна при работе с секретами.

Не передавайте пароли, токены и ключи через --build-arg. Значение сохраняется в истории образа и видно в docker history, поэтому любой, у кого есть образ, прочитает секрет. Для чувствительных данных используйте BuildKit secrets: они монтируются на время шага и не оседают в слоях.

Отключение кэша через --no-cache

Docker кэширует каждый слой и при повторной сборке переиспользует их, если инструкция и входные файлы не изменились. Иногда кэш мешает получить свежий результат, и сборку запускают заново:

docker build --no-cache -t myapp .

Флаг отключает кэш для всех шагов, поэтому сборка идёт дольше. Точечно сбросить кэш можно, изменив саму инструкцию или обновив базовый образ флагом --pull. Применяйте --no-cache осознанно: когда подозреваете, что слой устарел, или собираете релиз с нуля.

Как читать вывод сборщика и находить ошибки

Лог сборки читается сверху вниз и заканчивается либо идентификатором нового образа, либо сообщением об ошибке. Научитесь различать эти два финала, и диагностика займёт минуты.

Структура вывода BuildKit: шаги, слои, кэш

Каждый шаг соответствует одной инструкции Dockerfile. BuildKit помечает статусы:

  • CACHED - слой взят из предыдущей сборки, шаг не выполнялся.
  • DONE - шаг выполнен, слой создан.
  • ERROR - шаг завершился с ошибкой, сборка остановлена.

Пример фрагмента лога:

=> [2/3] RUN apt-get update && apt-get install -y curl
=> CACHED [3/3] CMD ["bash"]
=> exporting to image
=> => naming to docker.io/library/myapp:latest

CACHED на шаге RUN означает, что команда не запускалась: BuildKit нашёл готовый слой. Чтобы принудительно пересобрать, используйте --no-cache. Независимые шаги BuildKit выполняет параллельно, поэтому строки в логе могут идти не в том порядке, что инструкции в Dockerfile.

Типичные ошибки и как их исправлять

COPY failed: file not found. Путь в COPY не совпадает с расположением файла в контексте либо файл исключён через .dockerignore. Проверьте относительный путь и список исключений.

The command '/bin/sh -c ...' returned a non-zero code. Ошибка внутри RUN. Запустите команду вручную в контейнере на базовом образе, чтобы увидеть полный вывод:

docker run --rm -it ubuntu:22.04 bash

failed to solve: process "/bin/sh -c ..." did not complete successfully. Общая формулировка BuildKit, причина всегда в строках выше. Смотрите на последний ERROR и вывод команды под ним.

Ошибка при --build-arg. ARG в Dockerfile не объявлена либо в имени аргумента опечатка. Docker молча пропустит неизвестный аргумент, и значение не подставится.

Алгоритм: найдите шаг со статусом ERROR, откройте соответствующую инструкцию Dockerfile, воспроизведите команду вручную в контейнере базового образа. Так вы отделяете ошибку в самой команде от проблемы с контекстом или правами.

Проверка результата: docker images и запуск контейнера

Сборка без ошибок ещё не доказывает, что образ корректен. Проверьте наличие, тег, а затем запустите контейнер в изолированной среде.

Как проверить образ через docker images

Команда выводит таблицу с колонками REPOSITORY, TAG, IMAGE ID, CREATED, SIZE. Формат вывода:

REPOSITORYTAGIMAGE IDCREATEDSIZE
myapplatesta1b2c3d4e5f62 minutes ago142MB
ubuntu22.04f1e2d3c4b5a63 weeks ago77.9MB

Сверьте тег и размер. Большой размер часто указывает на лишние слои или неочищенный кэш пакетов. Детали по образу покажет docker image inspect: конфигурацию, переменные окружения, точку входа и слои. Разбор слоёв и поиск «лишнего веса» с dive и inspect мы описали в отдельном руководстве. Если образа в списке нет, проверьте, не перезаписал ли тег другой запуск сборки.

Безопасный запуск контейнера из собранного образа

Быстрая проверка в интерактивном режиме:

docker run --rm -it myapp:latest bash

Флаг --rm удаляет контейнер после выхода, -it даёт интерактивный терминал. Такой запуск не публикует порты и не трогает файловую систему хоста, поэтому прод не пострадает.

Для веб-приложения опубликуйте порт и проверьте ответ:

docker run -d -p 8080:80 myapp:latest
curl -I http://localhost:8080

Осторожнее с флагом -v: смонтированный с хоста каталог контейнер может изменить или удалить. Публикация портов открывает сервис наружу, поэтому не выставляйте тестовые контейнеры в интернет. В продакшене запускайте процесс от непривилегированного пользователя, а не от root.

Практические рекомендации и чек-лист перед сборкой

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

Безопасность сборки: секреты и непривилегированный пользователь

Секреты не передавайте через --build-arg: значения остаются в истории образа. Для паролей и токенов используйте BuildKit secrets, они не сохраняются в слоях.

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

FROM ubuntu:22.04
RUN useradd -m -s /bin/bash agent
USER agent
CMD ["bash"]

Инструкция USER agent переключает контекст, и процесс контейнера идёт без прав root. Похожий подход применяют в sandbox-образах Docker: они основаны на Ubuntu и работают от непривилегированного пользователя agent с доступом sudo - как это устроено в базовых образах Docker. При установке системных пакетов сначала работают от root, а затем возвращаются к agent, иначе файлы окажутся в /root/, куда пользователь не имеет доступа.

Запуск от root расширяет поверхность атаки: при компрометации контейнера процесс получит больше возможностей внутри него. Готовый чек-лист с командами для защиты контейнеров, включая сканирование образов и запуск без root, собран в материале по безопасности Docker-контейнеров.

Воспроизводимость и кэширование

Фиксируйте версии базовых образов и пакетов. FROM ubuntu:22.04 даёт предсказуемый результат, а FROM ubuntu:latest в один день может принести новую версию и сломать сборку.

Порядок инструкций влияет на кэш. Сначала копируйте файлы зависимостей, ставьте зависимости, и только потом копируйте код:

COPY package.json package-lock.json ./
RUN npm ci
COPY . .

При правке кода слой с npm ci берётся из кэша, и сборка остаётся быстрой. Если поменять порядок, каждая правка кода потянет за собой переустановку зависимостей.

Флаг --pull заставляет заново скачать базовый образ, что помогает не пропустить обновление безопасности. Для уменьшения размера используйте многоэтапную сборку: компилятор и исходники остаются в промежуточном этапе, а в финальный образ копируется только результат. Пошаговый разбор многоэтапной сборки и работы с кэшем мы собрали в гайде по сборке Docker-образа.

Чек-лист перед сборкой:

  1. Создан .dockerignore с .git, .env, node_modules и логами.
  2. Тег задан через -t, версия осмысленна.
  3. Для нескольких Dockerfile используется -f.
  4. Секреты не передаются через --build-arg.
  5. При подозрении на устаревший слой применяется --no-cache.
  6. Результат проверен через docker images и docker image inspect.
  7. Тестовый контейнер запущен с --rm, лишние порты не опубликованы.

После проверки перенесите команды в CI/CD и зафиксируйте версии так, чтобы результат повторялся на любой машине. Переход от ручной сборки к воспроизводимой в dev, test и prod разобран в руководстве по воспроизводимым Docker-образам.

Поделиться: