Cozystack Руководство по разработке

Cozystack Руководство по разработке

Как это работает

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

  1. Инсталлятор чарта (packages/core/installer) применяется через helm install. Он разворачивает Deployment cozystack-operator в пространстве имён cozy-system.

  2. cozystack-operator запускается и выполняет однократную начальную загрузку:

    • Устанавливает CRD Cozystack (Package, PackageSource) из встроенных манифестов (internal/crdinstall).
    • Устанавливает компоненты Flux (source-controller, helm-controller, source-watcher) из встроенных манифестов (internal/fluxinstall).
    • Создаёт начальный OCIRepository (cozystack-platform) из значений platformSourceUrl и platformSourceRef, заданных в инсталляторе.
    • Создаёт PackageSource, ссылающийся на начальный OCIRepository.
  3. Цикл согласования берёт управление. Оператор следит за CRD PackageSource и Package и преобразует их в объекты Flux HelmRelease. Flux затем устанавливает реальные Helm-чарты и управляет ими.

  4. Platform chart (packages/core/platform) разворачивается как обычный Package. Он читает конфигурацию кластера из ресурса cozystack.cozystack-platform Package и создаёт шаблоны манифестов пакетов, определяющих, какие системные компоненты должны быть установлены.

    Platform chart также создаёт вторичный OCIRepository (cozystack-packages), копируя спецификацию из начального OCIRepository. Все PackageSource ссылаются на этот вторичный репозиторий. При обновлениях platform chart выполняет миграции как pre-upgrade хуки перед созданием или обновлением HelmRelease компонентов.

  5. FluxCD — движок выполнения, он согласует объекты HelmRelease, созданные оператором, загружает артефакты чартов из ресурсов ExternalArtifact и применяет их к кластеру.

Полную цепочку согласования (PackageSource → ArtifactGenerator → ExternalArtifact → Package → HelmRelease → Pods), разрешение зависимостей, потоки обновления и отката, а также CLI cozypkg см. в разделе Ключевые концепции.

OCIRepository и поток миграции

Cozystack использует два ресурса OCIRepository для управления обновлениями платформы:

OCIRepositoryСоздаётсяСсылается на
cozystack-platformcozystack-operatorНастраивается через значения инсталлятора (platformSourceUrl, platformSourceRef)
cozystack-packagesPlatform chart (repository.yaml)Копирует спецификацию из cozystack-platform

Все PackageSource в packages/core/platform/sources/ ссылаются на cozystack-packages.

Выполнение миграций

Миграции выполняются как Helm pre-upgrade хуки в platform chart:

# packages/core/platform/templates/migration-hook.yaml
metadata:
  name: cozystack-migration-hook
  annotations:
    helm.sh/hook: pre-upgrade,pre-install
    helm.sh/hook-weight: "1"

Контейнер миграции считывает текущую версию из ConfigMap cozystack-version и выполняет скрипты миграции последовательно от CURRENT_VERSION до TARGET_VERSION - 1. Каждая миграция обновляет ConfigMap при успехе, обеспечивая идемпотентность миграций и возможность возобновления после сбоев.

Зачем два репозитория?

Разделение гарантирует, что:

  1. Начальный OCIRepository управляется оператором (через значения инсталлятора).
  2. Все PackageSource имеют согласованную ссылку (cozystack-packages), а не указывают напрямую на источник, управляемый оператором.
  3. Platform chart может выполнять миграции перед созданием вторичного OCIRepository, гарантируя выполнение миграций до обновления компонентов.

Ключевые бинарные файлы

Бинарный файлИсточникРоль
cozystack-operatorcmd/cozystack-operatorНачальная загрузка (CRD, Flux, источник платформы), согласование PackageSource и Package, репликация секрета cozystack-values.
cozystack-controllercmd/cozystack-controllerСогласование рабочих нагрузок и ApplicationDefinition, управление дашбордами.
cozystack-apicmd/cozystack-apiУровень агрегации API Kubernetes для групп API apps.cozystack.io и core.cozystack.io.
cozypkgcmd/cozypkgCLI-инструмент для управления пакетами — визуализация зависимостей, интерактивная установка и удаление.

Структура репозитория

Основная структура репозитория cozystack:

.
├── api             # Go-типы для CRD Cozystack (Package, PackageSource и т.д.)
├── cmd             # Точки входа для всех бинарных файлов
│   ├── cozystack-operator      # Основной оператор платформы
│   ├── cozystack-controller    # Контроллеры рабочих нагрузок и приложений
│   ├── cozystack-api           # Агрегированный API-сервер
│   └── cozypkg                 # CLI для управления пакетами
├── internal        # Реализации контроллеров и согласователей
│   ├── operator                # Согласователи PackageSource и Package
│   ├── controller              # Контроллеры рабочих нагрузок и ApplicationDefinition
│   ├── fluxinstall             # Встроенные манифесты Flux и инсталлятор
│   ├── crdinstall              # Встроенные манифесты CRD и инсталлятор
│   └── cozyvaluesreplicator    # Логика репликации секретов
├── packages        # Helm-чарты, организованные по слоям
│   ├── core            # Начальная загрузка и конфигурация платформы
│   ├── system          # Инфраструктурные операторы и upstream-чарты
│   ├── apps            # Пользовательские чарты приложений
│   └── extra           # Чарты приложений для конкретных тенантов
├── pkg             # Общие Go-библиотеки
├── dashboards      # Дашборды Grafana
├── hack            # Вспомогательные скрипты для локальной разработки
└── docs            # Журналы изменений и примечания к релизам

