Линковка образов: dependencies и imports
Что нужно знать перед уроком
- M3.03 — Stapel-builder глубоко — нужно понимать оба билдера, чтобы связывать образы, собранные разными способами
Что нужно знать перед уроком
M3 уроки 1–3 — Dockerfile multi-stage, werf.yaml, Stapel-стадии. Здесь — ключевой механизм для Application с несколькими компонентами (backend+frontend Vikunja, или подобные auth+controlplane→app): как передать информацию об одном собранном образе в сборку другого.
Теория
dependencies/imports — три типа передаваемой информации через targetBuildArg
| |
dependencies в image:-блоке объявляет, от каких других image:-блоков того же werf.yaml зависит текущий образ. Для каждой зависимости imports указывает, какую информацию об уже собранном образе передать как build-аргумент (targetBuildArg) внутрь Dockerfile текущего образа:
| Тип | Что передаёт |
|---|---|
ImageName | полное имя образа в registry (repo без тега) |
ImageTag | тег образа |
ImageRepo | адрес репозитория |
ImageDigest | content-based дайджест (детерминированный хэш содержимого) |
werf гарантирует порядок: образ-зависимость (auth, controlplane) собирается раньше зависимого (app), причём одной командой werf build/werf converge — оркестрацию порядка сборки берёт на себя werf, вам не нужно вручную вызывать werf build auth && werf build controlplane && werf build app.
Паттерн «builder (Stapel) → app (Dockerfile) импортирует бинарник»
| |
| |
Здесь builder собирается через Stapel (с тонким контролем кэша по git.stageDependencies, изученным в M3 уроке 3), а финальный app — обычным Dockerfile-builder, который через ARG BUILDER_IMAGE/FROM ${BUILDER_IMAGE} AS builder получает имя уже собранного образа и копирует из него бинарник тем же механизмом COPY --from, что и в обычном multi-stage build (M3 урок 1) — только теперь «стадии» физически разнесены по разным image:-блокам werf.yaml, а не находятся в одном Dockerfile.
Паттерн «несколько независимых образов → общий сборочный контекст»
Это ключевой механизм для Application с несколькими компонентами в одном пакете: если у вас, например, отдельно собираются auth и controlplane (разные Dockerfile/контексты), а финальный app должен знать оба их имени и дайджеста (например, чтобы встроить их в собственный манифест или конфигурацию инициализации) — dependencies позволяет объявить сразу несколько зависимостей в одном image:-блоке, каждая со своим набором imports. Именно такая структура применима к Vikunja: backend и frontend — независимые образы, но если бы нужен был третий «оркестрирующий» образ (например, nginx с обоими встроенными статик-раздачами), он объявил бы зависимости от обоих.
Расширение multi-stage за пределы одного Dockerfile
dependencies/imports — это концептуальное расширение multi-stage build (M3 урок 1) за пределы одного файла: обычный COPY --from=builder работает только внутри одного Dockerfile с несколькими FROM; werf позволяет линковать произвольные образы, определённые в werf.yaml, включая образы, собранные разными билдерами (Stapel и Dockerfile) и из разных Git-контекстов — оркестрацию порядка и передачу метаданных берёт на себя werf, а не сам Docker.
Частые ошибки и подводные камни
- Забыть, что
ARGв Dockerfile должен быть объявлен ДОFROM, если используется в самомFROM.ARG BUILDER_IMAGEпередFROM ${BUILDER_IMAGE}— стандартное ограничение синтаксиса Dockerfile (build-аргументы, используемые вFROM, требуют объявленияARGдо первогоFROM, использующего эту переменную), не специфичное для werf, но легко забываемое при первой линковке. - Путать
ImageName(без тега) сImageTag/полным адресом. Для гарантированной адресации конкретного собранного контента обычно нужен именноImageDigest(детерминированный хэш) в сочетании сImageName, а не просто имя — иначе можно случайно получить не тот вариант образа при параллельных сборках разных веток. - Пытаться линковать образы напрямую через
docker build --build-argвместоdependencies/imports. Это лишает werf возможности гарантировать правильный порядок сборки и автоматически подставлять актуальные значения дайджестов/имён.
Практика в кластере
Практики в кластере в этом уроке нет — фокус на линковке образов на этапе сборки, деплой связанных образов — начиная с M4.
Практика разработки
- Расширьте
werf.yamlVikunja так, чтобы финальныйnginx-образ, раздающий frontend, знал имя и дайджест собранногоbackend-образа (для примера — как если бы nginx-конфигурация встраивала адрес backend’а на этапе сборки, а не через runtime-переменные):
| |
- Соберите все три образа одной командой и понаблюдайте за порядком:
| |
Обратите внимание, что backend и frontend собираются (порядок между ними не гарантирован, т.к. они не зависят друг от друга), а nginx — строго после backend, т.к. явно от него зависит.
Шпаргалка команд урока
| |
| |
Вопросы для самопроверки
Четыре типа: ImageName (имя без тега), ImageTag, ImageRepo (адрес репозитория), ImageDigest (content-based хэш).
Источник: Werf — документация — Linking images
werf берёт на себя оркестрацию порядка сборки на основе графа dependencies, не требуя ручных последовательных вызовов.
Источник: Werf — документация
Механизм dependencies/imports работает на уровне уже собранных образов (имя/тег/дайджест), билдер, которым образ был собран, не важен для линковки.
ImageName без указания конкретного контента не гарантирует, какая именно версия образа имеется в виду; ImageDigest указывает точно на конкретный собранный контент.
Источник: Werf — документация
Стандартное ограничение синтаксиса Dockerfile: build-аргументы, используемые непосредственно в FROM, требуют объявления ARG до первого использующего их FROM.
Источник: Docker — документация
Рекомендуемая литература
Официальная документация
Статьи и блоги
- werf v1.2 — стабильный релиз утилиты для доставки приложений в Kubernetes (Stapel) — Flant на Habr.
- Первые шаги с werf: собираем и деплоим простое приложение — Flant на Habr.
- GitLab + K8s + Werf — Habr.
Книги
- Nigel Poulton. Docker Deep Dive. 2023. ISBN 978-1916585206.
Связанные материалы
- Предыдущий урок: M3.03 — Stapel-builder глубоко.
- Следующий урок: M3.05 — Stapel-импорт.
- Продвинутое использование этого же механизма: M8 урок 1 — Линковка образов вглубь.
✓ Урок пройден — все вопросы самопроверки отвечены верно