Пользовательские стадии
shell:
  beforeInstall:
  - <bash command>
  install:
  - <bash command>
  beforeSetup:
  - <bash command>
  setup:
  - <bash command>
  cacheVersion: <arbitrary string>
  beforeInstallCacheVersion: <arbitrary string>
  installCacheVersion: <arbitrary string>
  beforeSetupCacheVersion: <arbitrary string>
  setupCacheVersion: <arbitrary string>
Запуск инструкций сборки при изменениях в git-репозитории Запуск инструкций сборки при изменениях в git-репозитории

Пользовательские стадии

Пользовательские стадии — это стадии со сборочными инструкциями из конфигурации. Другими словами — это стадии, конфигурируемые пользователем (существуют также служебные стадии, которые пользователь конфигурировать не может). Сборочные инструкции описываются с помощью shell.

werf поддерживает четыре пользовательские стадии, которые выполняются последовательно в следующем порядке: beforeInstall, install, beforeSetup и setup. В результате выполнения инструкций пользовательской стадии создается один Docker-слой. Т.е. по одному слою на каждую стадию вне зависимости от количества инструкций.

Использование пользовательских стадий

werf позволяет определять до четырех пользовательских стадий с инструкциями сборки. На содержание самих инструкций сборки werf не накладывает каких-либо ограничений, т.е. вы можете указывать все те же инструкции, которые указывали в Dockerfile в директиве RUN. Однако важно не просто перенести инструкции из Dockerfile, а правильно разбить их на пользовательские стадии. Исходя из опыта работы с реальными приложениями, мы пришли к заключению, что сборка большинства приложений проходит следующие этапы:

  • установка системных пакетов;
  • установка системных зависимостей;
  • установка зависимостей приложения;
  • настройка системных пакетов;
  • настройка приложения.

Какая может быть наилучшая стратегия выполнения этих этапов?

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

Подход с пользовательскими стадиями предлагает следующую стратегию:

  • использовать стадию beforeInstall для инсталляции системных пакетов;
  • использовать стадию install для инсталляции системных зависимостей и зависимостей приложения;
  • использовать стадию beforeSetup для настройки системных параметров и установки приложения;
  • использовать стадию setup для настройки приложения.
Как работает сборка стадий stapel

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

Перед запуском сборочного контейнера werf подготавливает набор инструкций, который зависит от типа стадии и содержит как служебные команды werf, так и пользовательские, указанные в конфигурации werf.yaml. Например, среди служебных команд может быть добавление файлов, наложение патчей и т.п.

Stapel-сборщик использует свой набор инструментов и библиотек и никак не зависит от базового образа. При запуске сборочного контейнера werf монтирует всё необходимое из специального служебного образа registry.werf.io/werf/stapel.

Для платформ linux/amd64 и linux/arm64 бинарь werf уже содержит этот Stapel-образ встроенным внутри себя, поэтому werf загружает его напрямую, а не тянет из registry — доступ к сети и registry.werf.io в этом случае не требуется, что позволяет работать «из коробки» в закрытых/изолированных окружениях. Если используется другая платформа, либо переопределена ссылка на Stapel-образ (см. ниже), werf, как и прежде, обращается к registry за образом.

Если окружение не может обращаться к этому образу напрямую, например в закрытом контуре или при использовании приватного registry, ссылку на служебный Stapel-образ можно переопределить перед запуском werf:

export WERF_STAPEL_IMAGE_NAME=registry.werf.io/werf/stapel
export WERF_STAPEL_IMAGE_VERSION=0.6.2

При использовании приватного registry:

  1. Задайте переменную окружения WERF_STAPEL_IMAGE_NAME со значением адреса репозитория Stapel-образа.
  2. Убедитесь, что в registry существует образ ${WERF_STAPEL_IMAGE_NAME}:${WERF_STAPEL_IMAGE_VERSION}.
  3. Убедитесь, что werf аутентифицирован в registry до начала сборки.

В сборочный контейнер пробрасывается сокет SSH-агента с хоста, а также могут использоваться пользовательские маунты.

Также стоит отметить, что при сборке werf игнорирует некоторые параметры манифеста базового образа, заменяя их определёнными значениями:

  • --user=0:0;
  • --workdir=/;
  • --entrypoint=/.werf/stapel/embedded/bin/bash.

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

docker run \
  --volume=/tmp/ssh-ln8yCMlFLZob/agent.17554:/.werf/tmp/ssh-auth-sock \
  --volumes-from=stapel_0.6.1 \
  --env=SSH_AUTH_SOCK=/.werf/tmp/ssh-auth-sock \
  --user=0:0 \
  --workdir=/ \
  --entrypoint=/.werf/stapel/embedded/bin/bash \
  sha256:d6e46aa2470df1d32034c6707c8041158b652f38d2a9ae3d7ad7e7532d22ebe0 \
  -ec eval $(echo c2V0IC14 | /.werf/stapel/embedded/bin/base64 --decode)

beforeInstall

shell:
  beforeInstall:
    - apt update -q
    - apt install -y curl mysql-client libmysqlclient-dev g++ build-essential libcurl4
  beforeInstallCacheVersion: "1"

Данная стадия предназначена для выполнения инструкций перед установкой приложения. Этот этап предназначен для системных приложений, которые редко изменяются, но требуют много времени для установки. Примером таких приложений могут быть языковые пакеты или инструменты сборки, такие как Composer, Java, Gradle и т.д. Также сюда можно добавлять инструкции настройки системы, которые редко изменяются. Например, языковые настройки, настройки часового пояса, добавление пользователей и групп.

Поскольку эти компоненты меняются редко, они будут кэшироваться в рамках стадии beforeInstall на длительный период.

beforeInstallCacheVersion: <string> — опциональная директива, которая позволяет инвалидировать сборочный кеш данной стадии детерминированным способом через Git.

install

shell:
  install:
    - bundle install
    - npm ci
  installCacheVersion: "1"

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

На данной стадии появляется доступ к исходному коду используемых Git-репозиториев (директива git) и появляется возможность установки зависимостей на основе manifest-файлов с использованием таких инструментов, как Composer, Gradle, npm и т.д. Поскольку сборка стадии зависит от manifest-файла, для достижения наилучшего результата важно добавить зависимость от изменений в manifest-файлах репозитория для этой стадии. Например, если в проекте используется Composer, то добавление файла composer.lock в зависимости стадии beforeInstall позволит пересобирать стадию при изменении файла composer.lock.

installCacheVersion: <string> — опциональная директива, которая позволяет инвалидировать сборочный кеш данной стадии детерминированным способом через Git.

beforeSetup

shell:
  beforeSetup:
    - rake assets:precompile
  beforeSetupCacheVersion: "1"

Данная стадия предназначена для подготовки приложения перед настройкой.

На данной стадии рекомендуется выполнять разного рода компиляцию и обработку. Например, компиляция jar-файлов, бинарных файлов, файлов библиотек, создание ассетов web-приложений, минификация, шифрование и т.п. Перечисленные операции, как правило, зависят от изменений в исходном коде, и на данной стадии также важно определить достаточные зависимости от изменений в репозитории. Логично, что стадия будет зависеть от большего числа файлов в репозитории, чем на предыдущей стадии, и, соответственно, ее пересборка будет выполняться чаще.

При правильно определенных зависимостях изменения в коде приложения должны приводить к пересборке стадии beforeSetup, а изменение manifest-файла к стадии install и последующих стадий.

beforeSetupCacheVersion: <string> — опциональная директива, которая позволяет инвалидировать сборочный кеш данной стадии детерминированным способом через Git.

setup

shell:
  setup:
    - npm run build
  setupCacheVersion: "1"

Данная стадия предназначена для настройки приложения.

Обычно на данной стадии выполняется копирование файлов конфигурации (например, в каталог /etc), создание файлов текущей версии приложения и т.д. Такого рода операции не должны быть затратными по времени, т.к. они, скорее всего, будут выполняться в большинстве сборок.

setupCacheVersion: <string> — опциональная директива, которая позволяет инвалидировать сборочный кеш данной стадии детерминированным способом через Git.

Пользовательская стратегия

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

Синтаксис

Пользовательские стадии и инструкции сборки определяются внутри директивы shell. Каждый образ собирается используя сборочные инструкции shell, описанные в соответствующей директиве.

В каждой директиве можно описывать инструкции для пользовательских стадий, соответственно:

  • beforeInstall;
  • install;
  • beforeSetup;
  • setup.

Также можно указывать директивы версий кэша (cacheVersion), которые по сути являются частью дайджеста каждой пользовательской стадии. Более подробно в соответствующем разделе.

Shell

Синтаксис описания пользовательских стадий при использовании сборочных инструкций shell:

shell:
  beforeInstall:
  - <bash_command 1>
  - <bash_command 2>
  # ...
  - <bash_command N>
  install:
  - bash command
  # ...
  beforeSetup:
  - bash command
  # ...
  setup:
  - bash command
  # ...
  cacheVersion: <version>
  beforeInstallCacheVersion: <version>
  installCacheVersion: <version>
  beforeSetupCacheVersion: <version>
  setupCacheVersion: <version>

Сборочные инструкции shell — это массив Bash-команд для соответствующей пользовательской стадии. Все команды одной стадии выполняются как одна инструкция RUN в Dockerfile, т.е. в результате создается один слой на каждую пользовательскую стадию.

werf при сборке использует собственный исполняемый файл bash, и вам не нужно отдельно добавлять его в образ (или базовый образ) при сборке.

Пример описания стадии beforeInstall, содержащей команды apt-get update и apt-get install:

beforeInstall:
- apt-get update
- apt-get install -y build-essential g++ libcurl4

Исполняемый файл bash находится внутри Docker-тома stapel. Подробнее про эту концепцию можно узнать в этой статье (упоминаемый в статье dappdeps был переименован в stapel, но принцип сохранился)

Переменные окружения сборочного контейнера

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

Доступны следующие переменные:

  • WERF_COMMIT_HASH. Пример значения: cda9d17265d174c62424e8f7b5e5640bf749c565.
  • WERF_COMMIT_TIME_HUMAN. Пример значения: 2022-01-24 17:26:19 +0300 +0300.
  • WERF_COMMIT_TIME_UNIX. Пример значения: 1643034379.

Пример использования:

shell:
  install:
  - echo "Commands on the Install stage for $WERF_COMMIT_HASH"

В примере выше хэш текущего коммита будет подставлен в команду echo ..., но произойдет это в самый последний момент — на этапе выполнения инструкций shell’ом. Таким образом пересборок слоя install на каждом коммите происходить не будет.

Использование сборочных секретов

ЗАМЕЧАНИЕ: Чтобы использовать секреты в сборках, их нужно явно разрешить в настройках гитерминизма. Подробнее (здесь)

Секрет сборки — это любая конфиденциальная информация, например пароль или токен API, используемая в процессе сборки вашего приложения.

Аргументы сборки и переменные окружения не подходят для передачи секретов в сборку, поскольку они сохраняются в конечном образе. Вы можете использовать секреты при сборке, описав их в werf.yaml.

# werf.yaml
project: example
configVersion: 1
---
image: stapel-shell
from: ubuntu:22.04
secrets:
  - env: AWS_ACCESS_KEY_ID
  - id: aws_secret_key
    env: AWS_SECRET_ACCESS_KEY
  - src: "~/.aws/credentials"
  - id: plainSecret
    value: plainSecretValue
# werf-giterminism.yaml
giterminismConfigVersion: 1

config:
  secrets:
    allowEnvVariables:
      - "AWS_ACCESS_KEY_ID"
    allowFiles:
      - "~/.aws/credentials"
    allowValueIds:
      - plainSecret

При использовании секрета в Stapel инструкциях, секрет монтируется в файл по умолчанию. Путь к файлу секрета по умолчанию внутри контейнера сборки — /run/secrets/<id>. Если id секрета явно не указан в werf.yaml, то в качестве id будет использовано значение по умолчанию:

  • Для env — имя переменной окружения.
  • Для src — имя конечного файла (например, для /path/to/file будет использован id: file).

Для value — поле id является обязательным.

image: stapel-shell
from: ubuntu:22.04
secrets:
  - env: AWS_ACCESS_KEY_ID
  - id: aws_secret_key
    env: AWS_SECRET_ACCESS_KEY
  - src: "~/.aws/credentials"
  - id: plainSecret
    value: plainSecretValue