Разработку можно вести локально, изменяя и обновляя файлы в этом репозитории.

Пакеты

core

Core-пакеты отвечают за начальную загрузку и конфигурацию на уровне платформы.

installer

Helm-чарт, разворачивающий Deployment cozystack-operator. Он создаёт пространство имён cozy-system, ServiceAccount с правами cluster-admin и Deployment оператора с флагами, инициирующими установку CRD и Flux при запуске. Образ оператора и URL источника платформы задаются во время сборки.

platform

Helm-чарт, разворачиваемый как обычный Package (не применяется напрямую). Он читает конфигурацию кластера из ресурса cozystack.cozystack-platform Package и создаёт шаблоны манифестов согласно указанному варианту и настройкам компонентов, определяя, какие системные компоненты должны быть установлены.

flux-aio

Компоненты Flux, упакованные для развёртывания оператором.

talos

Конфигурационные ресурсы Talos OS.

system

System-пакеты настраивают систему для управления и развёртывания пользовательских приложений. Необходимые системные компоненты указываются в конфигурации пакета.

System-пакеты включают два вида компонентов:

  • Операторы (например, postgres-operator, kafka-operator, redis-operator): Контроллеры, умеющие управлять полным жизненным циклом конкретного приложения, включая операции второго дня.
  • Upstream Helm-чарты для приложений без выделенного оператора (например, nats, ingress-nginx): Эти чарты размещаются в system, чтобы пакеты apps и extra могли разворачивать их через Flux HelmRelease CR, фактически используя FluxCD в качестве оператора.

apps

Эти пользовательские приложения отображаются в дашборде и включают манифесты для применения к кластеру.

Чарты apps служат высокоуровневым API для пользователей. Они определяют только те параметры, которые должны быть открыты и проверены через values.schema.json, сохраняя интерфейс минимальным и безопасным. Чарты apps не должны содержать бизнес-логику развёртывания самого приложения — вместо этого они делегируют её оператору или FluxCD.

В зависимости от наличия выделенного оператора приложения apps следуют одному из двух паттернов:

Паттерн на основе оператора

Когда для приложения есть выделенный оператор (например, PostgreSQL, MongoDB, Redis, Kafka), чарт app создаёт экземпляры CRD, которыми управляет оператор:

packages/system/postgres-operator/   # Helm-чарт оператора
packages/apps/postgres/              # App-чарт создаёт postgresql.cnpg.io/v1.Cluster CR

Оператор обрабатывает все детали развёртывания и операции второго дня (масштабирование, резервное копирование, переключение при сбое). App-чарт просто создаёт соответствующий CRD со значениями, полученными из пользовательского ввода.

Паттерн на основе HelmRelease

Когда для приложения нет выделенного оператора и стандартным методом развёртывания является Helm-чарт, upstream-чарт размещается в system/, а app-чарт создаёт Flux HelmRelease CR, указывающий на него:

packages/system/nats/                # Upstream Helm-чарт NATS
packages/apps/nats/                  # App-чарт создаёт helm.toolkit.fluxcd.io/v2.HelmRelease

В этом случае FluxCD выступает оператором, управляя жизненным циклом Helm-релиза. App-чарт контролирует, какие upstream-значения открываются пользователю, обеспечивая дополнительный уровень безопасности — пользователи не могут обойти валидацию для развёртывания чарта с произвольными значениями.

Другие примеры этого паттерна: extra/ingress, extra/seaweedfs, extra/monitoring.

extra

Аналогично apps, но не отображается в каталоге приложений. Могут устанавливаться только в составе тенанта. Разрешены для использования нижележащими тенантами, установленными в пространстве имён текущего тенанта.

Подробнее о Системе тенантов читайте на странице основных концепций.

В одном пространстве имён тенанта можно использовать только один тип приложения.

Extra-пакеты следуют тем же двум архитектурным паттернам, что и apps (на основе оператора или HelmRelease).

Структура пакета

Каждый пакет — это типичный Helm-чарт, содержащий все необходимые образы и манифесты для платформы. Мы следуем логике umbrella-чарта, размещая upstream-чарты в директории ./charts и переопределяя values.yaml в корне приложения. Такая структура упрощает обновление upstream-чартов.

.
├── Chart.yaml                           # Определение Helm-чарта и описание параметров
├── Makefile                             # Общие цели для упрощения локальной разработки
├── charts                               # Директория для upstream-чартов
├── images                               # Директория для Docker-образов
├── patches                              # Опциональная директория для патчей upstream-чартов
├── templates                            # Дополнительные манифесты для upstream Helm-чарта
├── templates/dashboard-resourcemap.yaml # Роль для отображения ресурсов k8s в дашборде
├── values.yaml                          # Значения переопределения для upstream Helm-чарта
└── values.schema.json                   # JSON-схема для валидации входных значений и отрисовки элементов UI в дашборде

