Релиз werf 1.1: улучшения в сборщике сегодня и планы на будущее

в 9:18, , рубрики: devops, docker, dockerfile, gitops, kubernetes, open source, werf, Блог компании Флант, системы сборки, Флант

Релиз werf 1.1: улучшения в сборщике сегодня и планы на будущее - 1

werf — наша GitOps CLI-утилита с открытым кодом для сборки и доставки приложений в Kubernetes. Как и обещали, выход версии v1.0 знаменовал начало добавления в werf новых возможностей и пересмотра привычных подходов. Теперь мы рады представить релиз v1.1, который является большим шагом в развитии и заделом на будущее сборщика werf. Версия доступна на данный момент в канале 1.1 ea.

Основа релиза — это новая архитектура хранилища стадий и оптимизация работы обоих сборщиков (для Stapel и Dockerfile). Новая архитектура хранилища открывает возможности к реализации распределенных сборок с нескольких хостов и параллельных сборок на одном хосте.

Оптимизация работы включает в себя избавление от лишних вычислений на этапе расчета сигнатур стадий и изменения механизмов расчета контрольных сумм файлов на более эффективные. Эта оптимизация уменьшает среднее время сборок проекта с помощью werf. И холостые сборки, когда все стадии существуют в кэше stages-storage, теперь действительно быстрые. В большинстве случаев повторный запуск сборки пройдет быстрее, чем за 1 секунду! Это также касается и процедур верификации стадий в процессе работы команд werf deploy и werf run.

Также в данном релизе появилась стратегия тегирования образов по содержимому — content-based tagging, которая теперь включена по умолчанию и является единственной рекомендуемой.

Рассмотрим подробнее ключевые нововведения в werf v1.1, а заодно расскажем о планах на будущее.

Что изменилось в werf v1.1?

Новый формат именования стадий и алгоритм подбора стадий из кэша

Новое правило генерации имени стадии. Теперь каждая сборка стадии генерирует уникальное имя стадии, которое состоит из 2-х частей: сигнатура (как было в v1.0) плюс уникальный временной идентификатор.

Например, полное имя образа стадии может выглядеть так:

werf-stages-storage/myproject:d2c5ad3d2c9fcd9e57b50edd9cb26c32d156165eb355318cebc3412b-1582656767835

… или в общем виде:

werf-stages-storage/PROJECT:SIGNATURE-TIMESTAMP_MILLISEC

Здесь:

  • SIGNATURE — это сигнатура стадии, которая представляет идентификатор содержимого стадии и зависит от истории правок в Git, которые привели к данному содержимому;
  • TIMESTAMP_MILLISEC — это гарантированно уникальный идентификатор образа, который генерируется в момент сборки нового образа.

Алгоритм подбора стадий из кэша основан на проверке родства Git-коммитов:

  1. Werf рассчитывает сигнатуру некоторой стадии.
  2. В stages-storage может существовать несколько стадий по данной сигнатуре. Werf выбирает все подходящие по сигнатуре стадии.
  3. Если текущая стадия связана с Git (git-archive, пользовательская стадия с Git-патчами: install, beforeSetup, setup; или git-latest-patch), то werf выбирает только те стадии, которые связаны с коммитом, являющимся предком текущего коммита (для которого вызвана сборка).
  4. Из оставшихся подходящих стадий выбирается одна — старейшая по дате создания.

Стадия для разных Git-веток может иметь одну и ту же сигнатуру. Но werf предотвратит использование кэша, связанного с разными ветками, между этих веток, даже если сигнатуры совпали.

→ Документация.

Новый алгоритм создания и сохранения стадий в хранилище стадий

Если во время подбора стадий из кэша werf не находит подходящей стадии, то инициируется процесс сборки новой стадии.

Заметим, что несколько процессов (на одном или нескольких хостах) могут начать сборку одной и той же стадии в примерно одно и то же время. Werf использует алгоритм оптимистичной блокировки stages-storage в момент сохранения свежесобранного образа в stages-storage. Таким образом, когда сборка новой стадии готова, werf блокирует stages-storage и сохраняет туда свежесобранный образ только в случае, если там уже не существует подходящего образа (по сигнатуре и другим параметрам — см. новый алгоритм подбора стадий из кэша).

