Упаковка и публикация: package, репозиторий, OCI

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

helm package собирает чарт в версионированный .tgz-архив. Дальше архив кладут в репозиторий — классический HTTP с index.yaml или современный OCI-реестр (там же, где Docker-образы).

Упаковка

helm dependency update ./webapp     # подтянуть subchart-ы перед упаковкой
helm package ./webapp               # webapp-1.2.0.tgz
helm package ./webapp --version 1.2.1 --app-version 2.5.0

Имя архива формируется как <name>-<version>.tgz из Chart.yaml. Версия чарта в имени — поэтому в репозитории спокойно лежат несколько версий одного чарта.

Здесь важно держать в голове различие двух версий из Chart.yaml. version — это версия самого чарта (его шаблонов и дефолтов), она обязана быть валидным SemVer и попадает в имя архива. appVersion — это версия приложения, которое чарт разворачивает; она информационная, может быть любой строкой (тег образа, дата) и на разрешение зависимостей не влияет. На практике их путают: меняют образ приложения, но забывают поднять version чарта — и публикация молча перетирает старый артефакт. Правило простое: любое изменение в чарте, даже однострочная правка values-дефолта, требует инкремента version, потому что репозиторий идентифицирует чарт именно по нему.

Полезно понимать, что .tgz — это просто gzip-архив директории чарта: Chart.yaml, values.yaml, templates/, charts/ с уже скачанными зависимостями. Никакой «компиляции» не происходит, рендер по-прежнему случится у потребителя на install. Поэтому всё, что вы положили в charts/ на момент упаковки, замораживается в архиве — отсюда и важность dependency update ровно перед package.

Классический HTTP-репозиторий с index.yaml

Репозиторий — это директория с архивами и индексом. Индекс генерируется командой:

mkdir repo
mv webapp-1.2.0.tgz repo/
helm repo index repo --url https://charts.example.com

Файл index.yaml перечисляет все чарты, версии и URL архивов. Выложите директорию на любой статический хостинг (S3, GitHub Pages, nginx) — и это рабочий Helm-репозиторий. При добавлении нового чарта индекс перегенерируют с --merge, чтобы не потерять старые записи.

Красота этого способа — в полном отсутствии серверной логики. Helm-репозиторий по своей сути не требует «приложения»: это просто HTTP-эндпоинт, отдающий статические файлы. Поэтому популярнейший бесплатный вариант для open-source — GitHub Pages: складываете архивы и index.yaml в ветку gh-pages, и у вас публичный репозиторий без единого сервера. Обратная сторона — ручной труд: каждый релиз требует положить новый .tgz, перегенерировать индекс с --merge и закоммитить. Забыли --merge — индекс перезаписался с нуля, и все прежние версии «исчезли» для клиентов, хотя архивы физически на месте. На больших каталогах эта ручная операция становится узким местом, и команды переходят к серверу с API.

ChartMuseum: репозиторий с API

Статический индекс неудобно обновлять. ChartMuseum — сервер-репозиторий, в который чарты заливают по HTTP, а индекс он пересобирает сам:

# залить чарт в ChartMuseum
curl --data-binary "@webapp-1.2.0.tgz"   https://chartmuseum.example.com/api/charts

# подключить как обычный репозиторий
helm repo add internal https://chartmuseum.example.com
helm repo update
helm search repo internal/webapp

Ценность ChartMuseum в том, что он берёт на себя пересборку индекса: вы просто POST-ите архив, а сервер сам обновляет index.yaml, считает digest и отдаёт всё клиентам. Сверху он умеет хранить чарты в облачных бэкендах (S3, GCS, Azure Blob), разграничивать доступ по базовой аутентификации и отдавать метрики. Это закрывает разрыв между «статикой руками» и тяжёлым OCI-реестром — особенно там, где уже есть устоявшийся CI, заливающий артефакты по HTTP. Минус ровно один, но существенный: это ещё один сервис, который надо развернуть, обновлять и мониторить, тогда как OCI-реестр у многих команд уже есть для образов.

OCI-реестр: современный путь

С Helm 3.8+ чарты можно хранить в OCI-реестрах — тех же, где Docker-образы (Docker Hub, GitHub Container Registry, Harbor, ECR). Никакого index.yaml: реестр сам индексирует артефакты. Это рекомендуемый сегодня способ.

# залогиниться в реестр
helm registry login registry.example.com -u user

# запушить чарт как OCI-артефакт
helm push webapp-1.2.0.tgz oci://registry.example.com/charts

