werf — это CLI-утилита с открытым кодом для сборки приложений и их деплоя в Kubernetes. С версией v1.2 она получила множество изменений и улучшений, которые мы так тщательно тестировали и дорабатывали, что релиз долгое время — с января 2021-го — находился в статусе Early-Access. Наконец, мы рады объявить о его переводе в категорию Stable!

Для тех, кому интересен список изменений в werf v1.2 относительно v1.1, в документации проекта есть достаточно подробный changelog (а самые любопытные пользователи следили за прогрессом работы на GitHub и в Telegram-чате). Эта статья немного о другом — она представляет актуальную версию werf, рассказывая о её предназначении и основных принципах работы.

Версия 1.1 была больше похожа на конструктор (или «комбайн»), который предлагал множество вариантов реализации одного и того же, но за этим следовали и потенциальные проблемы, если пользователь не учитывал все детали выбранного подхода. werf v1.2 делает шаг в сторону систематизации и улучшения консистивности доставки, упрощая ее и делая более предсказуемой.

Что такое werf

werf — CLI-инструмент с открытым кодом для консистентной сборки и доставки приложений в Kubernetes, который может использоваться для организации полного цикла CI/CD.

Обычно, если требуется создать пайплайн сборки и деплоя приложения с Docker и Helm, инженеру приходится самостоятельно настраивать и интегрировать все компоненты системы CI/CD. Настройку детерминированного тегирования образов, связывание сборки и развертывания на уровне CI-системы, реализацию автоматической очистки образов и многое другое приходится делать вручную.

werf предлагает готовую интеграцию между всеми компонентами, задействованными в CI/CD. Пользователь получает не только полностью детерминированный, готовый конвейер для сборки и доставки приложения, но и ряд уникальных фич, которые возможны благодаря тесной интеграции между Git, Docker, Helm, CI-системой и container registry. К примеру, werf cleanup выполняет «умную» очистку container registry, которая учитывает и состояние Git-репозитория, и его историю, и текущее использование образов в кластере.

Для GitLab CI полный цикл сборки, развертывания приложения и автоматической очистки образов, кеша и временных файлов можно реализовать в три команды:

. $(werf ci-env gitlab --as-file)  # Интеграция с GitLab CI.
werf converge  # Сборка и развертывание.
werf cleanup  # Очистка container registry.

При этом werf предоставляет пользователю возможность не только тонко настраивать вышеописанный конвейер, но и реализовывать гораздо более нестандартные схемы CI/CD. Более подробно об этом будет рассказано в разделе «Разные варианты доставки».

Гитерминизм

Что важно для воспроизводимости сборки в любом окружении? Чтобы «источник правды» был неизменным и единственным. Таким источником для werf служит Git. 

Мы используем понятие гитерминизм (Git + determinism) применительно к основному режиму работы werf. Это можно перевести как «режим, детерминированный Git’ом». werf читает конфиги и файлы сборочного контекста из текущего Git-коммита, исключая внешние зависимости.

Как обеспечивается гитерминизм:

  • werf читает всю конфигурацию и сборочный контекст напрямую из Git;

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

  • собираемые Docker-образы и развертываемые Kubernetes-ресурсы детерминированы Git’ом. При этом: а) werf сам управляет тегированием образов, пользователь получает уже протегированные образы; б) используется content-based-тегирование* для обеспечения оптимальных тегов с точки зрения пересборки, воспроизводимости и реализации принципа неизменяемости образов.

* Про теги в werf

Если в дополнение к content-based-тегам хочется получать произвольные теги, можно использовать алиасы тегов. Если content-based-тегирование не требуется, можно экспортировать образы из экосистемы werf с помощью werf export.

Гитерминизм — это инструмент, который позволяет контролировать предсказуемость, воспроизводимость и легкость сопровождения приложения. Под детерминированностью подразумеваются фиксированные входные данные и окружение для детерминированного алгоритма: «алгоритмический процесс, который выдаёт уникальный и предопределенный результат для заданных входных данных».

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