shell:
  setup:
    - AWS_ACCESS_KEY_ID=$(cat /run/secrets/AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY=$(cat /run/secrets/aws_secret_key) aws s3 cp ...
    - AWS_SHARED_CREDENTIALS_FILE=$(cat /run/secrets/credentials) aws s3 cp ...
    - export WERF_BUILD_SECRET=$(cat /run/secrets/plainSecret)  

Зависимости пользовательских стадий

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

Дайджест пользовательских стадий и, соответственно, пересборка пользовательских стадий зависят от изменений:

  • в инструкциях сборки;
  • в директивах семейства cacheVersion;
  • в Git-репозитории (или Git-репозиториях);
  • в файлах, импортируемых из образов.

Первые три описанных варианта зависимостей рассматриваются подробно далее.

Зависимость от изменений в инструкциях сборки

Дайджест пользовательской стадии зависит от итогового текста инструкций, т.е. после применения шаблонизатора. Любые изменения в тексте инструкций с учетом применения шаблонизатора Go в пользовательской стадии приводят к пересборке стадии. Например, вы используете следующие shell-инструкции:

shell:
  beforeInstall:
  - echo "Commands on the Before Install stage"
  install:
  - echo "Commands on the Install stage"
  beforeSetup:
  - echo "Commands on the Before Setup stage"
  setup:
  - echo "Commands on the Setup stage"

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

Изменим инструкцию сборки для стадии install:

shell:
  beforeInstall:
  - echo "Commands on the Before Install stage"
  install:
  - echo "Commands on the Install stage"
  - echo "Installing ..."
  beforeSetup:
  - echo "Commands on the Before Setup stage"
  setup:
  - echo "Commands on the Setup stage"

Дайджест стадии install изменилась, и запуск werf для сборки приведет к выполнению всех инструкций стадии install и инструкций последующих стадий, т.е. beforeSetup и setup.

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

shell:
  beforeInstall:
  - echo "Commands on the Before Install stage for {{ env "CI_COMMIT_SHA” }}"
  install:
  - echo "Commands on the Install stage"
  # ...

Первая сборка высчитает дайджест стадии beforeInstall на основе команды (хэш коммита, конечно, будет другой):

echo "Commands on the Before Install stage for 0a8463e2ed7e7f1aa015f55a8e8730752206311b"

После очередного коммита при сборке дайджест стадии beforeInstall уже будет другой (с другим хешем коммита):

echo "Commands on the Before Install stage for 36e907f8b6a639bd99b4ea812dae7a290e84df27"

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

Зависимость от изменений в Git-репозитории

Зависимость от изменений в git-репозитории

Как описывалось в статье про git mapping, существуют специальные стадии gitArchive и gitLatestPatch. Стадия gitArchive выполняется после пользовательской стадии beforeInstall, а стадия gitLatestPatch после пользовательской стадии setup, если в локальном Git-репозитории есть изменения. Таким образом, чтобы выполнить сборку с последней версией исходного кода, можно пересобрать стадию beforeInstall, изменив значение директивы cacheVersion либо изменив сами инструкции стадии beforeInstall.

Пользовательские стадии install, beforeSetup и setup также могут зависеть от изменений в Git-репозитории. В этом случае (если такая зависимость определена) Git-патч применяется перед выполнением инструкций пользовательской стадии, чтобы сборочные инструкции выполнялись с актуальной версией кода приложения.

Во время процесса сборки исходный код обновляется только в рамках одной стадии, последующие стадии, зависящие последовательно друг от друга, будут использовать также обновленную версию файлов. Первая сборка добавляет файлы из Git-репозитория на стадии gitArchive. Все последующие сборки обновляют файлы на стадии gitCache, gitLatestPatch или на одной из следующих пользовательских стадий: install, beforeSetup, setup.

Пример этого этапа (фаза подсчета дайджестов, calculating digests): git files actualized on specific stage

Параметр git.stageDependencies задаёт, изменения каких файлов приводят к пересборке пользовательских стадий. Синтаксис:

git:
- ...
  stageDependencies:
    install:
    - <mask 1>
    # ...
    - <mask N>
    beforeSetup:
    - <mask>
    # ...
    setup:
    - <mask>