# поставить прямо из OCI (repo add не нужен!)
helm install web oci://registry.example.com/charts/webapp --version 1.2.0

Обратите внимание: для OCI helm repo add не требуется — вы ссылаетесь на чарт по полному oci://-пути. Это упрощает инфраструктуру: один реестр и для образов, и для чартов.

У OCI-подхода есть и практические преимущества, ради которых на него и переходят. Во-первых, единая аутентификация и RBAC: тот же docker login/helm registry login, те же права на репозиторий, что и для образов, — не нужно отдельно администрировать доступ к Helm-репозиторию. Во-вторых, чарты получают весь арсенал реестра: сканирование на уязвимости, политики хранения (retention), а главное — подпись и проверку через cosign, что закрывает вопрос «откуда взялся этот чарт и не подменили ли его». В-третьих, нет проблемы устаревающего index.yaml: в больших репозиториях на тысячи версий этот файл разрастается до десятков мегабайт, и каждый repo update качает его целиком; OCI же отдаёт только нужный тег.

Есть и подводные камни. Поиск по OCI ограничен: привычный helm search repo работает по локальному индексу классического репозитория, а в OCI его нет — список тегов смотрят средствами самого реестра. И версия чарта в OCI становится тегом артефакта, поэтому правила SemVer и неизменяемости тегов здесь критичны вдвойне: перезалив того же тега молча подменит чарт у всех, кто на него ссылается.

Сравнение способов

СпособПлюсМинус
Статический HTTP + index.yamlпрост, любой хостингиндекс обновляют вручную
ChartMuseumзаливка по APIотдельный сервис
OCI-реестрединый с образами, без index.yamlнужен Helm 3.8+

Как индекс работает под капотом

В классическом репозитории клиент Helm при repo add/update скачивает только index.yaml — небольшой файл со списком чартов, версий, их хешами и URL архивов. Поиск и разрешение версий идут по этому локальному индексу; сам .tgz качается лишь при install. В OCI всё иначе: чарт — это OCI-артефакт с манифестом и слоями (как образ), а «индекс» обеспечивает протокол реестра — клиент спрашивает теги и тянет нужный артефакт напрямую. Поэтому OCI не нуждается в отдельном index.yaml и масштабируется как обычный контейнерный реестр.

Стоит развеять частое заблуждение, что в index.yaml «лежат чарты». Индекс хранит только метаданные и ссылки, а архивы — рядом, на том же хостинге. Поле digest для каждой версии — это SHA-256 архива; именно по нему Helm проверяет, что скачанный .tgz не повреждён и совпадает с тем, что описано в индексе. Отсюда вытекает и типичная авария: если перезаписать архив, не обновив индекс (или наоборот), digest перестанет сходиться и install упадёт с ошибкой целостности. Поэтому индекс всегда генерируют после того, как все архивы уже лежат в директории.

В OCI роль такого манифеста играет дескриптор артефакта с собственным media-type для Helm-чартов (application/vnd.cncf.helm.chart.content.v1.tar+gzip). Реестр различает по этому типу, что перед ним чарт, а не образ контейнера, хотя хранятся они в одном бэкенде. Благодаря этому один и тот же Harbor или GHCR спокойно держит и образы приложения, и чарт, который их разворачивает, — что и делает OCI «единым» хранилищем артефактов.

Частые ошибки

  • Забыть dependency update перед package. Архив уедет без subchart-ов, install у потребителя упадёт.
  • Перегенерировать индекс без --merge. Потеряете записи старых версий.
  • Не поднять версию чарта. Публикация с той же версией — конфликт/перезапись; всегда инкрементируйте version.

Итог

  • helm package даёт версионированный .tgz; перед этим — dependency update.
  • Репозиторий — статический index.yaml, ChartMuseum или (рекомендуется) OCI-реестр.
  • Из OCI ставят по oci://-пути без repo add; всегда инкрементируйте версию чарта при публикации.
Проверьте себя
1. Что нужно сделать перед helm package, если у чарта есть зависимости?
Ahelm test
Bhelm dependency update — иначе архив уедет без subchart-ов
Chelm rollback
Dничего
2. Чем OCI-публикация удобнее классического index.yaml?
AРаботает в Helm 2
BЧарты живут в том же реестре, что и образы, без отдельного index.yaml; repo add не нужен
CНе требует версий
DШифрует чарт
3. Зачем helm repo index ... --merge при добавлении новой версии?
AДля скорости
BЧтобы не потерять записи о ранее опубликованных версиях в index.yaml
CДля шифрования
DЭто обязательно для OCI