Helm 3.7 + Harbor OCI: charts и образы в одном registry
Helm 3.7 стабилизировал OCI-реестры для хранения charts. Переносим клиентский chart-репозиторий с ChartMuseum на Harbor: сканирование, pipeline и один registry на всё.
Helm 3.7 переводит поддержку OCI-реестров для хранения Helm charts из экспериментальной в стабильную
Helm 3.7 вышел на этой неделе, и главная новость там - OCI-поддержка charts вышла из-за флага HELM_EXPERIMENTAL_OCI=1 и стала частью стабильного API. Для нас это был сигнал: наконец-то можно делать то, что мы откладывали уже несколько месяцев - переводить chart-репозиторий клиента с ChartMuseum на Harbor.
Расскажем, как это выглядело на практике.
Почему ChartMuseum начал раздражать
ChartMuseum - вполне рабочий инструмент, и мы не собираемся на него катить. Но у клиента уже стоял Harbor для container images, и поддерживать два отдельных сервиса - это две точки отказа, две точки обновления, две точки настройки авторизации. При этом Harbor поддерживает OCI artifacts достаточно давно, просто до Helm 3.7 это было экспериментально и включалось флагом окружения на каждой машине разработчика.
Второй аргумент - сканирование. Trivy в Harbor сканирует container images автоматически при push. Charts там не образы, но тоже содержат yaml-шаблоны с references на образы. Хотелось иметь возможность хотя бы видеть, что лежит в одном месте. После того как мы настроили сканирование container images через Trivy, концентрировать всё в Harbor выглядело логично.
Что изменилось в Helm 3.7
До 3.7 OCI-функциональность жила за экспериментальным флагом и имела несколько неприятных особенностей: отдельный логин командой helm registry login, несовместимый с обычным helm repo add, и часть команд вела себя иначе, чем с обычными репозиториями.
В 3.7 OCI-реестры интегрированы в стандартный workflow. Флаг HELM_EXPERIMENTAL_OCI больше не нужен (и фактически игнорируется). Команды helm push, helm pull, helm show работают с oci:// схемой напрямую. Авторизация через helm registry login теперь совместима с docker-credential-helpers, что упрощает работу в CI.
Важный нюанс: chart-репозитории в классическом смысле (helm repo add) и OCI-реестры - это разные модели. В OCI нет index.yaml, нет helm repo update. Каждый chart - это отдельный OCI artifact с тегом-версией. Это ломает ряд привычных вещей, о которых скажем ниже.
Настройка Harbor
Harbor мы использовали версии 2.3, которая поддерживает OCI Distribution Spec 1.0. Для charts создали отдельный project - helm-charts. Никаких специальных настроек проекта для OCI artifacts не требуется, Harbor воспринимает их автоматически.
Права доступа настраиваются теми же robot accounts, что и для образов. Это, собственно, одно из главных преимуществ: один robot account с нужными правами работает и для docker pull, и для helm pull.
# Логин - один раз, credentials кешируются в ~/.config/helm/registry/config.json
helm registry login harbor.example.com \
--username robot$ci-account \
--password <токен>
Pipeline: push chart в Harbor
Клиентский пайплайн в GitLab. После сборки и тестирования chart публикуется в Harbor:
publish-chart:
stage: publish
image: alpine/helm:3.7.1
script:
- helm registry login ${HARBOR_HOST}
--username ${HARBOR_USER}
--password ${HARBOR_PASSWORD}
- helm package charts/${CHART_NAME}
--version ${CI_COMMIT_TAG}
--app-version ${CI_COMMIT_TAG}
- helm push ${CHART_NAME}-${CI_COMMIT_TAG}.tgz
oci://${HARBOR_HOST}/helm-charts
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
При pull в кластере:
helm pull oci://harbor.example.com/helm-charts/app-name --version 1.2.3
# или сразу install
helm install my-release \
oci://harbor.example.com/helm-charts/app-name \
--version 1.2.3 \
-f values-prod.yaml
Что сломалось при переезде
helm search repo не работает с OCI. В классическом репозитории helm search repo ищет по index.yaml. Для OCI-реестра этой команды нет - нужно смотреть в Harbor UI или использовать Harbor API. Для команды разработчиков, привыкших к helm search, это неудобно. Мы написали небольшой bash-скрипт, который дёргает Harbor API и выводит список charts с версиями в похожем формате.
Helmfile и зависимости. Helmfile поддерживает OCI начиная с версии 0.141.0. Клиент использовал 0.138 - пришлось обновить. Синтаксис в helmfile.yaml меняется: вместо repository: ... + chart: repo/name нужно писать chart: oci://harbor.example.com/helm-charts/app-name.
Chart dependencies через OCI. Если в Chart.yaml указаны dependencies с repository: "oci://...", то helm dependency update работает, но требует предварительного helm registry login. В CI это решается добавлением логина в начало скрипта, но нужно помнить.
Сканирование charts в Harbor
Trivy в Harbor умеет сканировать OCI artifacts, но charts сканируются иначе, чем образы. По факту Trivy разбирает chart как архив и ищет в нём references на образы, после чего сканирует эти образы. Это не то же самое, что сканировать сам chart на предмет misconfiguration в yaml - для этого нужен отдельный инструмент вроде helm lint или Checkov/Conftest.
Для клиента настроили автоматическое сканирование при push через политики Harbor. Плюс добавили helm lint в pipeline перед публикацией - это ловит синтаксические ошибки и явные несоответствия.
Что в итоге
Переезд занял примерно день с учётом обновления всех клиентских машин разработчиков и обновления Helmfile. ChartMuseum отключён, Harbor обслуживает и образы, и charts. Robot accounts единые, логин один.
Из неочевидного: мы потеряли helm search repo и получили необходимость смотреть версии через Harbor UI или API. Это реальное неудобство, и если в команде активно пользовались поиском по репозиторию - нужно готовиться. Плюс документацию пришлось обновить в нескольких местах, где были примеры с helm repo add.
OCI-подход к charts - это стандарт дистрибуции артефактов, который уже работает для образов. Иметь один registry вместо двух выглядит разумно. Но это не бесплатный переезд, и несколько вещей, привычных по ChartMuseum, там просто отсутствуют.