Линковка образов: dependencies и imports

Уровень: advanced ~55 мин Практика: Vikunja (AGPL-3.0)

Что нужно знать перед уроком

  • M3.03 — Stapel-builder глубоко — нужно понимать оба билдера, чтобы связывать образы, собранные разными способами

Что нужно знать перед уроком

M3 уроки 1–3 — Dockerfile multi-stage, werf.yaml, Stapel-стадии. Здесь — ключевой механизм для Application с несколькими компонентами (backend+frontend Vikunja, или подобные auth+controlplaneapp): как передать информацию об одном собранном образе в сборку другого.

Теория

dependencies/imports — три типа передаваемой информации через targetBuildArg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
image: app
dockerfile: Dockerfile
dependencies:
  - image: auth
    imports:
      - type: ImageName
        targetBuildArg: AUTH_IMAGE_NAME
      - type: ImageDigest
        targetBuildArg: AUTH_IMAGE_DIGEST
  - image: controlplane
    imports:
      - type: ImageName
        targetBuildArg: CONTROLPLANE_IMAGE_NAME
      - type: ImageDigest
        targetBuildArg: CONTROLPLANE_IMAGE_DIGEST

dependencies в image:-блоке объявляет, от каких других image:-блоков того же werf.yaml зависит текущий образ. Для каждой зависимости imports указывает, какую информацию об уже собранном образе передать как build-аргумент (targetBuildArg) внутрь Dockerfile текущего образа:

ТипЧто передаёт
ImageNameполное имя образа в registry (repo без тега)
ImageTagтег образа
ImageRepoадрес репозитория
ImageDigestcontent-based дайджест (детерминированный хэш содержимого)

werf гарантирует порядок: образ-зависимость (auth, controlplane) собирается раньше зависимого (app), причём одной командой werf build/werf converge — оркестрацию порядка сборки берёт на себя werf, вам не нужно вручную вызывать werf build auth && werf build controlplane && werf build app.

Паттерн «builder (Stapel) → app (Dockerfile) импортирует бинарник»

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
image: builder
from: golang
git:
  - add: /
    to: /app
shell:
  install:
    - cd /app
    - go build -o /app/bin/server
---
image: app
dockerfile: Dockerfile
dependencies:
  - image: builder
    imports:
      - type: ImageName
        targetBuildArg: BUILDER_IMAGE
1
2
3
4
5
6
# Dockerfile для образа app
ARG BUILDER_IMAGE
FROM ${BUILDER_IMAGE} AS builder
FROM alpine:3.22
COPY --from=builder /app/bin/server /usr/local/bin/server
ENTRYPOINT ["/usr/local/bin/server"]

Здесь 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.

Практика разработки

🧩 Практика урока: Vikunja · лицензия AGPL-3.0
  1. Расширьте werf.yaml Vikunja так, чтобы финальный nginx-образ, раздающий frontend, знал имя и дайджест собранного backend-образа (для примера — как если бы nginx-конфигурация встраивала адрес backend’а на этапе сборки, а не через runtime-переменные):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
project: vikunja
configVersion: 1
---
image: backend
dockerfile: Dockerfile
context: api/
---
image: frontend
from: node:24-alpine
git:
  - add: /frontend
    to: /app
shell:
  install:
    - cd /app && npm ci
  setup:
    - cd /app && npm run build
---
image: nginx
dockerfile: Dockerfile.nginx
context: frontend/
dependencies:
  - image: backend
    imports:
      - type: ImageName
        targetBuildArg: BACKEND_IMAGE_NAME
      - type: ImageDigest
        targetBuildArg: BACKEND_IMAGE_DIGEST
  1. Соберите все три образа одной командой и понаблюдайте за порядком:
1
werf build

Обратите внимание, что backend и frontend собираются (порядок между ними не гарантирован, т.к. они не зависят друг от друга), а nginx — строго после backend, т.к. явно от него зависит.

Шпаргалка команд урока

1
2
3
4
5
dependencies:
  - image: <image-name>
    imports:
      - type: ImageName|ImageTag|ImageRepo|ImageDigest
        targetBuildArg: <ARG_NAME>
1
2
werf build              # соберёт все image:-блоки в правильном порядке зависимостей
werf build <image-name>  # соберёт конкретный образ и всё, от чего он зависит

Вопросы для самопроверки

Какие типы информации можно передать через imports/targetBuildArg?

Четыре типа: ImageName (имя без тега), ImageTag, ImageRepo (адрес репозитория), ImageDigest (content-based хэш).

Источник: Werf — документация — Linking images

Гарантирует ли werf порядок сборки зависимых образов автоматически?

werf берёт на себя оркестрацию порядка сборки на основе графа dependencies, не требуя ручных последовательных вызовов.

Источник: Werf — документация

Можно ли линковать образ, собранный через Stapel, с образом, собранным через Dockerfile-builder?

Механизм dependencies/imports работает на уровне уже собранных образов (имя/тег/дайджест), билдер, которым образ был собран, не важен для линковки.

Источник: Werf — документация — пример builder(Stapel

Почему для гарантированной адресации конкретного собранного контента обычно предпочтителен ImageDigest, а не просто ImageName?

ImageName без указания конкретного контента не гарантирует, какая именно версия образа имеется в виду; ImageDigest указывает точно на конкретный собранный контент.

Источник: Werf — документация

Что нужно помнить про ARG в Dockerfile, если он используется прямо в инструкции FROM?

Стандартное ограничение синтаксиса Dockerfile: build-аргументы, используемые непосредственно в FROM, требуют объявления ARG до первого использующего их FROM.

Источник: Docker — документация

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Nigel Poulton. Docker Deep Dive. 2023. ISBN 978-1916585206.

Связанные материалы