Отступление от дефолтной детерминированной конфигурации допустимо: можно работать, например, с незакоммиченными, неотслеживаемыми файлами и добавлять внешние зависимости. Но это должно быть явно указано (задекларировано) в werf_giterminism.yaml.

Стандартные технологии

werf обеспечивает интеграцию привычных для разработчика и DevOps-/SRE-инженера инструментов. Каждый из них выполняет определенную роль в CI/CD-процессе.

Технология

Функции в рамках werf

Git

Хранение кода и конфигурации. Сборка, кеширование и очистка на основе истории и состояния Git-репозитория.

Kubernetes

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

Container registry

Хранение бандлов, контейнеров, кэша и метаданных.

Docker

Сборка и запуск образов.

Helm

Выкат приложения. Организация конфигурации для Kubernetes: шаблонизация и параметризация, а также управление зависимостями.

CI-система

Непрерывная интеграция кода (werf совместима с любой CI-системой, а с GitLab и GitHub Actions интегрируется одной командой).

Docker Compose

Интеграция для локальной разработки.

Рассмотрим чуть подробнее, как werf использует и расширяет Docker, Helm и container registry.

Docker

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

Поддерживается и альтернативный синтаксис — Stapel, который полностью покрывает возможности Dockerfile-инструкций (в расширенном и более гибком варианте), а также предлагает дополнительную функциональность. 

Главная особенность Stapel — тесная интеграция с Git при сборке образов. Добавление файлов может выполняться не на определённом шаге сборки, как в случае с Docker, а быть плавающим: пользователь выставляет зависимости у команд, и добавление файлов происходит оптимальным образом. В итоге время сборок значительно сокращается за счёт эффективного инкрементального изменения исходного кода из Git.

Stapel-синтаксис удобен в сопровождении за счет YAML-формата и возможностей шаблонизации.

В статье «werf vs Docker. Чем лучше собирать образы» подробно рассказано обо всех отличиях и особенностях сборки в werf.

Helm

Популярное решение для развертывания приложений в Kubernetes. werf реализует деплой, используя расширенный и улучшенный Helm (форк от upstream-проекта с некоторыми патчами от нас встроен в утилиту).

Особенности:

  • Обратная совместимость: чарты для Helm можно применять в werf без изменений. Используются те же Helm-шаблоны, так же организована работа с values.

  • Интеграция с собираемыми образами: динамически генерируемые теги образов доступны через values.

  • Продвинутый трекинг статуса и расширенная конфигурация выката ресурсов, отображение логов запускающихся Pod’ов — для этого мы написали отдельную Open Source-библиотеку kubedog.

  • Работа с секретами «из коробки».

  • Автоматическая установка аннотаций и лейблов в ресурсы с полезной информацией (например, ссылка на job в CI/CD-системе и Git-коммит, из которого был выкачен ресурс).

  • Защита от конфликтов при параллельных выкатах в один и тот же контур: выкаты могут быть с разных хостов за счет использования распределенных блокировок.

В статье «werf vs. Helm» подробно рассказано о том, как Helm интегрирован в процессы werf.

Container registry

В container registry werf хранит конечные образы, бандлы (подробнее о них — ниже), а также сборочный кэш и метаданные. Метаданные обеспечивают эффективную сборку и очистку на основе истории Git.

werf использует container registry не только как хранилище артефактов, но и как часть механизма, обеспечивающего производительность и воспроизводимость всех сборок при совместном использовании. ​​Таким образом, с werf пользователь получает готовый к работе, гибкий, масштабируемый и производительный CI/CD — дополнительно ничего настраивать не нужно.

Поддерживаются различные схемы организации хранилища на основе нескольких типов container registry.

Разные варианты доставки

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

