Стадии импорта
import:
- artifact: <artifact name>
  image: <image name>
  stage: <stage name>
  before: <install  setup>
  after: <install  setup>
  add: <absolute path>
  to: <absolute path>
  owner: <owner>
  group: <group>
  includePaths:
  - <relative path or glob>
  excludePaths:
  - <relative path or glob>

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

Условный пример:

RUN “download-source && cmd && cmd2 && remove-source”

Аналогичный пример может быть реализован и в werf. Для этого достаточно описать инструкции в одной пользовательской стадии. Пример при использовании shell-сборщика для стадии install (аналогичен и для ansible-сборщика):

shell:
  install:
  - "download-source"
  - "cmd"
  - "cmd2"
  - "remove-source"

Однако при использовании такого метода кэширование работать не будет, и установка инструментов сборки будет выполняться каждый раз.

Другой способ — использование multi-stage сборки, которая поддерживается в Docker, начиная с версии 17.05.

FROM node:latest AS storefront
WORKDIR /app
COPY react-app .
RUN npm install
RUN npm run build

FROM maven:latest AS appserver
WORKDIR /app
COPY . .
RUN mvn package

FROM java:8-jdk-alpine
COPY --from=storefront /app/react-app/build/ /static
COPY --from=appserver /app/target/AtSea-0.0.1-SNAPSHOT.jar /app/AtSea.jar

Смысл такого подхода в следующем — описать несколько вспомогательных образов и выборочно копировать артефакты из одного образа в другой, оставляя все то, что не нужно в конечном образе.

werf предлагает такой-же подход, но с использованием образов и артефактов.

Почему werf не использует multi-stage сборку?

  • Исторически возможность импорта появилась значительно раньше, чем в Docker появилась multi-stage сборка.
  • werf дает больше гибкости при работе со вспомогательными образами.

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

  • image: <image name> или artifact: <artifact name>: исходный образ, имя образа из которого вы хотите копировать файлы или каталоги.
  • stage: <stage name>: стадия исходного образа, определённая стадия исходного образа, из которого вы хотите копировать файлы или каталоги.
  • add: <absolute path>: исходный путь, абсолютный путь к файлу или каталогу в исходном образе для копирования.
  • to: <absolute path>: путь назначения, абсолютный путь в образе назначения (куда импортируются файлы или каталоги). В случае отсутствия считается равным значению, указанному в параметре add.
  • before: <install || setup> or after: <install || setup>: стадия образа назначения для импорта. В настоящий момент возможен импорт только до/после стадии install или setup.

Пример:

import:
- artifact: application-assets
  add: /app/public/assets
  to: /var/www/site/assets
  after: install
- image: frontend
  add: /app/assets
  after: setup

Так же, как и при конфигурации git mappings, поддерживаются маски включения и исключения файлов и каталогов. Для указания маски включения файлов используется параметр include_paths: [], а для исключения exclude_paths: []. Маски указываются относительно пути источника (параметр add). Вы также можете указывать владельца и группу для импортируемых ресурсов с помощью параметров owner: <owner> и group: <group> соответственно. Это поведение аналогично используемому при добавлении кода из Git-репозиториев, и вы можете подробнее почитать об этом в соответствующем разделе.

Обратите внимание, что путь импортируемых ресурсов и путь указанный в git mappings не должны пересекаться.

Что такое артефакты?

Артефакт — это специальный образ, используемый в других артефактах или отдельных образах, описанных в конфигурации. Артефакт предназначен преимущественно для отделения ресурсов инструментов сборки от процесса сборки образа приложения. Примерами таких ресурсов могут быть — программное обеспечение или данные, которые необходимы для сборки, но не нужны для запуска приложения, и т.п.

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

  • Если приложение состоит из набора компонент, каждый со своими зависимостями, то обычно вам приходится пересобирать все компоненты каждый раз. Вам бы хотелось пересобирать только те компоненты, которым это действительно нужно.
  • Компоненты должны быть собраны в разных окружениях.

Импортирование ресурсов из артефактов указывается с помощью директивы import в конфигурации в секции образа или секции артефакта.

Конфигурация

Конфигурация артефакта похожа на конфигурацию обычного образа. Каждый артефакт должен быть описан в своей секции конфигурации.

Инструкции, связанные со стадией from (инструкции указания базового образа и монтирования), а также инструкции импорта точно такие же, как и при описании образа.

Стадия добавления инструкций Docker (docker_instructions) и соответствующие директивы недоступны при описании артефактов. Артефакт — это инструмент сборки, и все что от него требуется, это — только данные.

Остальные стадии и инструкции описания артефактов рассматриваются далее подробно.

Именование

artifact: string

Образ артефакта объявляется с помощью директивы artifact. Синтаксис: artifact: string. Так как артефакты используются только самим werf, отсутствуют какие-либо ограничения на именование артефактов, в отличие от ограничений [на именование обычных образов.

Пример:

artifact: "application assets"

Добавление исходного кода из Git-репозиториев

В отличие от обычных образов, у конвейера стадий артефактов нет стадий gitCache и gitLatestPatch.

В werf для артефактов реализована необязательная зависимость от изменений в Git-репозиториях. Таким образом, по умолчанию werf игнорирует какие-либо изменения в Git-репозитории, кэшируя образ после первой сборки. Но вы можете определить зависимости от файлов и каталогов, при изменении в которых образ артефакта будет пересобираться.

Читайте подробнее про работу с git-репозиториями в соответствующей статье.

Запуск инструкций сборки

У артефактов точно такое же, как и у обычных образов, использование директив и пользовательских стадий — beforeInstall, install, beforeSetup и setup.

Если в директиве stageDependencies в блоке Git для пользовательской стадии не указана зависимость от каких-либо файлов, то образ кэшируется после первой сборки и не будет повторно собираться, пока соответствующая стадия находится в stages storage.

Если необходимо повторно собирать артефакт при любых изменениях в Git, нужно указать stageDependency **/* для соответствующей пользовательской стадии. Пример для стадии install:

git:
- to: /
  stageDependencies:
    install: "**/*"

Читайте подробнее про работу с инструкциями сборки в соответствующей статье.

Использование артефактов

В отличие от обычного образа, у образа артефакта нет стадии git latest patch. Это сделано намеренно, т.к. стадия git latest patch выполняется обычно при каждом коммите, применяя появившиеся изменения к файлам. Однако артефакт рекомендуется использовать как образ с высокой вероятностью кэширования, который обновляется редко или нечасто (например, при изменении специальных файлов).

Пример: нужно импортировать в артефакт данные из Git, и пересобирать ассеты только тогда, когда изменяются влияющие на сборку ассетов файлы. Т.е. в случае изменения каких-либо других файлов в Git ассеты пересобираться не должны.

Конечно, существуют случаи, когда необходимо включать изменения любых файлов Git-репозитория в образ артефакта (например, если в артефакте происходит сборка приложения на Go). В этом случае необходимо указать зависимость относительно стадии (сборку которой необходимо выполнять при изменениях в Git) с помощью git.stageDependencies и * в качестве шаблона. Пример:

git:
- add: /
  to: /app
  stageDependencies:
    setup:
    - "*"

В этом случае любые изменения файлов в Git-репозитории будут приводить к пересборке образа артефакта и всех образов, в которых определен импорт этого артефакта.

Замечание: Если вы используете какие-либо файлы и при сборке артефакта, и при сборке обычного образа, правильный путь — использовать директиву git.add при описании каждого образа, где это необходимо, т.е. несколько раз. Нерекомендуемый вариант — добавить файлы при сборке артефакта, а потом импортировать их используя директиву import в другой образ.