Свежесобранный образ гарантированно будет иметь уникальный идентификатор по TIMESTAMP_MILLISEC (см. новый формат именования стадий). В случае, если в stages-storage будет найден подходящий образ, werf отбросит свежесобранный образ и будет использовать образ из кэша.

Другими словами: первый процесс, который закончит собирать образ (самый быстрый), получит право сохранить его в stages-storage (и затем именно этот единственный образ будет использоваться для всех сборок). Медленный же процесс сборки никогда не будет блокировать более быстрый процесс от сохранения результатов сборки текущей стадии и перехода к сборке следующей.

→ Документация.

Улучшена производительность сборщика Dockerfile

На данный момент конвейер стадий для образа, собираемого из Dockerfile, состоит из одной стадии — dockerfile. При вычислении сигнатуры считается контрольная сумма файлов context, что будут использоваться при сборке. До этого улучшения werf рекурсивно проходил по всем файлам и получал контрольную сумму, просуммировав контекст и мод каждого файла. Начиная с версий v1.1, werf может использовать рассчитанные контрольные суммы, хранящиеся в Git-репозитории.

В основе алгоритма — git ls-tree. Алгоритм учитывает записи в .dockerignore и проходит рекурсивно по дереву файлов только при необходимости. Таким образом, мы отвязались от чтения файловой системы, а зависимость алгоритма от размера context не является существенной.

Также алгоритм проверяет untracked-файлы и при необходимости учитывает их в контрольной сумме.

Улучшена производительность при импортировании файлов

В версиях werf v1.1 используется rsync-сервер при импорте файлов из артефактов и образов. Раньше импортирование выполнялось в два шага с использованием монтирования директории из хост-системы.

Производительность импортов в macOS больше не ограничивается Docker volumes, а импорты выполняются за то же время, что и в Linux и Windows.

Content-based tagging

Werf v1.1 поддерживает так называемое тегирование по содержимому образа — content-based tagging. Теги результирующих Docker-образов зависят от содержимого этих образов.

При запуске команды werf publish --tags-by-stages-signature или werf ci-env --tagging-strategy=stages-signature будут протегированы публикуемые образы так называемой сигнатурой стадий образа. Каждый образ тегируется своей собственной сигнатурой стадий этого образа, которая рассчитывается по тем же правилам, что и регулярная сигнатура каждой из стадий в отдельности, но является обобщающим идентификатором образа.

Сигнатура стадий образа зависит от:

  1. содержимого этого образа;
  2. истории правок в Git, которые привели к этому содержимому.

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

При использовании content-based tagging решаются проблемы лишних перезапусков pod'ов приложения в Kubernetes из-за изменений имени образа, даже если содержимое образа не поменялось. Кстати, это является одной из причин, мешающих хранить множество микросервисов одного приложения в едином Git-репозитории.

Также content-based tagging является более надежным методом тегирования, чем тегирование по Git-веткам, потому что содержимое результирующих образов не зависит от порядка исполнения pipeline'ов в CI-системе для сборки нескольких коммитов одной и той же ветки.

Важно: начиная с текущего момента stages-signature — это единственная рекомендуемая стратегия тегирования. Именно она будет использоваться по умолчанию в команде werf ci-env (если явно не указать другую схему тегирования).

→ Документация. Этой фиче будет также посвящена отдельная публикация.

Уровни логирования

У пользователя появилась возможность контролировать вывод, задавать уровень логирования и работать с отладочной информацией. Добавлены опции --log-quiet, --log-verbose, --log-debug.

По умолчанию в выводе содержится минимум информации:

Релиз werf 1.1: улучшения в сборщике сегодня и планы на будущее - 2

При использовании подробного вывода (--log-verbose) можно проследить, как работает werf:

Релиз werf 1.1: улучшения в сборщике сегодня и планы на будущее - 3

Детальный вывод (--log-debug), помимо отладочной информации werf, также содержит логи используемых библиотек. Например, можно увидеть, как происходит взаимодействие с Docker Registry, а также зафиксировать места, в которых тратится существенное количество времени:

Релиз werf 1.1: улучшения в сборщике сегодня и планы на будущее - 4

Дальнейшие планы

Внимание! Описанные далее возможности с пометкой v1.1 станут доступны уже в этой версии, многие из них — в ближайшее время. Обновления придут через автоапдейты при использовании multiwerf. Эти возможности не затрагивают стабильную часть функций v1.1, их появление не потребует ручного вмешательства пользователя в уже существующие конфигурации.