Для генерации файлов README.md и values.schema.json можно использовать readme-generator от Bitnami.

Просто установите его как бинарный файл readme-generator в своей системе и запустите генерацию командой make generate.

Принципы разработки Helm-чартов

Структура пакетов и рабочий процесс разработки в Cozystack основаны на следующих принципах:

Простое обновление upstream-чартов

Оригинальный upstream-чарт должен быть легко обновляемым, переопределяемым и изменяемым. Мы используем паттерн umbrella-чарта — upstream-чарты находятся в директории ./charts и хранятся в оригинальном виде. Кастомизации вносятся через переопределения values.yaml и дополнительные templates/, а структурные изменения в upstream-чарте применяются через patches/. Такое разделение гарантирует простое обновление до новой upstream-версии: выполните make update, просмотрите diff и при необходимости повторно примените патчи.

Локальные артефакты

Патчи и образы контейнеров хранятся локально и являются частью пакета. Директория patches/ содержит любые изменения upstream-чарта, а директория images/ — Dockerfile для сборки всех необходимых образов. Это обеспечивает полную воспроизводимость — всё необходимое для сборки и развёртывания пакета самодостаточно внутри репозитория.

Рабочий процесс локальной разработки и тестирования

Каждый пакет должен быть легко обновляемым и тестируемым локально на реальном кластере без использования CI. Стандартные цели make (make image, make diff, make apply) обеспечивают быструю обратную связь: сборка образов, сравнение отрендеренных манифестов с живым кластером и применение изменений — всё с рабочей станции разработчика.

Без внешних зависимостей

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

Разработка

Настройка Buildx

Для сборки образов необходимо установить и настроить плагин docker buildx.

Вместо встроенного сборщика можно настроить дополнительные, которые могут быть удалёнными или поддерживать несколько архитектур. В этом примере показано, как создать сборщик с драйвером kubernetes, позволяющим собирать образы непосредственно в кластере Kubernetes:

docker buildx create \
  --bootstrap \
  --name=buildkit \
  --driver=kubernetes \
  --driver-opt=namespace=tenant-kvaps,replicas=2 \
  --platform=linux/amd64 \
  --platform=linux/arm64 \
  --use

Либо опустите параметры –driver*, чтобы настроить среду сборки в локальном Docker-окружении.

Управление пакетами

Каждое приложение включает Makefile для упрощения процесса разработки. Для каждого пакета мы следуем такой логике:

make update  # Обновить Helm-чарт и версии из upstream-источника
make image   # Собрать Docker-образы, используемые в пакете
make show    # Показать вывод отрендеренных шаблонов
make diff    # Сравнить Helm-релиз с объектами в кластере Kubernetes
make apply   # Применить Helm-релиз к кластеру Kubernetes

Например, для обновления cilium:

cd packages/system/cilium         # Перейти в директорию приложения
make update                       # Загрузить новую версию из upstream
make image                        # Собрать образ cilium
git diff .                        # Показать diff с изменёнными манифестами
make diff                         # Показать diff с применёнными манифестами кластера
make apply                        # Применить изменённые манифесты к кластеру
kubectl get pod -n cozy-cilium    # Проверить корректность работы
git commit -m "Update cilium"     # Зафиксировать изменения в ветке

Для сборки контейнера cozystack с обновлённым чартом:

cd packages/core/installer        # Перейти в директорию пакета cozystack
make image-packages               # Собрать образ пакетов
make apply                        # Применить к кластеру
kubectl get pod -n cozy-system    # Проверить корректность работы
kubectl get hr -A                 # Проверить объекты HelmRelease

Тестирование

Платформа включает скрипт e2e.sh, выполняющий следующие задачи:

  • Запускает три виртуальные машины QEMU
  • Настраивает Talos Linux
  • Устанавливает Cozystack
  • Ожидает установки всех HelmRelease
  • Выполняет дополнительные проверки работоспособности компонентов

Скрипт e2e.sh можно запускать как локально, так и непосредственно в контейнере Kubernetes.

Для запуска тестов в кластере Kubernetes перейдите в директорию packages/core/testing и выполните следующие команды:

make apply    # Создать тестовую песочницу в кластере Kubernetes
make test     # Запустить end-to-end тесты в существующей песочнице
make delete   # Удалить тестовую песочницу из кластера Kubernetes

Динамическая среда разработки

Если вы предпочитаете разрабатывать Cozystack в виртуальных машинах вместо изменения существующего кластера, можно использовать ту же песочницу из тестовой среды. Makefile в packages/core/testing включает дополнительные опции:

make exec     # Открывает интерактивную оболочку в контейнере песочницы.
make login    # Загружает kubeconfig во временную директорию и запускает оболочку с окружением песочницы; требуется установленный mirrord.
make proxy    # Включает SOCKS5 прокси-сервер; требуются mirrord и gost.

Прокси Socks5 можно настроить в браузере для доступа к сервисам кластера, работающего в песочнице. В Firefox есть удобное расширение для переключения прокси: