Аутентификация в container registry
Перед работой с образами необходимо аутентифицироваться в container registry. Сделать это можно командой werf cr login:
werf cr login <registry url>
Например:
# Login with username and password from command line
werf cr login -u username -p password registry.example.com
# Login with token from command line
werf cr login -p token registry.example.com
# Login into insecure registry (over http)
werf cr login --insecure-registry registry.example.com
В случае использования команды ci-env с поддерживаемыми CI/CD-системами аутентификация во встроенные container registry выполняется в рамках команды, поэтому использование команды werf cr login в этом случае не требуется.
Тегирование образов
Тегирование образов werf выполняется автоматически в рамках сборочного процесса. Используется оптимальная схема тегирования, основанная на содержимом образа, которая предотвращает лишние пересборки и время простоя приложения при выкате.
По умолчанию тег — это некоторый идентификатор в виде хэша, включающий в себя контрольную сумму инструкций и файлов сборочного контекста. Например:
registry.example.org/group/project d4bf3e71015d1e757a8481536eeabda98f51f1891d68b539cc50753a-1589714365467 7c834f0ff026 20 hours ago 66.7MB
registry.example.org/group/project e6073b8f03231e122fa3b7d3294ff69a5060c332c4395e7d0b3231e3-1589714362300 2fc39536332d 20 hours ago 66.7MB
Такой тег будет меняться только при изменении входных данных для сборки образа. Таким образом, один тег может быть переиспользован для разных Git-коммитов. werf берёт на себя:
- расчёт таких тегов;
- атомарную публикацию образов по этим тегам в репозиторий или локально;
- передачу тегов в Helm-чарт.
Образы в репозитории именуются согласно следующей схемы: CONTAINER_REGISTRY_REPO:DIGEST-TIMESTAMP_MILLISEC
. Здесь:
CONTAINER_REGISTRY_REPO
— репозиторий, заданный опцией--repo
;DIGEST
— контрольная сумма от:- сборочных инструкций, описанных в Dockerfile или
werf.yaml
; - файлов сборочного контекста, используемых в тех или иных сборочных инструкциях.
- сборочных инструкций, описанных в Dockerfile или
TIMESTAMP_MILLISEC
— временная отметка, которая проставляется в процессе процедуры сохранения слоя в container registry после того, как стадия была собрана.
Сборочный алгоритм также дополнительно гарантирует нам, что образ под таким тегом является уникальным, и этот тег никогда не будет перезаписан образом с другим содержимым.
Тегирование промежуточных слоёв
На самом деле описанный выше автоматический тег используется и для финальных образов, которые запускает пользователь, и для промежуточных слоёв, хранимых в container registry. Любой слой, найденный в репозитории, может быть использован либо как промежуточный для сборки нового слоя на его основе, либо в качестве финального образа.
Получение тегов
Для получения тегов образов может использоваться опция --save-build-report
для команд werf build
, werf converge
и пр.:
# По умолчанию формат JSON.
werf build --save-build-report --repo REPO
# Поддерживается формат envfile.
werf converge --save-build-report --build-report-path .werf-build-report.env --repo REPO
# В команде рендера финальные теги будут доступны только с параметром --repo.
werf render --save-build-report --repo REPO
ЗАМЕЧАНИЕ: Получить теги заранее, не вызывая сборочный процесс, на данный момент невозможно, можно получить лишь теги уже собранных ранее образов.
Добавление произвольных тегов
Пользователь может добавить произвольное количество дополнительных тегов с опцией --add-custom-tag
:
werf build --repo REPO --add-custom-tag main
# Можно добавить несколько тегов-алиасов.
werf build --repo REPO --add-custom-tag main --add-custom-tag latest --add-custom-tag prerelease
Шаблон тега может включать следующие параметры:
%image%
,%image_slug%
или%image_safe_slug%
для использования имени образа изwerf.yaml
(обязательно при сборке нескольких образов);%image_content_based_tag%
для использования content-based тега werf.
werf build --repo REPO --add-custom-tag "%image%-latest"
ЗАМЕЧАНИЕ: При использовании опций создаются дополнительные теги-алиасы, ссылающиеся на автоматические теги-хэши. Полное отключение создания автоматических тегов не предусматривается.
Послойное кэширование образов
Послойное кэширование образов является неотъемлемой частью сборочного процесса werf. werf сохраняет и переиспользует сборочный кэш в container registry, а также синхронизирует работу параллельных сборщиков.
Сборка реализована с отступлением от стандартной для Docker парадигмы разделения стадий build
и push
, и переходом к одной стадии build
, совмещающей и сборку, и публикацию слоёв.
Стандартный подход сборки и публикации образов и слоёв через Docker может выглядеть следующим образом:
- Скачивание сборочного кеша из container registry (опционально).
- Локальная сборка всех промежуточных слоёв образа с использованием локального кеша слоёв.
- Публикация собранного образа.
- Публикация локального сборочного кеша в container registry (опционально).
Алгоритм сборки образов в werf работает по-другому:
- Если очередной собираемый слой уже есть в container registry, то его сборка и скачивание не происходит.
- Если очередной собираемый слой отсутствует в container registry, то скачивается предыдущий слой, базовый для сборки текущего.
- Новый слой собирается на локальной машине и публикуется в container registry.
- В момент публикации автоматически разрешаются конфликты между сборщиками с разных хостов, которые пытаются опубликовать один и тот же слой. В этом случае гарантированно будет опубликован только один слой, и все остальные сборщики будут обязаны переиспользовать именно его. (Такое возможно за счёт использования встроенного сервиса синхронизации).
- И т.д. до тех пор, пока не будут собраны все слои образа.
Алгоритм выборки стадии в werf можно представить следующим образом:
- Рассчитывается дайджест стадии.
- Выбираются все стадии, подходящие под дайджест, т.к. с одним дайджестом может быть связанно несколько стадий в репозитории.
- Для stapel-сборщика, если текущая стадия связана с Git (стадия Git-архив, пользовательская стадия с Git-патчами или стадия
git latest patch
), тогда выбираются только те стадии, которые связаны с коммитами, являющимися предками текущего коммита. Таким образом, коммиты соседних веток будут отброшены. - Выбирается старейший по времени
TIMESTAMP_MILLISEC
.
Если запустить сборку с хранением образов в репозитории, то werf сначала проверит наличие требуемых стадий в локальном хранилище и скопирует оттуда подходящие стадии, чтобы не пересобирать эти стадии заново.
ЗАМЕЧАНИЕ: Предполагается, что репозиторий образов для проекта не будет удален или очищен сторонними средствами без негативных последствий для пользователей CI/CD, построенного на основе werf (см. очистка образов).
Dockerfile
По умолчанию Dockerfile-образы кешируются одним образом в container registry.
Для включения послойного кеширования Dockerfile-инструкций в container registry необходимо использовать директиву staged
в werf.yaml:
# werf.yaml
image: example
dockerfile: ./Dockerfile
staged: true
Существует несколько ревизий послойного сборщика Dockerfile, которые могут быть включены с помощью переменной WERF_STAGED_DOCKERFILE_VERSION={v1|v2}
. Изменение версии сборщика может вызвать пересборку сборочного кеша.
v1
используется по умолчанию.v2
включает отдельный слой для стадииFROM
, чтобы закешировать базовый образ, указанный в инструкцииFROM
.
Совместимость версии v2
может быть сломана в будущих релизах.
Stapel
Образы stapel кешируются в режиме послойного кеширования в container registry по умолчанию без дополнительной конфигурации.
Параллельность и порядок сборки образов
Все образы, описанные в werf.yaml
, собираются параллельно на одном сборочном хосте. При наличии зависимостей между образами сборка разбивается на этапы, где каждый этап содержит набор независимых образов и может собираться параллельно.
При использовании Dockerfile-стадий параллельность их сборки также определяется на основе дерева зависимостей. Также, если Dockerfile-стадия используется разными образами, объявленными в
werf.yaml
, werf обеспечит однократную сборку этой общей стадии без лишних пересборок
Параллельная сборка в werf регулируется двумя параметрами --parallel
и --parallel-tasks-limit
. По умолчанию параллельная сборка включена и собирается не более 5 образов одновременно.
Рассмотрим следующий пример:
# backend/Dockerfile
FROM node as backend
WORKDIR /app
COPY package*.json /app/
RUN npm ci
COPY . .
CMD ["node", "server.js"]
# frontend/Dockerfile
FROM ruby as application
WORKDIR /app
COPY Gemfile* /app
RUN bundle install
COPY . .
RUN bundle exec rake assets:precompile
CMD ["rails", "server", "-b", "0.0.0.0"]
FROM nginx as assets
WORKDIR /usr/share/nginx/html
COPY configs/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=application /app/public/assets .
COPY --from=application /app/vendor .
ENTRYPOINT ["nginx", "-g", "daemon off;"]
image: backend
dockerfile: Dockerfile
context: backend
---
image: frontend
dockerfile: Dockerfile
context: frontend
target: application
---
image: frontend-assets
dockerfile: Dockerfile
context: frontend
target: assets
Имеется 3 образа backend
, frontend
и frontend-assets
. Образ frontend-assets
зависит от frontend
, потому что он импортирует скомпилированные ассеты из frontend
.
Формируются следующие наборы для сборки:
┌ Concurrent builds plan (no more than 5 images at the same time)
│ Set #0:
│ - ⛵ image backend
│ - ⛵ image frontend
│
│ Set #1:
│ - ⛵ frontend-assets
└ Concurrent builds plan (no more than 5 images at the same time)
Использование container registry
При использовании werf container registry используется не только для хранения конечных образов, но также для сборочного кэша и служебных данных, необходимых для работы werf (например, метаданные для очистки container registry на основе истории Git). Репозиторий container registry задаётся параметром --repo
:
werf converge --repo registry.mycompany.org/project
В дополнение к основному репозиторию существует ряд дополнительных:
--final-repo
для сохранения конечных образов в отдельном репозитории;--secondary-repo
для использования репозитория в режимеread-only
(например, для использования container registry CI, в который нельзя пушить, но можно переиспользовать сборочный кэш);--cache-repo
для поднятия репозитория со сборочным кэшом рядом со сборщиками.
ВАЖНО. Для корректной работы werf container registry должен быть надёжным (persistent), а очистка должна выполняться только с помощью специальной команды
werf cleanup
Дополнительный репозиторий для конечных образов
При необходимости в дополнение к основному репозиторию могут использоваться т.н. финальные репозитории для непосредственного хранения конечных образов.
werf build --repo registry.mycompany.org/project --final-repo final-registry.mycompany.org/project-final
Финальные репозитории позволяют сократить время загрузки образов и снизить нагрузку на сеть за счёт поднятия container registry ближе к кластеру Kubernetes, на котором происходит развёртывание приложения. Также при необходимости финальные репозитории могут использоваться в том же container registry, что и основной репозиторий (--repo
).
Дополнительный репозиторий для быстрого доступа к сборочному кэшу
С помощью параметра --cache-repo
можно указать один или несколько т.н. кеширующих репозиториев.
# Дополнительный кэширующий репозиторий в локальной сети.
werf build --repo registry.mycompany.org/project --cache-repo localhost:5000/project
Кеширующий репозиторий может помочь сократить время загрузки сборочного кэша, но для этого скорость загрузки из него должна быть значительно выше по сравнению с основным репозиторием — как правило, это достигается за счёт поднятия container registry в локальной сети, но это необязательно.
При загрузке сборочного кэша кеширующие репозитории имеют больший приоритет, чем основной репозиторий. При использовании кеширующих репозиториев сборочный кэш продолжает сохраняться и в основном репозитории.
Очистка кeширующего репозитория может осуществляться путём его полного удаления без каких-либо рисков.
Синхронизация сборщиков
Для обеспечения согласованности в работе параллельных сборщиков, а также гарантии воспроизводимости образов и промежуточных слоёв, werf берёт на себя ответственность за синхронизацию сборщиков. По умолчанию используется публичный сервис синхронизации по адресу https://synchronization.werf.io/ и от пользователя ничего дополнительно не требуется.
Сервис синхронизации — это компонент werf, который предназначен для координации нескольких процессов werf и выполняет роль менеджера блокировок. Блокировки требуются для корректной публикации новых образов в container registry и реализации алгоритма сборки, описанного в разделе «Послойное кэширование образов».
На сервис синхронизации отправляются только обезличенные данные в виде хэш-сумм тегов, публикуемых в container registry.
В качестве сервиса синхронизации может выступать:
- HTTP-сервер синхронизации, реализованный в команде
werf synchronization
. - Ресурс ConfigMap в кластере Kubernetes. В качестве механизма используется библиотека lockgate, реализующая распределённые блокировки через хранение аннотаций в выбранном ресурсе.
- Локальные файловые блокировки, предоставляемые операционной системой.
Использование собственного сервиса синхронизации
HTTP-сервер
Сервер синхронизации можно запустить командой werf synchronization
, например для использования порта 55581 (по умолчанию):
werf synchronization --host 0.0.0.0 --port 55581
— данный сервер поддерживает только работу в режиме HTTP, для использования HTTPS необходима настройка дополнительной SSL-терминации сторонними средствами (например через Ingress в Kubernetes).
Далее во всех командах werf, которые используют параметр --repo
дополнительно указывается параметр --synchronization=http[s]://DOMAIN
, например:
werf build --repo registry.mydomain.org/repo --synchronization https://synchronization.domain.org
werf converge --repo registry.mydomain.org/repo --synchronization https://synchronization.domain.org
Специальный ресурс в Kubernetes
Требуется лишь предоставить рабочий кластер Kubernetes, и выбрать namespace, в котором будет хранится сервисный ConfigMap/werf, через аннотации которого будет происходить распределённая блокировка.
Далее во всех командах werf, которые используют параметр --repo
дополнительно указывается параметр --synchronization=kubernetes://NAMESPACE[:CONTEXT][@(base64:CONFIG_DATA)|CONFIG_PATH]
, например:
# Используем стандартный ~/.kube/config или KUBECONFIG.
werf build --repo registry.mydomain.org/repo --synchronization kubernetes://mynamespace
werf converge --repo registry.mydomain.org/repo --synchronization kubernetes://mynamespace
# Явно указываем содержимое kubeconfig через base64.
werf build --repo registry.mydomain.org/repo --synchronization kubernetes://mynamespace@base64:YXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnCnByZWZlcmVuY2VzOiB7fQoKY2x1c3RlcnM6Ci0gY2x1c3RlcjoKICBuYW1lOiBkZXZlbG9wbWVudAotIGNsdXN0ZXI6CiAgbmFtZTogc2NyYXRjaAoKdXNlcnM6Ci0gbmFtZTogZGV2ZWxvcGVyCi0gbmFtZTogZXhwZXJpbWVudGVyCgpjb250ZXh0czoKLSBjb250ZXh0OgogIG5hbWU6IGRldi1mcm9udGVuZAotIGNvbnRleHQ6CiAgbmFtZTogZGV2LXN0b3JhZ2UKLSBjb250ZXh0OgogIG5hbWU6IGV4cC1zY3JhdGNoCg==
# Используем контекст mycontext в конфиге /etc/kubeconfig.
werf build --repo registry.mydomain.org/repo --synchronization kubernetes://mynamespace:mycontext@/etc/kubeconfig
ЗАМЕЧАНИЕ: Данный способ неудобен при доставке проекта в разные кластера Kubernetes из одного Git-репозитория из-за сложности корректной настройки. В этом случае для всех команд werf требуется указывать один и тот же адрес кластера и ресурс, даже если деплой происходит в разные контура, чтобы обеспечить консистивность данных в container registry. Поэтому для такого случая рекомендуется запустить отдельный общий сервис синхронизации, чтобы исключить вероятность некорректной конфигурации.
Локальная синхронизация
Включается опцией --synchronization=:local
. Локальный менеджер блокировок использует файловые блокировки, предоставляемые операционной системой.
werf build --repo registry.mydomain.org/repo --synchronization :local
werf converge --repo registry.mydomain.org/repo --synchronization :local
ЗАМЕЧАНИЕ: Данный способ подходит лишь в том случае, если в вашей CI/CD системе все запуски werf происходят с одного и того же раннера.
Мультиплатформенная сборка
Мультиплатформенная сборка использует механизмы кроссплатформенного исполнения инструкций, предоставляемые ядром Linux и эмулятором QEMU. Перечень поддерживаемых архитектур. Подготовка хост-системы для мультиплатформенной сборки рассмотрена в разделе установки werf
Поддержка мультиплатформенной сборки для разных вариантов синтаксиса сборки, режимов сборки и используемого бекенда:
buildah | docker-server | |
---|---|---|
Dockerfile | полная поддержка | полная поддержка |
staged Dockerfile | полная поддержка | не поддерживается |
stapel | полная поддержка | только linux/amd64 |