Полная поддержка различных реализаций Docker Registry (НОВОЕ)

  • Версия: v1.1
  • Сроки: март
  • Issue

Цель — пользователь должен использовать произвольную реализацию без ограничений при использовании werf.

На текущий момент мы выделили следующий набор решений, для которых собираемся гарантировать полную поддержку:

  • Default (library/registry)*,
  • AWS ECR,
  • Azure*,
  • Docker Hub,
  • GCR*,
  • GitHub Packages,
  • GitLab Registry*,
  • Harbor*,
  • Quay.

Звёздочкой отмечены решения, которые на текущий момент уже полностью поддерживаются werf. Для остальных есть поддержка, но с ограничениями.

Можно выделить две основные проблемы:

  • Некоторые решения не поддерживают удаление тегов с помощью Docker Registry API, что не позволяет пользователям использовать автоматическую очистку, реализованную в werf. Это справедливо для AWS ECR, Docker Hub и GitHub Packages.
  • Часть решений не поддерживают, так называемые, nested repositories (Docker Hub, GitHub Packages и Quay) или поддерживают, но пользователь должен создавать их вручную, используя UI или API (AWS ECR).

Эти и остальные проблемы мы собираемся решать с использованием нативных API у решений. В эту задачу также входит покрытие тестами полного цикла работы werf для каждого из них.

Распределённая сборка образов (↑)

  • Версия: v1.2 v1.1 (приоритет по реализации данной возможности был увеличен)
  • Сроки: март-апрель март
  • Issue

На данный момент, werf v1.0 и v1.1 можно использовать лишь на одном выделенном хосте для операций сборки и публикации образов и деплоя приложения в Kubernetes.

Чтобы открыть возможности распределенной работы werf, когда сборка и деплой приложений в Kubernetes запускаются на нескольких произвольных хостах и эти хосты не сохраняют свое состояние между сборками (временные runner’ы), от werf требуется реализация возможности использования Docker Registry в качестве хранилища стадий.

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

Примечание. Данная возможность не предполагает работу сборщика внутри pod'ов Kubernetes, т.к. для этого необходимо избавиться от зависимости от локального Docker-сервера (в pod'е Kubernetes нет доступа к локальному Docker-серверу, потому что сам процесс запущен в контейнере, а работу с Docker-сервером по сети werf не поддерживает и не будет поддерживать). Поддержка работы в Kubernetes будет реализована отдельно.

Официальная поддержка GitHub Actions (НОВОЕ)

  • Версия: v1.1
  • Сроки: март
  • Issue

Включает в себя документацию werf (разделы reference и guide), а также официальный GitHub Action для работы с werf.

Кроме того, позволит работать werf на эфемерных runner'ах.

Механика взаимодействия пользователя с CI-системой будет основана на выставлении label'ов на pull-request'ы для инициирования определенных действий по сборке/выкату приложения.

Локальная разработка и развёртывание приложений с werf (↓)

  • Версия: v1.1
  • Сроки: январь-февраль апрель
  • Issue

Главная цель — добиться единого унифицированного конфига для развёртывания приложений как локально, так и в production, без сложных действий, «из коробки».

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

Новый алгоритм очистки (НОВОЕ)

  • Версия: v1.1
  • Сроки: апрель
  • Issue

В текущей версии werf v1.1 в процедуре cleanup не предусмотрена очистка образов для схемы тегирования по содержимому (content-based tagging) — данные образы будут скапливаться.

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

