This article is more than one year old. Older articles may contain outdated content. Check that the information in the page has not become incorrect since its publication.

Cozyhr: как мы упростили локальную разработку с Helm и Flux

Cozyhr: как мы упростили локальную разработку с Helm и Flux

Привет! Я Andrei Kvapil, CEO Ænix и разработчик Cozystack — платформы и фреймворка с открытым исходным кодом для построения облачной инфраструктуры. В этой статье я расскажу о том, как мы доставляем приложения в Kubernetes, объясню, почему обычный GitOps может быть неудобен при локальной разработке, и покажу, как новый инструмент cozyhr устраняет эти болевые точки. Статья рассчитана на инженеров, которые уже знакомы с Helm и Flux.

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

Cozystack предоставляет множество инфраструктурных сервисов и интерфейс для их запроса через Kubernetes API. Каждый сервис поставляется с готовыми конфигурациями, встроенным мониторингом и оповещениями. Одни сервисы относятся к IaaS (например, управляемый Kubernetes и виртуальные машины), другие — к PaaS (DBaaS, очереди, S3-бакеты и так далее).

Сама платформа построена поверх Kubernetes и использует множество бесплатных/открытых cloud-native компонентов. Среди них — операторы Kubernetes, система хранилища, сетевая фабрика, а также собственный образ Talos Linux с зафиксированной версией ядра и предзагруженными модулями, которые гарантируют стабильную работу всех компонентов.

Доставку этих компонентов обеспечивает Flux. На практике платформа использует только часть Flux — Helm Controller, который устанавливает Helm-чарты через кастомные ресурсы HelmRelease.

Хотя у каждого сервиса есть собственный CRD kind, под капотом каждый из них — это просто изолированный Helm-чарт, который определяет пользовательский интерфейс (как UI, так и API) для создания ресурсов.

Мы делим наши чарты на три категории:

  • основные чарты (core) — это фундаментальные части платформы, которые определяют её логику.
    Они используются для установки, тестирования и настройки всех остальных чартов.
    Ключевой чарт, platform, содержит настройки Flux и реконсилируется каждую минуту, подстраиваясь под изменения в кластере.
  • системные чарты (system) — это компоненты, устанавливаемые только один раз на кластер: CSI, CNI, KubeVirt, различные операторы, Cluster API и так далее.
  • чарты приложений (apps) — это чарты уровня арендатора, которые конечные пользователи устанавливают в своих пространствах имён. Они предоставляют лишь минимально необходимые параметры в values.yaml и используют Cozystack API для создания высокоуровневых ресурсов Kubernetes. Те, в свою очередь, порождают низкоуровневые кастомные ресурсы (CR) для операторов Kubernetes, которые уже запускают и управляют самими приложениями.

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

Cozy Flow: как организована разработка Cozystack

В Cozystack все компоненты живут в едином репозитории, который хранит их общую конфигурацию и шаблонизацию.
Чтобы поддержка была безболезненной, мы следуем нескольким принципам. Ключевой принцип: каждый компонент — это Helm-чарт.

Для системных компонентов мы используем паттерн umbrella chart: у чарта каждого компонента есть всего одна зависимость — upstream-чарт проекта. Мы включаем этот upstream-чарт прямо в репозиторий Cozystack, а не ссылаемся на внешний репозиторий. Это позволяет нам патчить его на лету, когда нужно, и переопределять значения конфигурации на более высоком уровне.

Типичная структура компонента выглядит так:

.
├── Chart.yaml           # Определение чарта и документация параметров
├── Makefile             # Общие цели для локальной разработки
├── charts               # Включённые upstream-чарты
├── images               # Dockerfile'ы / контекст сборки образа
├── patches              # Опциональные патчи для upstream
├── templates            # Дополнительные манифесты поверх
├── values.yaml          # Наши переопределения по умолчанию
└── values.schema.json   # JSON Schema для валидации + подсказки UI

Dockerfile’ы могут находиться прямо внутри директории чарта. После сборки образа путь к образу и его digest автоматически добавляются в values.yaml компонента.

Также вы заметите Makefile с целями по умолчанию, которые ускоряют рабочие процессы разработчиков:

make update  # Получить свежий upstream-чарт и версии
make image   # Собрать Docker-образы, используемые пакетом
make show    # helm template (рендеринг манифестов)
make diff    # Сравнить отрендеренный вывод с объектами в кластере
make apply   # Установить/обновить HelmRelease в кластере

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

Паттерн show / diff / apply впервые появился в Ksonnet и живёт в Jsonnet-инструментах, таких как Qbec и Grafana Tanka. Мы позаимствовали лучшее, но остались с Helm, который гораздо более распространён в мире Kubernetes.

После тестирования изменение коммитится, и ревьюер может изучить отрендеренные манифесты в PR.
При выпуске релиза мы упаковываем все Helm-чарты в контейнерный образ и запускаем тесты. Когда они проходят, публикуется дистрибутив, готовый к установке на других кластерах.

Техническая реализация

Все эти Makefile’ы довольно просты внутри. Изначально каждая цель make была тонким shell-скриптом: она извлекала данные из Flux-ресурсов (CR) в кластере, превращала их в values.yaml, а затем вызывала Helm.

Мы использовали плагин helm-diff, который показывает аккуратный diff того, что изменится в кластере. Другой скрипт, fluxcd-kustomize.sh, пост-обрабатывал вывод, добавляя аннотации Flux, чтобы helm diff показывал только реальные изменения.

В какой-то момент нам захотелось получить единый инструмент, который делал бы всё это.
Встречайте cozyhr — крошечный бинарник на Go (в 5 раз меньше, чем kubectl!), который объединяет функциональность множества других инструментов: Helm, helm-diff, flux CLI, kubectl и нашего собственного пост-процессора Flux.

cozyhr ориентирован на локальную разработку чартов и тесно интегрируется с Flux.
По умолчанию предполагается, что вы запускаете его из директории чарта.

Вот список всех доступных команд cozyhr:

$ cozyhr --help
Cozy wrapper around Helm and Flux CD for local development
Usage:
  cozyhr [command]
Available Commands:
  apply       Upgrade or install the HelmRelease and sync status
  completion  Generate shell‑autocomplete script
  delete      Uninstall the release
  diff        Show live vs desired manifests
  get         Get one or many HelmReleases
  list        List HelmReleases
  reconcile   Trigger Flux reconciliation
  resume      Resume a suspended release
  show        Render manifests (helm template)
  suspend     Suspend a release (Flux stops reconciling)
  version     Print version

Когда вы разворачиваете локальные изменения, cozyhr автоматически устанавливает suspend: true для HelmRelease, чтобы избежать гонки с Flux. Чтобы снова включить Flux, выполните cozyhr resume.

Мы также хотели улучшить обработку чартов. Для этого мы научили cozyhr добавлять корректные conditions в статусы ресурсов HelmRelease, чтобы другие зависимые релизы больше не ждали Flux и сразу получали правильный статус.

Мы используем такие составные чарты для развёртывания ресурсов в кластеры арендаторов. Например, один HelmRelease может породить набор дочерних релизов, которые устанавливают компоненты в кластере пользователя.

Взгляд в будущее

Вы можете спросить: «Почему бы не назвать инструмент cozyctl

Дело в том, что Cozystack позиционирует себя как платформа, которая предоставляет высокоуровневые ресурсы — вида kind: Kubernetes, kind: Postgres и kind: VirtualMachine. Конечные пользователи работают с высокоуровневым API и никогда не соприкасаются с Helm. Поэтому мы решили приберечь cozyctl для будущего инструмента, нацеленного на эти ресурсы. cozyhr`, напротив, остаётся низкоуровневым и предназначен в первую очередь для разработчиков, которые используют Helm и Flux в собственных проектах.

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

Заключение

С помощью cozyhr мы собираем наш опыт ускорения разработки в едином инструменте и делимся нашим подходом с сообществом.

Мы будем рады отзывам и pull request’ам: https://github.com/cozystack/cozyhr

Приятного кодинга и оставайтесь cozy!

Присоединяйтесь к сообществу Cozystack

Смотрите также

Записи докладов Andrei Kvapil