Привет! Я Андрей Квапил (или kvaps) и в этой статье я опишу наш путь организации доставки приложений в Kubernetes, объясню недостатки классического GitOps в локальной разработке и покажу, как новая утилита cozypkg решает эти проблемы. Материал рассчитан на разработчиков, знакомых с Helm и Flux.

Для начала пара слов о Cozystack, это важно для понимания контекста. Cozystack — это облачная платформа, которая позволяет запускать и предоставлять managed-сервисы: базы данных, виртуальные машины, K8s и другие — и берет на себя управление полным жизненным циклом каждого из них.

Cozystack предоставляет множество инфраструктурных сервсисов и интерфейс для их заказа через Kubernetes API. Сами сервисы запускаются с готовыми конфигурациями и преднастроенным мониторингом, алертами. В Cozystack есть как IaaS: managed Kubernetes, виртуальные машины — так и PaaS: Databases-as-a-Service, Queues, S3-бакеты и прочее.

Платформа базируется на Kubernetes и множестве свободных cloud native-компонентов: операторов, системы хранения, сетевой фабрики и подготовленного образа операционной системы (Talos Linux) с захардкоженной версий ядра и преднастроенными модулями, которые гарантируют стабильную работу всех компонентов.

За доставку компонентов в Cozystack отвечает Flux, он предоставляет унифицированный интерфейс для установки Helm-чартов. По сути, из всего Flux платформа использует только Helm-оператор, который позволяет задавать параметры деплоя через кастом-ресурсы HelmRelease.

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

Чарты можно разделить на несколько типов:

  • core. Основные компоненты платформы, которые формируют её логику. Те чарты которые используются для установки, запуска тестов и настройки всех остальных чартов и компонентов системы. Главный из таких чартов — platform. Он содержит конфигурацию для Flux, которая реконсайлится и применяется в кластер каждую минуту, реагируя на изменения в кластере.

  • system. Системные чарты, которые устанавливаются в кластер один раз. Это компоненты, необходимые для функционирования платформы: CSI, CNI, KubeVirt, операторы, Cluster API.

  • apps. Пользовательские чарты, которые устанавливаются конечными пользователями в тенантные неймспейсы. Они содержат минимальный набор параметров для конфигурирования в values.yaml, а также с помощью Cozystack API определяют пользовательские ресурсы в Kubernetes. В свою очередь, эти пользовательские ресурсы деплоят кастом-ресурсы для операторов, которые и управляют жизненным циклом приложения.

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

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

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

Для системных компонентов мы используем паттерн umbrella chart, который содержит единственную зависимость на апстримовый чарт.

Эта зависимость определяется не ссылкой на внешний чарт в апстрим-репозитории компонента. Весь необходимый код скачивается и хранится прямо в нашем репозитории, в директории charts основного Helm-чарта компонента.

Такой подход позволяет нам легко импортировать upstream-чарты, менять их на лету при необходимости и оверрайдить values на высоком уровне. Таким образом у каждого компонента получается примерно такая структура:

.
├── Chart.yaml           # Helm chart definition and parameter description
├── Makefile             # Common targets for simplifying local development
├── charts               # Directory for upstream charts
├── images               # Directory for Docker images
├── patches              # Optional directory for upstream chart patches
├── templates            # Additional manifests for the upstream Helm chart
├── values.yaml          # Override values for the upstream Helm chart
└── values.schema.json   # JSON schema used for input values validation and to render UI elements in dashboard

Внутри директории с Helm-чартом могут находиться еще и докерфайлы для сборки образов. Однако при их сборке мы автоматически получаем прописанные пути и дайджесты в values.yaml нашего компонента.

Здесь можно заметить и Makefile, который включает набор дефолтных таргетов для локальной разработки. По сути, у каждого чарта есть Makefile, который автоматически выставляет дефолтные переменные NAME и NAMESPACE. В Makefile доступен следующий набор таргетов:

make update  # Update Helm chart and versions from the upstream source
make image   # Build Docker images used in the package
make show    # Show output of rendered templates
make diff    # Diff Helm release against objects in a Kubernetes cluster
make apply   # Apply Helm release to a Kubernetes cluster

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