Придуман новый унифицированный для всех схем тегирования алгоритм очистки образов на основе истории коммитов в Git:

  • Хранить не больше, чем N1 образов, связанных с N2 последними коммитами для каждого из git HEAD (ветки и теги).
  • Хранить не больше, чем N1 образов-стадий, связанных с N2 последними коммитами для каждого из git HEAD (ветки и теги).
  • Хранить все образы, которые используются в каких-либо ресурсах кластера Kubernetes (сканируются все kube-контексты файла конфигурации и namespace'ы; можно ограничить такое поведение специальными опциями).
  • Хранить все образы, которые используются в манифестах конфигурации ресурсов, сохраненных в Helm-релизах.
  • Образ может быть удален, если он не связан ни с одним HEAD из git (например, потому что сам соответствующий HEAD был удален) и не используется ни в одном из манифестов в кластере Kubernetes и в релизах Helm.

Параллельная сборка образов (↓)

  • Версия: v1.1
  • Сроки: январь-февраль апрель*

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

* Примечание: срок сдвинут из-за повышения приоритета по реализации распределенной сборки, которая добавит больше возможностей по горизонтальному масштабированию, а также использованию werf с GitHub Actions. Параллельная же сборка является следующим шагом оптимизации, дающим вертикальную масштабируемость при сборке одного проекта.

Переход на Helm 3 (↓)

  • Версия: v1.2
  • Сроки: февраль-март май*

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

* Примечание: переход на Helm 3 не добавит существенных возможностей в werf, потому что все ключевые фичи Helm 3 (3-way-merge и отсутствие tiller) уже реализованы в werf. Более того, werf имеет дополнительные возможности помимо указанных. Однако этот переход остается в наших планах и будет осуществлен.

Jsonnet для описания конфигурации Kubernetes (↓)

  • Версия: v1.2
  • Сроки: январь-февраль апрель-май

Werf будет поддерживать описание конфигурации для Kubernetes в формате Jsonnet. При этом werf останется совместимым с Helm и будет возможность выбора формата описания.

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

Также рассматривается возможность внедрения и других систем описания конфигурации Kubernetes (например, Kustomize).

Работа внутри Kubernetes (↓)

  • Версия: v1.2
  • Сроки: апрель-май май-июнь

Цель: обеспечить сборку образов и доставку приложения с использованием runner’ов в Kubernetes. Т.е. сборка новых образов, их публикация, очистка и деплой может происходить прямо из pod’ов Kubernetes.

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

Также требуется поддержка режима работы сборщика без Docker-сервера (т.е. Kaniko-подобная сборка или сборка в userspace).

Werf будет поддерживать сборку в Kubernetes не только с помощью Dockerfile, но и с помощью своего сборщика Stapel с инкрементальными пересборками и Ansible.

Шаг в сторону открытой разработки

Мы любим наше сообщество (GitHub, Telegram) и хотим, чтобы всё больше людей помогали делать werf лучше, понимали, в каком направлении мы движемся, и участвовали в разработке.

Совсем недавно было решено перейти на GitHub project boards для того, чтобы приоткрыть рабочий процесс нашей команды. Сейчас можно посмотреть ближайшие планы, а также текущие работы по следующим направлениям:

Проделана большая работа с issues:

  • Удалены неактуальные.
  • Существующие приведены к единому формату, достаточному количеству деталей и подробностей.
  • Добавлены новые issues с идеями и предложениями.

Как включить версию v1.1

Версия доступна на данный момент в канале 1.1 ea (в каналах stable и rock-solid релизы появятся по мере стабилизации, однако ea сама по себе уже достаточно стабильна для использования, т.к. прошла через каналы alpha и beta). Активируется через multiwerf следующим способом:

source $(multiwerf use 1.1 ea)
werf COMMAND ...

Заключение

Новая архитектура хранилища стадий и оптимизация работы сборщика для Stapel и Dockerfile сборщиков открывают возможности реализовать распределенные и параллельные сборки в werf. Данные возможности вскоре появятся в том же релизе v1.1 и станут автоматически доступны через механизм автообновлений (для пользователей multiwerf).

В данном релизе была добавлена стратегия тегирования по содержимому образов — content-based tagging, — которая стала стратегией по умолчанию. А также был переработан лог основных команд: werf build, werf publish, werf deploy, werf dismiss, werf cleanup.

Следующим существенным шагом станет добавление распределенных сборок. Распределенные сборки со времени v1.0 стали более приоритетной задачей, чем параллельные сборки, потому что добавляют больше ценности werf: вертикальное масштабирование сборщиков и поддержка эфемерных сборщиков в различных CI/CD-системах, а также возможность сделать официальную поддержку GitHub Actions. Поэтому сроки реализации параллельных сборок были сдвинуты. Однако мы работаем над тем, чтобы скорее реализовать обе возможности.

Следите за новостями! И не забывайте заглядывать к нам в GitHub, чтобы создать issue, найти уже существующий и поставить плюс, создать PR или просто понаблюдать за развитием проекта.

P.S.

Читайте также в нашем блоге:

Автор: Алексей Игрычев

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js