Первый вариант — werf converge. Cборка образов и деплой в Kubernetes в один шаг (для пользователя). Что при этом делает werf:

  • анализирует текущее состояние конфигурации из Git-коммита;

  • дособирает и публикует недостающие образы в хранилище;

  • приводит состояние Kubernetes к актуальному.

Другой подход — werf bundle publish и werf bundle apply. Бандлы позволяют выкатывать приложение без доступа к  Git-репозиторию, в котором приложение собирается. Как работают команды:

  • werf bundle publish готовит и публикует в container registry бандлы — артефакты, состоящие из собранных образов и инструкций для их развертывания;

  • werf bundle apply выкатывает бандл из container registry (доступ к Git-репозиторию уже не требуется, только к container registry).

Кроме того, для использования werf совместно с другими инструментами развертывания есть команды:

  • werf export — для сборки образов, отвязанных от werf;

  • werf render — для сборки образов и генерации манифестов (без развертывания);

  • werf run — для сборки образов и запуска контейнеров.

Как попробовать werf

Quickstart по началу работы с актуальной версией werf доступен на сайте проекта.

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

* «Первые шаги» самоучителя доступны для всех фреймворков, а второй раздел в настоящий момент готов для Node.js, Laravel и Ruby on Rails.

Заключение

Несмотря на статус stable для werf v1.2, работа по расширению функциональности продолжается. Мы планируем завершить интеграцию с Buildah по следующим направлениям:

  • Поддержка Dockerfile (уже реализовано).

  • Поддержка Stapel.

  • Инструкции для запуска внутри Docker-контейнера (dind) и в Kubernetes.

  • Эффективный и версионированный кэш в container registry вместо маунтов и multistage.

Мы уже давно используем werf v1.2 в production и уверены в стабильности новой версии. Но это, конечно, не значит, что проблемы исключены. Если у вас есть вопросы про релиз или про работу werf в целом — приходите в Telegram-чат проекта; будем рады помочь!

P.S.

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

Комментарии (7)


  1. gserge
    01.12.2021 14:54
    +7

    Ура! Спасибо команде разработки.


  1. sundmoon
    01.12.2021 21:11
    +1

    Есть Waypoint vs. Other Software | Waypoint by HashiCorp (waypointproject.io)

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

    Можете прокомментировать? Возможно ли взять лучшее и там, и тут?


    1. aigrychev Автор
      02.12.2021 01:19

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

      У нас во всех проектах при каждом коммите автоматически создаётся CI-пайплайн. В нём собираются образы, выполняются тесты, приложение для отладки и оставшихся проверок выкатывается на различные Kubernetes-контуры, и если всё хорошо — изменения доходят до конечного пользователя.

      Условно следующий набор шагов:

      werf build                     # сборка образов                     
      werf run || werf compose up    # произвольное количество шагов тестирования компонентов 
      werf compose --env review-<ID> # выкат на легковесный ревью контур
      werf compose --env staging     # выкат на production-like контур
      werf compose --env production  # выкат на production

      p.s. количество шагов / пайплайнов, а также зависимости (вручную, автоматически, при изменении определённой ветки ...) произвольны.


      1. aigrychev Автор
        02.12.2021 10:22

        UPDATE: последние три команды в примере это конечно же werf converge, а не werf compose


    1. tkir
      02.12.2021 18:00

      Werf поддерживает данное разделение публикации артефактов и релиза с помощью т.н. бандлов: https://werf.io/documentation/v1.2/advanced/bundles.html

      • werf bundle publish готовит и публикует в container registry бандлы — артефакты, состоящие из собранных образов и инструкций для их развертывания;

      • werf bundle apply выкатывает бандл из container registry (доступ к Git-репозиторию уже не требуется, только к container registry).


    1. vitaly_il1
      02.12.2021 22:38

      деплой артефактов и релиз (публикация запущенного приложения) должны быть разделены на уровне воркфлоу

      Имеется в виду публикация артифактов? Если да, то ИМХО обычно сегодня так и делают.


      1. aigrychev Автор
        03.12.2021 18:49

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