У параметра git.stageDependencies возможно указывать 3 ключа: install, beforeSetup и setup. Значение каждого ключа — массив масок файлов, относящихся к соответствующей стадии. Соответствующая пользовательская стадия пересобирается, если в Git-репозитории происходят изменения подпадающие под указанную маску.

Для каждой пользовательской стадии werf создает список подпадающих под маску файлов и вычисляет контрольную сумму каждого файла с учетом его аттрибутов и содержимого. Эти контрольные суммы являются частью дайджеста стадии, поэтому любое изменение файлов в репозитории, подпадающее под маску, приводит к изменениям дайджеста стадии. К этим изменениям относятся: изменение атрибутов файла, изменение содержимого файла, добавление или удаление подпадающего под маску файла и т.п.

Маски git.stageDependencies работают совместно с фильтрами git.includePaths и git.excludePaths (смотри подробнее про них в соответствующем разделе): оба фильтра только сужают набор файлов, которые может захватить маска. Файл считается зависимостью пользовательской стадии, если он подпадает под одну из масок stageDependencies этой стадии, удовлетворяет фильтру includePaths (если фильтр задан) и не удовлетворяет фильтру excludePaths. Исключение только вычитает файлы: excludePaths никогда не добавляет файлы в зависимости стадии.

Правила описания маски в параметре stageDependencies аналогичны описанию параметров includePaths и excludePaths. Маска определяет шаблон для файлов и путей и может содержать следующие шаблоны:

  • * — удовлетворяет любому файлу. Шаблон включает . и исключает /.
  • ** — удовлетворяет директории со всем ее содержимым, рекурсивно.
  • ? — удовлетворяет любому одному символу в имени файла (аналогично regexp-шаблону /.{1}/).
  • [set] — удовлетворяет любому символу из указанного набора символов. Аналогично использованию в regexp-шаблонах, включая указание диапазонов типа [^a-z].
  • \ — экранирует следующий символ.

Маска, которая начинается с шаблона * или **, должна быть взята в одинарные или двойные кавычки в werf.yaml:

# * в начале маски, используем двойные кавычки.
- "*.rb"
# Одинарные также работают.
- '**/*'
# Нет * в начале, можно не использовать кавычки.
- src/**/*.js

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

  • werf создает список всех файлов согласно пути, определенному в параметре add, и применяет фильтры excludePaths и includePaths;
  • К каждому файлу с учетом его пути применяется маска, согласно правилам применения шаблонов;
  • Если под маску подпадает каталог, то все содержимое этого каталога считается подпадающей под маску рекурсивно;
  • У получившегося списка файлов werf подсчитывает контрольные суммы с учетом аттрибутов файлов и их содержимого.

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

Пример:

image: app
git:
- add: /src
  to: /app
  stageDependencies:
    beforeSetup:
    - "*"
shell:
  install:
  - echo "install stage"
  beforeSetup:
  - echo "beforeSetup stage"
  setup:
  - echo "setup stage"

В приведенном файле конфигурации werf.yaml указан git mapping, согласно которому содержимое каталога /src локального Git-репозитория копируется в каталог /app собираемого образа. Во время первой сборки файлы кэшируются в стадии gitArchive и выполняются сборочные инструкции стадий install, beforeSetup и setup.

Сборка следующего коммита, в котором будут только изменения файлов за пределами каталога /src, не приведет к выполнению инструкций каких-либо стадий. Если коммит будет содержать изменение внутри каталога /src, контрольные суммы файлов подпадающих под маску изменятся, werf применит Git-патч и пересоберёт все пользовательские стадии, начиная со стадии beforeSetup, а именно — beforeSetup и setup. Применение Git-патча будет выполнено один раз на стадии beforeSetup.

Маски незаданных стадий

Маски незаданных стадий werf выводит из заданных. Стадии всегда упорядочены по порядку сборки — install → beforeSetup → setup — независимо от порядка ключей в werf.yaml, и маски выводятся отдельно для каждого git mapping:

  • стадия с явно заданными масками использует именно эти маски;
  • явно заданный пустой список ([]) означает отсутствие прямой зависимости от файлов Git-репозитория и при этом считается объявлением стадии;
  • незаданная стадия до последней явно объявленной стадии получает [];
  • незаданная стадия после последней явно объявленной стадии получает **/*;
  • если stageDependencies не указан вовсе или задан как {}, все три стадии получают **/*.

