git:
- add: <absolute path in git repository>
to: <absolute path inside image>
owner: <owner>
group: <group>
includePaths:
- <path or glob relative to path in add>
excludePaths:
- <path or glob relative to path in add>
stageDependencies:
install:
- <path or glob relative to path in add>
beforeSetup:
- <path or glob relative to path in add>
setup:
- <path or glob relative to path in add>
git:
- url: <git repo url>
branch: <branch name>
commit: <commit>
tag: <tag>
add: <absolute path in git repository>
to: <absolute path inside image>
owner: <owner>
group: <group>
includePaths:
- <path or glob relative to path in add>
excludePaths:
- <path or glob relative to path in add>
stageDependencies:
install:
- <path or glob relative to path in add>
beforeSetup:
- <path or glob relative to path in add>
setup:
- <path or glob relative to path in add>
Что такое git mapping?
Git mapping определяет, какой файл или каталог из Git-репозитория должны быть добавлены в конкретное место образа.
Git-репозиторий может быть как локальным репозиторием, в котором находится файл конфигурации сборки (werf.yaml
), так и удаленным.
В этом случае указывается адрес репозитория и версия кода — ветка, тег или конкретный коммит.
werf добавляет файлы из Git-репозитория в образ, копируя их с помощью git archive, либо накладывая Git-патч. При повторных сборках и появлении изменений в Git-репозитории werf добавляет patch к собранному ранее образу, чтобы в конечном образе отразить изменения файлов и папок. Более подробно механизм переноса файлов и накладывания патчей рассматриваются в следующей секции.
Конфигурация git mapping поддерживает фильтры, что позволяет сформировать практически любую файловую структуру в образе, используя произвольное количество git mappings.
Также вы можете указать группу и владельца конечных файлов в образе, что освобождает от необходимости делать это отдельной командой (chown
).
В werf реализована поддержка сабмодулей Git (git submodules), и если werf определяет, что какая-то часть git mapping является сабмодулем, то принимаются соответствующие меры, чтобы обрабатывать изменения в сабмодулях корректно.
Все Git-сабмодули проекта связаны с конкретным коммитом, поэтому все разработчики, работающие с репозиторием с сабмодулями, получают одинаковое содержимое. werf не инициализирует и не обновляет сабмодули, а использует соответствующие связанные коммиты.
Пример добавления файлов из каталога /src
локального Git-репозитория в каталог /app
собираемого образа и добавления кода PhantomJS из удаленного репозитория в каталог /src/phantomjs
собираемого образа:
git:
- add: /src
to: /app
- url: https://github.com/ariya/phantomjs
add: /
to: /src/phantomjs
Синтаксис
Для добавления кода из локального Git-репозитория используется следующий синтаксис:
add
— (необязательный параметр) путь к директории или файлу, содержимое которого (которой) нужно добавить в образ. Указывается абсолютный путь относительно корня репозитория, т.е. он должен начинаться с/
. По умолчанию копируется все содержимое репозитория, отсутствие параметраadd
равносильно указаниюadd: /
;to
— путь внутри образа, куда будет скопировано соответствующее содержимое;owner
— имя или ID пользователя-владельца файлов в образе;group
— имя или ID группы-владельца файлов в образе;excludePaths
— список исключений (маска) при рекурсивном копировании файлов и папок. Указывается относительно пути, указанного вadd
;includePaths
— список масок файлов и директорий для рекурсивного копирования. Указывается относительно пути, указанного вadd
;stageDependencies
— список масок файлов и директорий для указания зависимости пересборки стадии от их изменений. Позволяет указать, при изменении каких файлов и директорий необходимо принудительно пересобирать конкретную пользовательскую стадию. Более подробно рассматривается здесь.
При использовании удаленных репозиториев дополнительно используются следующие параметры:
url
— адрес удаленного репозитория;branch
,tag
,commit
— имя ветки, тега или коммита соответственно. По умолчанию — веткаmaster
.
По умолчанию использование директивы
branch
запрещено гитерминизмом (подробнее об этом в статье).
Использование git mapping
Копирование директорий
Параметр add
определяет источник, путь в Git-репозитории, откуда файлы рекурсивно копируются в образ и помещаются по адресу, указанному в параметре to
. Если параметр не определен, то по умолчанию используется значение /
, т.е. копируется весь репозиторий.
Пример простейшей конфигурации, добавляющей содержимое всего локального Git-репозитория в образ в каталог /app
.
git:
- add: /
to: /app
Также можно указать несколько git mappings:
git:
- add: /src
to: /app/src
- add: /assets
to: /static
Следует отметить, что конфигурация git mapping не похожа, например, на копирование типа cp -r /src /app
.
Параметр add
указывает на содержимое каталога, которое будет рекурсивно копироваться из репозитория.
Поэтому, если каталог /assets
со всем содержимым из репозитория должен быть скопирован в каталог /app/assets
образа, то имя assets вы должны указать два раза.
Либо, как вариант, вы можете использовать фильтр (например, параметр includePaths
).
Примеры обоих вариантов, которые вы можете использовать для достижения одинакового результата:
git:
- add: /assets
to: /app/assets
либо
git:
- add: /
to: /app
includePaths: assets
Изменение владельца
При добавлении файла из Git-репозитория вы можете указать имя и/или группу владельца файлов в образе. Добавляемым файлам и каталогам в образе при копировании будут установлены соответствующие права. Пользователь и группа могут быть указаны как именем, так и числовым ID (userid, groupid).
Пример использования:
git:
- add: /src/index.php
to: /app/index.php
owner: www-data
Если указан только параметр owner
, как в приведенном примере, то группой-владельцем устанавливается основная группа указанного пользователя в системе.
В результате в каталог /app
образа будет добавлен файл index.php
и ему будут установлены следующие права:
Если значения параметра owner
или group
не числовые ID, а текстовые (т.е. названия соответственно пользователя и группы), то соответствующие пользователь и группа должны существовать в системе. Их нужно добавить заранее при необходимости (к примеру, на стадии beforeInstall), иначе при сборке возникнет ошибка.
git:
- add: /src/index.php
to: /app/index.php
owner: wwwdata
Использование фильтров
Парамеры фильтров includePaths
и excludePaths
используются при составлении списка файлов для добавления.
Эти параметры содержат набор путей или масок, применяемых соответственно для включения и исключения файлов и каталогов при добавлении в образ.
Фильтр excludePaths
работает следующим образом: каждая маска списка применяется к каждому файлу, найденному по пути add
.
Если путь файла удовлетворяет хотя бы одной маске, то он исключается из списка файлов на добавление.
Если путь файла не удовлетворяет ни одной маске, то он добавляется в образ.
Фильтр includePaths
работает наоборот — если путь файла удовлетворяет хотя бы одной маске, то он добавляется в образ.
Конфигурация git mapping может содержать оба фильтра.
В этом случае файл добавляется в образ, если его путь удовлетворяет хотя бы одной маске includePaths
и не удовлетворяет ни одной маске excludePaths
.
Пример:
git:
- add: /src
to: /app
includePaths:
- '**/*.php'
- '**/*.js'
excludePaths:
- '**/*-dev.*'
- '**/*-test.*'
В приведенном примере добавляются .php
и .js
файлы из каталога /src
, исключая файлы с суффиксом -dev.
или -test.
в имени файла.
Последний шаг в алгоритме с добавлением суффикса
**/*
сделан для удобства — вам достаточно указать название каталога в параметрах git mapping, чтобы все его содержимое удовлетворяло шаблону параметра.
Маска может содержать следующие шаблоны:
*
— удовлетворяет любому файлу. Шаблон включает.
и исключает/
.**
— удовлетворяет директории со всем ее содержимым, рекурсивно.?
— удовлетворяет любому одному символу в имени файла (аналогично regexp-шаблону/.{1}/
).[set]
— удовлетворяет любому символу из указанного набора символов. Аналогично использованию в regexp-шаблонах, включая указание диапазонов типа[^a-z]
.\
— экранирует следующий символ.
Маска, которая начинается с шаблона *
или **
, должна быть взята в одинарные или двойные кавычки в werf.yaml
:
"*.rb"
— двойные кавычки;'**/*'
— одинарные кавычки.
Примеры фильтров:
add: /src
to: /app
includePaths:
# Удовлетворяет всем PHP-файлам, расположенным конкретно в каталоге /src.
- '*.php'
# Удовлетворяет всем PHP файлам рекурсивно, начиная с каталога /src
# (также удовлетворяет файлам *.php, т.к. '.' включается шаблон **).
- '**/*.php'
# Удовлетворяет всем файлам в каталоге /src/module1 рекурсивно.
- module1
Фильтр includePaths
может применяться для копирования одного файла без изменения имени. Пример:
git:
- add: /src
to: /app
includePaths: index.php
Наложение путей копирования
Если вы определяете несколько git mappings, вы должны учитывать, что при наложении путей в образе в параметре to
вы можете столкнуться с невозможностью добавления файлов. Пример:
git:
- add: /src
to: /app
- add: /assets
to: /app/assets
Чтобы избежать ошибок сборки, werf определяет возможные наложения касающиеся фильтров includePaths
и excludePaths
, и если такое наложение присутствует, то werf пытается разрешить самые простые конфликты, неявно добавляя соответствующий параметр excludePaths
в git mapping.
Однако, такое поведение может все-таки привести к неожиданным результатам, поэтому лучше всего избегать наложения путей при определении git mappings.
В примере выше werf в итоге неявно добавит параметр excludePaths
, и итоговая конфигурация будет следующей:
git:
- add: /src
to: /app
excludePaths: # werf добавил этот фильтр, чтобы исключить конфликт наложения результирующих путей
- assets # между /src/assets и /assets
- add: /assets
to: /app/assets
Работа с удаленными репозиториями
werf может использовать удаленные репозитории в качестве источника файлов.
Для указания адреса внешнего репозитория используется параметр url
.
werf поддерживает работу с удаленными репозиториями по протоколам https
и git+ssh
.
HTTPS
Синтаксис для работы по протоколу https
:
git:
- url: https://[USERNAME[:PASSWORD]@]repo_host/repo_path[.git/]
Указание логина и пароля при доступе по https
опционально.
Пример доступа к репозиторию из pipeline GitLab CI с использованием переменных окружения:
git:
- url: https://{{ env "CI_REGISTRY_USER" }}:{{ env "CI_JOB_TOKEN" }}@registry.gitlab.company.name/common/helper-utils.git
В приведенном примере используется метод env библиотеки Sprig для доступа к переменным окружения.
Git, SSH
Доступ к удаленному репозиторию с помощью протокола git
защищается с использованием доступа поверх SSH. Это распространенная практика, используемая в частности GitHub, Bitbucket, GitLab, Gogs, Gitolite и т.д. Обычно адрес репозитория выглядит следующим образом:
git:
- url: git@gitlab.company.name:project_group/project.git
Для работы с удаленными репозиториями по SSH необходимо понимать, как werf находит SSH-ключи (читай далее подробнее).
Работа с SSH-ключами
SSH-ключи для доступа предоставляются через SSH-agent. SSH-agent — это демон, который работает через файловый сокет, путь к которому хранится в переменной окружения SSH_AUTH_SOCK
. werf монтирует этот файловый сокет во все сборочные контейнеры и устанавливает переменную окружения SSH_AUTH_SOCK
. Т.e. соединение с удаленным Git-репозиторием устанавливается с использованием ключей, зарегистрированных в запущенном SSH-агенте.
werf использует следующий алгоритм для определения запущенного SSH-агента:
- werf запущен с ключом
--ssh-key
(одним или несколькими):- Запускается временный SSH-агент, в который добавляются указанные при запуске werf ключи. Эти ключи используются при всех операциях с удаленными репозиториями.
- Уже запущенный SSH-агент игнорируется.
- werf запущен без указания ключа
--ssh-key
и есть запущенный SSH-агент:- Используется переменная окружения
SSH_AUTH_SOCK
, ключи добавляются в соответствующий SSH-агент и используются далее при всех операциях работы с удаленными репозиториями.
- Используется переменная окружения
- werf запущен без указания ключа
--ssh-key
и нет запущенного SSH-агента:- Если существует файл
~/.ssh/id_rsa
, запускается временный SSH-агент, в который добавляется ключ из файла~/.ssh/id_rsa
.
- Если существует файл
- Если ни один из вариантов не применим, то SSH-агент не запускается и при операциях с внешними Git-репозиториями не используются никакие SSH-ключи. Сборка образа, с объявленными удаленными репозиториями в git mapping, завершится с ошибкой.
Подробнее про gitArchive, gitCache, gitLatestPatch
Далее будет более подробно рассмотрен процесс добавления файлов в целевой образ. Как упоминалось ранее, Docker-образ состоит из набора слоёв. Чтобы понимать, какие слои создает werf, представим последовательную сборку трех коммитов: 1
, 2
и 3
:
- Сборка коммита 1. Исходя из конфигурации git mapping, все соответствующие файлы добавляются в один слой. Сам процесс добавления выполняется с помощью
git archive
. Получившийся слой соответствует стадии gitArchive. - Сборка коммита 2. Накладывается патч с изменениями файлов, в результате чего получается еще один слой. Получившийся слой соответствует стадии gitLatestPatch.
- Сборка коммита 3. Файлы уже добавлены, и werf накладывает патч, обновляя слой gitLatestPatch.
Сборки для этих коммитов можно представить следующим образом:
gitArchive | gitLatestPatch | |
---|---|---|
Commit No. 1 is made, build at 10:00 | files as in commit No. 1 | - |
Commit No. 2 is made, build at 10:05 | files as in commit No. 1 | files as in commit No. 2 |
Commit No. 3 is made, build at 10:15 | files as in commit No. 1 | files as in commit No. 3 |
Со временем количество коммитов растет, и размер патча между коммитом №1 и текущим может стать довольно большим. Это еще больше увеличит размер последнего слоя и общий размер стадий. Чтобы предотвратить неконтролируемый рост последнего слоя, werf предоставляет дополнительный промежуточный этап — gitCache. Когда gitLatestPatch diff становится слишком большим, большая часть его diff объединяется с gitCache diff, тем самым уменьшая размер стадии gitLatestPatch.
Rebase и git-стадии
Каждая Git-стадия хранит служебные лейблы с SHA-коммитами, которые использовались при сборке стадии.
Эти коммиты будут использоваться при сборке следующей Git-стадии при создании патчей (по сути это git diff COMMIT_FROM_PREVIOUS_GIT_STAGE LATEST_COMMIT
для каждого git-mapping).
Если в стадии сохранён коммит, который отсутствует в Git-репозитории (например, после выполнения rebase), werf пересоберёт эту стадию, используя актуальный коммит.
Git worktree
Для корректной работы сборщика stapel werf’у требуется полная Git-история проекта, чтобы работать в наиболее эффективном режиме. Поэтому по умолчанию werf выполняет fetch истории для текущего Git-проекта, когда это требуется. Это означает, что werf может автоматически сконвертировать shallow-clone репозитория в полный clone и скачать обновлённый список веток и тегов из origin в процессе очистки образов.
Поведение по умолчанию описывается следующими настройками:
gitWorktree:
forceShallowClone: false
allowUnshallow: true
allowFetchOriginBranchesAndTags: true
Чтобы, например, выключить автоматический unshallow рабочей директории Git, необходимы следующие настройки:
gitWorktree:
forceShallowClone: true
allowUnshallow: false