Множественные build context в Docker

TL;DR
Docker BuildKit (v0.8+) позволяет указывать несколько build context при сборке образа через docker buildx. Это даёт возможность подключать файлы из разных директорий, удалённых репозиториев или других образов без изменения Dockerfile. Обновите Docker до 20.10.13+, используйте синтаксис Dockerfile v1.4 и флаг –build-context.
Быстрые ссылки
- Цель build context
- Использование нескольких build context
- Приоритет разрешения ресурсов
- Удалённые URL и источники
- Монтирование файлов из build context
- Точное пересоздание образов
- Когда это не сработает
- Метод и контрольные списки
- Заключение
Введение
Концепция “build context” в Docker — одна из самых ограничивающих и часто неправильно понимаемых. Build context определяет локальные файлы и папки, к которым Dockerfile может обратиться во время сборки. Всё, что находится вне этого контекста, недоступно сборщику, что осложняет реализацию сложных процессов сборки.
BuildKit версии 0.8 улучшает ситуацию: теперь можно использовать несколько именованных контекстов в одной сборке. Это упрощает обращение к зависимостям, расположенным в разных местах: в рабочем каталоге проекта, в соседних папках, в форке на GitHub или даже в другом Docker-образе.
Далее мы подробно рассмотрим, зачем нужны множественные контексты, как их настроить и какие сценарии они решают. В конце — практические чеклисты, рекомендации по безопасности и примеры, когда этот подход не подходит.
Цель build context
Пояснение в одну строку: build context — это набор файлов, который Docker-клиент отправляет демон-строителю для выполнения инструкций Dockerfile.
Docker использует архитектуру с демоном: процесс сборки может выполняться на удалённой машине, которой нет прямого доступа к вашей локальной файловой системе. Поэтому при запуске сборки клиент передаёт выбранный контекст (обычно содержимое каталога) демону.
Обычно разработчики запускают сборку с текущей директорией как build context:
.docker build -t my-website:latest .Это позволяет ссылаться на любые файлы внутри рабочего каталога, например:
FROM httpd:latest
COPY index.html /var/www/html/index.htmlОднако при попытке скопировать файл из родительской директории вы получите ошибку, потому что он вне контекста:
FROM httpd:latest
COPY ../company-css/company.css /var/www/html/company.cssВывод: все файлы, которые нужны для изображения контейнера, должны находиться под одной директорией, выбранной как build context. Взаимодействие с внешними зависимостями требует обходных решений — до появления множественных контекстов это было неудобно.
Использование нескольких build context
Ключевые требования
- BuildKit 0.8 или новее.
- Docker CLI 20.10.13 и новее (поддержка синтаксиса Dockerfile v1.4).
- Использование docker buildx build вместо docker build (legacy builder не поддерживает эту функцию).
Пример команды с buildx:
$ docker buildx build -t my-website:latest .Добавляем именованные контексты через –build-context:
$ docker buildx build -t my-website:latest . \
--build-context company-css=../company-css \
--build-context company-js=../company-jsВ Dockerfile используйте синтаксис v1.4 и указывайте –from, чтобы скопировать файлы из этих контекстов:
#syntax=docker/dockerfile:1.4
FROM httpd:latest
COPY index.html /var/www/html/index.html
COPY --from=company-css /company.css /var/www/html/company.css
COPY --from=company-js /company.js /var/www/html/company.jsЭто позволяет включать файлы, лежащие за пределами основного контекста, независимо от их положения в файловой системе.
Важно: строка с декларацией синтаксиса (#syntax=…) обязательна для активации функциональности Dockerfile v1.4.
Приоритет разрешения ресурсов
Алгоритм разрешения ключей, переданных в –from, теперь выглядит так (в порядке приоритета):
- Ищется именованный build context, заданный через –build-context.
- Ищется предыдущая стадия сборки, объявленная в Dockerfile как “FROM … AS stage-name”.
- Если ничего не найдено, BuildKit создаёт inline-стадию с указанным ключом как образом (попытка интерпретировать значение как имя образа).
Следствие: вы можете переопределять удалённые зависимости локальными контекстами. Пример:
#syntax=docker/dockerfile:1.4
FROM my-org/company-scss:latest AS css
RUN sass company.scss company.css
FROM httpd:latest
COPY index.html /var/www/html/index.html
COPY --from=css /company.css /var/www/html/company.cssЧтобы протестировать локальную правку, определите контекст с именем css:
$ docker buildx build -t my-website:latest . --build-context css=css/Теперь BuildKit возьмёт файл css/company.css из локального каталога вместо сборки/пуллинга image my-org/company-scss:latest.
Также можно указать контекст с именем, совпадающим с image reference, чтобы переопределить содержимое registry образа:
$ docker buildx build -t my-website:latest . --build-context my-org/company-scss:latest=css/Удалённые URL и поддерживаемые источники
Именованные контексты поддерживают те же типы источников, что и docker build:
- Локальная папка: –build-context my-context=../local/path
- Git-репозиторий: –build-context my-context=https://github.com/user/repo.git
- Удалённый tarball: –build-context my-context=https://example.com/data.tar
- Содержимое другого Docker-образа: –build-context my-context=docker-image://busybox:latest
Практическое применение: указывать форк репозитория или фиксированный тарбол — не меняя Dockerfile — для быстрой подмены зависимостей.
Монтирование файлов из build context в RUN
Именованные контексты работают и с инструкциями RUN: можно смонтировать содержимое другого контекста во время выполнения команды.
#syntax=docker/dockerfile:1.4
RUN --mount=from=name-of-build-context demo-executableТакой монт не копирует файлы в слой образа — это снижает размер итогового образа и ускоряет сборку. При этом монтируемый исполняемый файл не попадёт в финальный образ, если вы не выполните явные COPY/ADD.
Точное пересоздание образов
Проблема
Docker-теги (например, alpine:3.15) не являются константными: образ, доступный по тегу, со временем может сменить хэши слоёв (патчи, фиксы). Это мешает детерминированному воспроизведению образа.
Решение с использованием buildx imagetools
- Инспектируйте метаинформацию сборки, чтобы получить данные о точном образе (sha256) базы:
$ docker buildx imagetools inspect --format '{{json .BuildInfo}}' my-image:latestВо входных данных вы увидите блок “sources” с типом docker-image и полем “pin” — этот sha256 точно указывает образ, использованный при сборке.
- Определите именованный build context, который указывает на конкретный sha-образ:
$ docker buildx build -t my-image:latest . --build-context alpine:3.15=docker-image://alpine3.15@4edbd2beb5f78b1014028f4fbb99f3237d9561100b6881aabbf5acce2c4f9454Таким образом вы можете заново собрать образ с точно теми же заинтересованными слоями, не внося правки в Dockerfile.
Когда это не сработает (примеры и ограничения)
Сценарии с секретами: build context не предназначен для безопасного хранения секретов. Нельзя полагаться на то, что контекст закрепляет секреты от утечек — лучше использовать секреты BuildKit (RUN –mount=type=secret) или специализированные секрет-менеджеры.
Ограничения прав доступа: если демон сборки находится в окружении, где нет сетевого доступа к удалённым ресурсам, указание удалённого URL не сработает.
Совместимость старых инструментов: legacy docker build не распознаёт –build-context. Если CI использует старую версию Docker, функциональность будет недоступна.
Большие удалённые контексты: скачивание большого tarball или клона репозитория может замедлить сборку и потребовать дополнительного места.
Файлы вне контекста по времени жизни: если локальный контекст указывает на временные файлы, пересборка в другом окружении не сможет воспроизвести их.
Альтернативные подходы
Multi-stage builds (без именованных контекстов): используйте предыдущие стадии как источник файлов, но это требует включения всех зависимостей в Dockerfile.
Сводный monorepo: переместить все зависимости в один репозиторий/дерево (может быть громоздко и не всегда возможно).
CI-артефакты: публикуйте готовые артефакты в реестр/хранилище и ссылаться на них как на docker-image или tarball.
Использование bind-mount/volume в рантайме (не подходит для сборки): полезно при локальной разработке, но не для создания образа.
Ментальные модели и эвристики
- Контекст = «пакет» файлов, который попадёт в демон. Всё остальное — недоступно.
- Именованный контекст = alias, который можно направлять на любую поддержку (локально, git, tar, образ).
- –from в COPY/ADD — это универсальный путь разрешения: сначала локальный build-context, потом стадия, потом образ.
Пользуйтесь простыми именами контекстов, которые отражают назначение (css, deps, base-image), чтобы тестирование и CI оставались понятными.
Мини-методология: как безопасно вводить множественные контексты в проект
- Обновите Docker CLI до 20.10.13+ и убедитесь в наличии BuildKit 0.8+.
- Добавьте в Dockerfile строку: #syntax=docker/dockerfile:1.4
- Локально протестируйте сборку с –build-context, указывая локальные каталоги для критичных зависимостей.
- Обновите CI-конфигурацию: убедитесь, что runner использует buildx и поддерживает BuildKit.
- Для production-пересборок фиксируйте base image через docker-image@sha256 и используйте его как build context для детерминированности.
- Документируйте используемые имена контекстов в README и CI.
Рекомендации по безопасности и конфиденциальности
- Не включайте секреты или приватные ключи в build context. Для секретов используйте BuildKit secrets (RUN –mount=type=secret) или внешние секрет-менеджеры.
- Контролируйте доступ к удалённым URL: если вы указываете приватный git-репозиторий, настройте доступ в CI и убедитесь, что токены не попадают в логи.
- При использовании docker-image:// источников учитывайте, что образ может содержать нежелательные файлы — проверяйте доверенные источники.
Важно: build context — это транспорт для файлов, а не механизм политик доступа. Политику безопасности реализуйте на уровне CI и хранения секретов.
Контрольные списки (роль: разработчик / инженер CI / ревьюер)
Разработчик
- Добавил #syntax=docker/dockerfile:1.4 в Dockerfile
- Локально протестировал сборку с –build-context
- Проверил, что финальный образ не содержит временных/секретных файлов
- Документировал используемые контексты в README
Инженер CI
- Runner использует docker buildx и BuildKit 0.8+
- CI-пропуск для приватных git-репозиториев настроен
- Фиксированы версии образов для reproducible builds (sha256)
- Логи сборки не содержат секретов
Ревьюер PR
- Dockerfile не импортирует ненужные большие артефакты
- Имена –build-context понятны и документированы
- Нет включения приватных данных в контексты
Decision flow (Mermaid)
flowchart TD
A[Нужно подключить файл/зависимость] --> B{Файл в рабочем дереве?}
B -- Да --> C[Добавить в основной контекст или COPY]
B -- Нет --> D{Можно ли поместить в локальный контекст?}
D -- Да --> E[Использовать --build-context с локальным путём]
D -- Нет --> F{Источник — git / tar / образ?}
F -- git --> G[--build-context myctx=https://github.com/...]
F -- tar --> H[--build-context myctx=https://example.com/data.tar]
F -- image --> I[--build-context myctx=docker-image://busybox:latest]
G --> J[Тестировать сборку]
H --> J
I --> J
C --> J
E --> J
J --> K[CI: установить buildx и фиксировать версии]Критерии приёмки
- Dockerfile содержит #syntax=docker/dockerfile:1.4.
- Сборка проходит в локальном окружении и в CI с одинаковыми контекстами.
- Все внешние зависимости явно задокументированы в конфигурации сборки.
- При необходимости произведено закрепление образов через sha256 для детерминированности.
Примеры тест-кейсов
- Локальная подмена зависимости
- Указать –build-context css=css/
- Убедиться, что финальный образ содержит локальную company.css
- Подмена образа base
- Использовать –build-context my-org/company-scss:latest=css/
- Проверить, что содержимое, которое ранее подтягивалось из registry, заменено
- Поведение при отсутствии сети
- Запустить сборку с удалённым git-контекстом в среде без доступа в интернет — ожидается ошибка
- Секреты
- Убедиться, что переменные окружения и файлы с ключами не попадают в тарбол контекста
Заключение
Множественные build context в Docker BuildKit — мощный инструмент для организации сложных процессов сборки. Они позволяют:
- Подключать файлы из разных директорий и удалённых источников без модификации Dockerfile.
- Переопределять зависимости для локальной отладки.
- Фиксировать исходные образы для воспроизводимости сборок.
Используйте эту функциональность аккуратно: документируйте контексты, не храните секреты в контексте и проверяйте CI-настройки. Начать можно уже сегодня, обновив Docker до версии 20.10.13+ и переключившись на docker buildx.
Похожие материалы
Unity Lights: циферблат Apple Watch для Black History Month
Обновление видеодрайвера для Rainbow Six Siege
Ограничение частоты запросов в ASP.NET Core
Исправление лагов Android: TRIM и LagFix
Семафоры в Bash: что это и как реализовать