Изначально этот паттерн разработки (show, diff, apply) был позаимствован из оригинальной идеи Ksonnet. Сейчас он продолжает развиваться и в других инструментах для Jsonnet: Qbec и Grafana Tanka. Мы решили взять лучшее и применить тот же подход для Helm-чартов. В отличие от Jsonnet, Helm-чарты куда больше распространены в сегодняшнем мире и знакомы большинству инженеров, работающих с Kubernetes.

После тестирования можно закоммитить изменения в Git, а ревьювер увидит все изменённые манифесты и сможет их проконтролировать.

При формировании нового релиза мы просто пакуем все Helm-чарты из репозитория в контейнер и запускаем тестирование с ними. Если все тесты прошли успешно, формируется дистрибутив, готовый для установки на другие кластеры.

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

Все эти Makefil’ы выглядят достаточно просто. До того, как мы реализовали cozypkg, каждый таргет представлял собой небольшой shell-скрипт, который вытаскивал данные из fluxcd-ресурса в кластере и подсовывал их в Helm в виде values.yaml.

Для реализации diff использовался отдельный Helm-плагин — helm-diff, который выводит красивый diff с конфигами в кластере. Кроме того, существовал еще и скрипт fluxcd-kustomize.sh, который использовался как постпроцессор для Helm и добавлял все стандартные аннотации для Flux — в том числе и для локально отрендеренного чарта. Это было необходимо, чтобы diff отображал действительно только изменённые манифесты.

В какой-то момент у нас появилось желание объединить всю эту логику в едином инструменте. Так и появился cozypkg. Он сочетает в себе логику сразу нескольких инструментов: Helm, helm diff, командной утилиты flux, kubectl и нашего скрипта для пост-процессинга. Всё это упаковано в один go-бинарник (ровно в пять раз меньше, чем у Kubernetes?) и позволяет эффективно разрабатывать приложения с использованием описанного выше подхода.

Cozypkg заточен под локальную разработку Helm-чартов и тесно интегрируется с Flux.

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

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

Cozy wrapper around Helm and Flux CD for local development

Usage:
  cozypkg [command]

Available Commands:
  apply       Upgrade or install HelmRelease and sync status
  completion  Generate the autocompletion script for the specified shell
  delete      Uninstall the Helm release
  diff        Show a diff between live and desired manifests
  get         Get one or many HelmReleases
  help        Help about any command
  list        List HelmReleases
  reconcile   Trigger HelmRelease reconciliation
  resume      Resume Flux HelmRelease
  show        Render manifests like helm template
  suspend     Suspend Flux HelmRelease
  version     Print version

Flags:
  -h, --help                help for cozypkg
      --kubeconfig string   Path to kubeconfig
  -n, --namespace string    Kubernetes namespace (defaults to the current context)
  -v, --version             version for cozypkg

Use "cozypkg [command] --help" for more information about a command.

При применении локальных изменений cozypkg автоматически выставляет ресурсу HelmRelease-флаг suspend: true, чтобы избежать конфликтов одновременного деплоя со стороны Flux. При желании вернуть управление во Flux, этот флаг можно снять с помощью команды resume.

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

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

Мысли на будущее

Предвкушая ваши вопросы, почему мы не назвали эту утилиту cozyctl, отвечу так: Cozystack позиционирует себя как облачная платформа, а значит, он предоставляет конечным пользователям высокоуровневые ресурсы вроде kind: Kubernetes, kind: Postgres, kind: VirtualMachine. То есть они не работают с Helm-релизами напрямую, а работают с высокоуровневым API. Так что мы решили зарезервировать это название для нашей следующей утилиты, которая будет предназначена для работы именно с такими ресурсами.

cozypkg остается достаточно низкоуровневой утилитой и в первую очередь предназначена для разработчиков, использующих Helm и Flux в своих проектах.

Сейчас мы активно работаем над декомпозицией Cozystack и планируем развивать функциональность фреймворка, чтобы вы смогли реализовать свой собственный подключаемый репозиторий и предоставлять management сервис на базе Cozystack. cozypkg — один из необходимых шагов к тому, чтобы предоставить example-репозиторий и готовый flow для разработки плагинов для Cozystack.

Заключение

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

Будем рады обратной связи и pull-request’ам: https://github.com/cozystack/cozypkg

Happy coding & stay cozy!

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

Читайте также:

Видеозаписи докладов Андрея Квапила

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