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.

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