Итоговые маски для типовых конфигураций:

stageDependencies в werf.yaml install beforeSetup setup
не указан или stageDependencies: {} **/* **/* **/*
beforeSetup: ["src/**/*"] [] src/**/* **/*
install: ["package.json", "package-lock.json"] и setup: ["src/**/*"] package.json, package-lock.json [] src/**/*
install: ["package-lock.json"] package-lock.json **/* **/*
beforeSetup: [] [] [] **/*
setup: [] [] [] []

Например, при неизменных остальных входных данных сборки в конфигурации ниже стадия install пересобирается только при изменении package-lock.json, а стадии beforeSetup и setup, идущие после последней объявленной стадии, — при любом изменении добавляемых исходников:

image: app
from: alpine:3.20
git:
- add: /
  to: /app
  stageDependencies:
    install:
    - package-lock.json
shell:
  install: ["echo install"]
  beforeSetup: ["echo beforeSetup"]
  setup: ["echo setup"]

Чтобы ничего не оставлять выводимым маскам, объявите все три стадии явно:

image: app
from: alpine:3.20
git:
- add: /
  to: /app
  stageDependencies:
    install:
    - package-lock.json
    beforeSetup: []
    setup:
    - "src/**/*"
shell:
  install: ["echo install"]
  beforeSetup: ["echo beforeSetup"]
  setup: ["echo setup"]

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

Маски не создают стадии: пользовательская стадия без сборочных инструкций не создаётся независимо от масок, а непустой набор масок для стадии без сборочных инструкций остаётся ошибкой конфигурации. У стадии beforeInstall нет ключа в stageDependencies, и она никогда не зависит от файлов Git-репозитория напрямую.

Зависимость от значения CacheVersion

Существуют ситуации, когда необходимо принудительно пересобрать все или какую-то конкретную пользовательскую стадию. Этого можно достичь, изменяя параметры cacheVersion или <user stage name>CacheVersion.

Дайджест пользовательской стадии install зависит от значения параметра installCacheVersion. Чтобы пересобрать пользовательскую стадию install (и все последующие стадии), можно изменить значение параметра installCacheVersion.

Обратите внимание, что параметры cacheVersion и beforeInstallCacheVersion имеют одинаковый эффект — при изменении этих параметров возникает пересборка стадии beforeInstall и всех последующих стадий.

Пример: общий образ для нескольких приложений

Вы можете определить образ, содержащий общие системные пакеты в отдельном файле werf.yaml. Изменение параметра cacheVersion может быть использовано для пересборки этого образа, чтобы обновить версии системных пакетов.

image: app
from: ubuntu:latest
shell:
  beforeInstallCacheVersion: 2
  beforeInstall:
  - apt update
  - apt install ...

Этот образ может быть использован как базовый образ для нескольких приложений (например, если образ с hub.docker.com не удовлетворяет вашим требованиям).

Пример использования внешних зависимостей

Параметры CacheVersion можно использовать совместно с шаблонами Go-шаблонизатора, чтобы определить зависимость пользовательской стадии от файлов, не находящихся в Git-репозитории.

image: app
from: ubuntu:latest
shell:
  installCacheVersion: {{.Files.Get "some-library-latest.tar.gz" | sha256sum}}
  install:
  - tar zxf some-library-latest.tar.gz
  - <build application>

Если использовать, например, скрипт загрузки файла some-library-latest.tar.gz и запускать werf для сборки уже после скачивания файла, то пересборка пользовательской стадии install (и всех последующих) будет происходить в случае, если скачан новый (измененный) файл.

Использование SSH-агента

По умолчанию werf монтирует сокет SSH-агента во все сборочные контейнеры, что позволяет вашим инструкциям использовать SSH-агент для аутентификации. Это особенно полезно, если ваши команды требуют SSH-доступа, например, для клонирования приватных репозиториев.

Подробную информацию об использовании SSH-агента можно найти здесь.