Helm Repository Management: ChartMuseum and Harbor
Set up and manage private Helm chart repositories using ChartMuseum and Harbor, plus best practices for working with public chart repositories.
Introduction
Helm charts become useful only when you can share them across teams and environments. A chart repository is a web server that serves packaged charts and an index file, letting other engineers install your charts with a single command. Without a repository, you are manually copying chart tarballs or relying on local paths, neither of which scales.
Private chart repositories matter for most organizations that build internal platform components. Database operators, messaging middleware, monitoring agents, and shared services need a controlled distribution mechanism with access control, versioning, and audit trails. Public repositories like Bitnami work well for off-the-shelf software, but internal charts require a private solution that stays behind your VPN or works in air-gapped environments.
This guide covers setting up ChartMuseum for lightweight single-team use and Harbor for enterprise environments that already manage container images. You will learn how to push charts, manage versions, configure authentication, mirror public charts for air-gapped clusters, and monitor repository health. By the end, you will have a working private chart repository and the knowledge to operate it in production.
When to Use / When Not to Use
When to use private chart repositories
Private repos make sense when you have internal platform components that should not be public. Database operators, messaging middleware, monitoring stacks, and shared services that your teams install repeatedly benefit from a private repo with controlled access.
A private repo also helps when you need fine-grained access control. Harbor lets you set permissions per project, so one team cannot accidentally install another team’s charts.
Air-gapped environments essentially require private repos since your clusters cannot reach public chart repositories.
When to skip private repos
If you are a solo developer or small team shipping a single service, the operational overhead of maintaining ChartMuseum or Harbor is probably not worth it. A GitHub release with manually downloadable chart tarballs works fine for months.
If your organization already standardized on a different packaging system like ArgoCD ApplicationSets or raw kubectl with kustomize, adding Helm repos on top creates redundancy without clear benefit.
Repository Architecture Flow
flowchart LR
A[Developer] -->|helm package| B[CI/CD Pipeline]
B --> C{Push method}
C -->|OCI| D[Harbor<br/>Chart Registry]
C -->|HTTP API| E[ChartMuseum<br/>HTTP Server]
E --> F[index.yaml]
D --> G[Clusters pull<br/>via helm repo add]
F --> G
Chart Repository Basics
A Helm chart repository is simply a web server with an index.yaml file listing available charts and their tarballs. Users add your repo and Helm fetches the index:
helm repo add mycorp https://charts.mycorp.example.com
helm repo update
helm install mycorp/app ./mychart
The index.yaml contains chart metadata:
apiVersion: v2
entries:
myapp:
- version: 1.0.0
appVersion: "2.0"
created: "2026-01-15T10:30:00Z"
digest: sha256:a1b2c3d4e5f6...
urls:
- https://charts.mycorp.example.com/mychart-1.0.0.tgz
- version: 0.9.0
appVersion: "1.9"
created: "2025-12-01T08:00:00Z"
digest: sha256:b2c3d4e5f6a7...
urls:
- https://charts.mycorp.example.com/mychart-0.9.0.tgz
ChartMuseum Installation and Configuration
ChartMuseum is a lightweight, open-source chart repository server written in Go.
Deploy with Helm:
helm repo add stable https://charts.helm.sh/stable
helm repo update
helm install chartmuseum stable/chartmuseum \
--namespace chartmuseum \
--create-namespace \
--set persistence.enabled=true \
--set persistence.size=10Gi \
--set env.open.STORAGE=local \
--set service.type=LoadBalancer
Configuration options:
# Override values
env:
open:
STORAGE: local
STORAGE_LOCAL_ROOTDIR: /charts
DISABLE_API: "false"
AUTH_ANONYMOUS_GET: "true"
CHART_URL: https://charts.mycorp.example.com
ALLOWED_IMAGE_TYPES: images+helm-chart
persistence:
enabled: true
size: 50Gi
storageClass: standard-ssd
service:
type: ClusterIP
Upload charts via curl:
# Basic upload
curl -F "chart=@mychart-1.0.0.tgz" http://chartmuseum:8080/api/charts
# With basic auth
curl -u user:pass -F "chart=@mychart-1.0.0.tgz" \
http://chartmuseum:8080/api/charts
Automated upload in CI/CD:
#!/bin/bash
CHART_VERSION=$(helm show chart ./mychart | grep ^version: | awk '{print $2}')
helm package ./mychart
curl -u "$CHARTMUSEUM_USER:$CHARTMUSEUM_PASS" \
-F "chart=@mychart-${CHART_VERSION}.tgz" \
"$CHARTMUSEUM_URL/api/charts"
Harbor as Chart Registry
Harbor is an enterprise-grade registry that handles container images and Helm charts together. If you already use Harbor for container images, extending it for charts provides unified artifact management.
Enable chart repository in Harbor:
- Go to Administration > Registries > New endpoint
- Select Helm as the provider
- Configure the chart repository URL
Or enable via Harbor configuration in /etc/harbor/harbor.yml:
chart:
absolute_url: true
compression_rules:
- name: gzip
enabled: true
cache_duration: 24h
Push charts to Harbor:
# Login to Harbor
helm registry login harbor.mycorp.example.com
# Push chart directly as OCI artifact
helm chart push harbor.mycorp.example.com/myproject/mychart:1.0.0
# Or use http protocol
helm repo add mycorp https://harbor.mycorp.example.com/chartrepo/myproject
helm repo push ./mychart-1.0.0.tgz mycorp
Chart caching for air-gapped environments:
# Mirror a public chart to your private Harbor
helm chart pull stable/nginx
helm chart export stable/nginx mycorp/charts/
helm chart push mycorp/charts/nginx-1.0.0.tgz mycorp
Repository Caching Strategies
For organizations with multiple clusters or limited internet access, caching public charts locally improves reliability and speed.
ChartMuseum with cache:
# Pull and cache upstream charts
curl https://charts.helm.sh/stable/index.yaml -o /tmp/stable-index.yaml
curl https://charts.bitnami.com/index.yaml -o /tmp/bitnami-index.yaml
# Import into your ChartMuseum
curl -X POST http://mycache:8080/api/charts \
-F "chart=@/tmp/stable-index.yaml"
Sync automation script:
#!/bin/bash
# sync-charts.sh
UPSTREAM_REPOS="stable bitnami incubator"
CACHE_URL="http://chartmuseum:8080"
for repo in $UPSTREAM_REPOS; do
echo "Syncing $repo..."
helm repo add $repo https://charts.$repo.example.com
helm repo update $repo
# Get all chart versions
for chart in $(helm search repo $repo/ --format "{{.Name}}"); do
helm pull $chart -d /tmp/charts/
done
# Push to cache
for tgz in /tmp/charts/*.tgz; do
curl -F "chart=@$tgz" $CACHE_URL/api/charts
done
done
Chart Versioning and Deprecation
Managing chart lifecycles requires clear versioning policies and deprecation signals.
Version policies:
| Version Type | Format | Use |
|---|---|---|
| Major | 2.0.0 | Breaking changes |
| Minor | 1.5.0 | New features, backward compatible |
| Patch | 1.4.1 | Bug fixes |
Marking charts as deprecated:
# Chart.yaml
apiVersion: v2
name: old-chart
deprecated: true
version: 1.0.0
Helm treats deprecated charts specially:
# Search shows deprecated status
$ helm search repo mycorp/
NAME VERSION APP VERSION DEPRECATED
mycorp/old-chart 1.0.0 1.0 true
Automated deprecation notices:
# templates/notes.yaml
{{- if .Chart.Deprecated }}
WARNING: This chart is deprecated and will not receive updates.
Please migrate to: https://charts.mycorp.example.com/new-chart
{{- end }}
Private vs Public Chart Tradeoffs
When deciding between private and public repositories, consider these factors:
| Factor | Private Repository | Public Repository |
|---|---|---|
| Access Control | Fine-grained permissions | Limited |
| Internet Dependency | None (air-gapped friendly) | Requires internet |
| Maintenance | Your responsibility | Managed by provider |
| Discovery | Team-only | Anyone can find |
| Compliance | Full control | May have restrictions |
For most enterprise workloads, a private repository behind your VPN or in an air-gapped environment provides the best balance of security and usability. Public repositories work well for widely-adopted off-the-shelf software like nginx, Redis, or Prometheus where you want the convenience of community-maintained packages.
Production Failure Scenarios
Stale index.yaml after adding new charts
If you push a new chart version to ChartMuseum but forget to regenerate the index.yaml, users running helm repo update will not see the new version. Helm caches the index until the next update.
# After pushing a chart, regenerate index
helm repo index /path/to/charts --url https://charts.mycorp.example.com
# Then commit and push the updated index.yaml
ChartMuseum with API enabled handles this automatically when you use curl -F "chart=@..." to push.
Authentication expiring in CI
Long-running CI pipelines that pull charts hours after authenticating may fail when the Harbor or ChartMuseum token expires. Use short-lived tokens or re-authenticate before each pull.
# Re-authenticate before chart pull in long pipelines
helm registry login --username "$HARBOR_USER" --password "$HARBOR_PASS" harbor.mycorp.example.com
helm pull mycorp/mychart --version 1.0.0
Storage fills up on ChartMuseum
Without monitoring, ChartMuseum storage grows unbounded as you push new chart versions. Old versions accumulate, and if you use local storage, the disk eventually fills.
Set up storage cleanup policies or use an external object store (S3, GCS) with lifecycle policies to automatically delete old chart tarballs.
Harbor OCI vs repository mode confusion
Harbor supports charts in two modes: as OCI artifacts and as traditional chart repositories. Mixing modes or pushing OCI charts to a non-OCI project causes confusing errors.
Ensure your Harbor project has OCI artifact support enabled before pushing chart OCI artifacts.
Common Pitfalls / Anti-Patterns
No index.yaml regeneration
Pushing chart tarballs directly to the web server directory without regenerating index.yaml leaves the repository broken. Helm cannot discover charts that are not listed in the index.
Always regenerate index.yaml after adding or updating charts:
helm repo index /path/to/charts
Using latest tag in chart references
Referring to myapp:latest in your chart repository means Helm always pulls whatever was most recently pushed. This breaks reproducibility and makes rollbacks impossible since you cannot tell which version “latest” actually was.
Always pin to specific versions.
No access control on ChartMuseum
Leaving ChartMuseum with anonymous write access means anyone can upload any chart, including malicious ones. Use authentication and role-based access control.
Not mirroring critical public charts
Relying on public repositories like Bitnami without a local mirror means your air-gapped clusters cannot install those charts when the internet is unavailable. Mirror the charts you depend on.
Mixing chart sources without vetting
Not all public charts are created equal. Charts from unknown sources may have misconfigured resources, outdated dependencies, or security vulnerabilities. Vet public charts before recommending them to your team.
Observability Hooks
Track the health of your chart repository infrastructure with these monitoring practices.
Key metrics to monitor:
# ChartMuseum storage usage (bytes)
chartmuseum_storage_used_bytes
# Repository API request rate
sum(rate(chartmuseum_http_requests_total[5m])) by (method, status)
# Chart download latency
histogram_quantile(0.95, sum(rate(chartmuseum_request_duration_seconds_bucket[5m])) by (le))
# Harbor chart registry storage
harbor_chart_storage_used_bytes{project=~".*"}
# OCI artifact pull failures
sum(rate(oci_manifest_pulls_failed_total[5m])) by (repository, error_code)
Alert rules for chart repositories:
# Alert if ChartMuseum storage is above 80%
- alert: ChartMuseumStorageHigh
expr: chartmuseum_storage_used_bytes / chartmuseum_storage_limit_bytes > 0.8
labels:
severity: warning
annotations:
summary: "ChartMuseum storage above 80%"
description: "Chart repository storage is running low. Consider cleanup or expansion."
# Alert if Harbor chart registry is unavailable
- alert: HarborChartRegistryDown
expr: harbor_chart_registry_up == 0
labels:
severity: critical
annotations:
summary: "Harbor chart registry is down"
description: "Chart artifacts cannot be pulled from Harbor. Check Harbor status."
# Alert on high API error rate
- alert: ChartRepoHighErrorRate
expr: sum(rate(chartmuseum_http_requests_total{status=~"5.."}[5m])) / sum(rate(chartmuseum_http_requests_total[5m])) > 0.05
labels:
severity: warning
annotations:
summary: "Chart repository API error rate above 5%"
description: "High error rate on chart repository API. Check ChartMuseum logs."
Debugging commands:
# Check ChartMuseum health
curl http://chartmuseum:8080/health
# List all charts in ChartMuseum
curl http://chartmuseum:8080/api/charts | jq 'keys'
# Verify Harbor chart repository connectivity
helm repo add mycorp https://harbor.mycorp.example.com/chartrepo/myproject --debug
# Check OCI artifact manifest
oras manifest fetch myregistry.azurecr.io/myteam/mychart:1.0.0
# Verify chart signature
helm verify ./mychart-1.0.0.tgz
Interview Questions
Expected answer points:
- ChartMuseum is a lightweight, Go-based HTTP server specifically for Helm charts with a simple API
- Harbor is an enterprise-grade registry handling both container images and Helm charts with integrated authentication, scanning, and replication
- Choose ChartMuseum for single-team, simple chart hosting; Harbor for multi-team enterprise environments already using Harbor for container images
- Harbor supports both OCI artifact mode and traditional chart repository mode; ChartMuseum uses HTTP API only
Expected answer points:
- Set `deprecated: true` in Chart.yaml—Helm marks the chart as deprecated when users search
- Add warning notes in templates/notes.yaml that redirect users to the replacement chart
- Do not delete the old chart—existing installs need to continue working until users migrate
- Consider keeping old versions available but removing them from search results over time
Expected answer points:
- Stale index.yaml—when pushing a new chart version but forgetting to regenerate index, users do not see the new version
- ChartMuseum with API enabled handles index regeneration automatically via `curl -F "chart=@..."`
- Storage fills up on ChartMuseum without monitoring—old versions accumulate on local storage until disk fills
- Authentication expiring in CI—long-running pipelines may fail when Harbor/ChartMuseum tokens expire
Expected answer points:
- Use `helm chart pull` to download public charts, then `helm chart export` to extract the tarball
- Push the extracted chart to your private Harbor or ChartMuseum instance
- Automation script loops through upstream repos, pulls all chart versions, and pushes to cache
- Set up sync jobs to periodically check for new versions of critical public charts
Expected answer points:
- index.yaml is the metadata file listing all available charts and their versions in the repository
- Contains chart metadata: version, appVersion, created date, digest, and URLs to tarballs
- When users run `helm repo update`, Helm downloads the index.yaml to know what charts/versions are available
- Must be regenerated after adding or updating charts if not using ChartMuseum API
Expected answer points:
- Basic auth with username/password passed via environment variables
- Use short-lived tokens for CI instead of long-lived credentials—re-authenticate before each pull
- ChartMuseum supports anonymous GET when `AUTH_ANONYMOUS_GET: "true"` is set for public charts
- For Harbor, use `helm registry login` with credentials stored as secrets in your CI system
Expected answer points:
- OCI mode pushes charts as OCI artifacts using `helm chart push` (Helm 3.8+), integrated with container image storage
- Traditional mode uses HTTP API with index.yaml and chart tarballs via `helm repo add` and `helm repo push`
- OCI mode requires OCI artifact support enabled at the Harbor project level—disabled by default
- Mixing modes or pushing OCI charts to a non-OCI project causes confusing errors
Expected answer points:
- ChartMuseum storage usage (bytes and percentage of limit)
- Repository API request rate by method and status code
- Chart download latency p95
- Harbor chart registry storage by project
- OCI manifest pull failures by repository and error code
Expected answer points:
- Private repos offer fine-grained access control, no internet dependency (air-gapped friendly), full compliance control
- Private repos require your own maintenance—updates, security patches, storage management
- Public repos (Bitnami, etc.) are convenient for off-the-shelf software but require internet access and provide limited access control
- For enterprise workloads with security/compliance requirements, private repos behind VPN are usually the right choice
Expected answer points:
- Follow semantic versioning: Major (breaking changes), Minor (new features backward compatible), Patch (bug fixes)
- Major version bumps indicate incompatible API or configuration changes
- Mark deprecated charts with `deprecated: true` in Chart.yaml
- Keep old versions available for existing users while clearly communicating migration paths
Expected answer points:
- Public charts from unknown sources may contain misconfigured resources, outdated dependencies, or security vulnerabilities
- Vet public charts before recommending them to your team — review Chart.yaml, values schema, templates
- Mirror critical public charts to your private repository to avoid dependency on external availability
- Charts can contain pre-install hooks that run arbitrary code — review hooks before use
- Use Helm registry authentication and signed charts to verify chart authenticity
- Regularly update mirrored charts to patch known vulnerabilities in dependencies
Expected answer points:
- Harbor supports both OCI artifact mode and traditional chart repository mode — ensure you understand which mode you're migrating to
- Export charts from ChartMuseum: pull all chart versions with `helm pull chartmuseum/mychart`
- Push to Harbor: either via `helm chart push` (OCI mode) or `helm repo push` (HTTP mode)
- Update CI/CD pipelines to reference new Harbor repository URL
- Update developer workstation configurations: `helm repo remove chartmuseum && helm repo add harbor`
- Keep ChartMuseum running during transition period — remove after verifying Harbor is working for all users
Expected answer points:
- Chart signing uses PGP private keys to sign chart packages, providing authenticity and integrity verification
- Sign charts as part of CI/CD pipeline after packaging: `helm sign mychart-1.0.0.tgz`
- Distribute public key to users: via key server, direct exchange, or embedded in internal documentation
- Users verify: `helm verify mychart-1.0.0.tgz` or `helm install --verify mychart`
- Harbor supports chart signing natively; ChartMuseum requires external signing integration
- Signing prevents tampered charts from being installed — critical for supply chain security
Expected answer points:
- Monitor ChartMuseum storage usage — set alerts at 70% capacity to avoid running out of space
- Implement retention policy: keep N recent versions per chart, archive or delete older versions
- Use object store (S3, GCS) with lifecycle policies to auto-delete old chart tarballs after specified period
- Before deleting old versions: ensure no active deployments depend on those versions
- Announce deprecation of old versions in chart repository notices — give users time to update
- Archive rather than delete: download and store old chart versions in cold storage for compliance if needed
Expected answer points:
- Traditional chart repository uses HTTP API with index.yaml and chart tarballs — `helm repo add`, `helm repo update`
- OCI artifact distribution uses `helm chart push/pull` to push charts as OCI artifacts to container registries
- OCI mode integrates chart storage with container image storage — single registry for both
- OCI requires Helm 3.8+ and registry support for OCI artifacts — Harbor supports this, basic ChartMuseum does not
- Migrating between modes is not automatic — choose mode based on your registry capabilities and team workflow
Expected answer points:
- Harbor uses project-based access control — each team has their own project with isolated chart repositories
- Project members: can push/pull charts within project; non-members cannot access
- Robot accounts: create service accounts for CI/CD with specific project permissions — avoid sharing user credentials
- Use LDAP/AD integration to sync team memberships from corporate directory
- Public projects: anyone can pull charts without authentication — use for shared base charts
- Quotas: set storage limits per project to prevent one team from consuming all repository space
Expected answer points:
- Chart testing: `helm lint` validates syntax and template rendering; `helm template` renders without installing
- Install in test cluster: `helm install mychart ./mychart --namespace test --dry-run --debug`
- Use `helm unittest` plugin for unit tests inside charts — test template output for various input values
- CI/CD pipeline: lint, template, install to ephemeral test namespace, run smoke tests, uninstall
- Test upgrade path: install old version, upgrade to new version, verify upgrade completes without errors
- Test rollback: install version, upgrade, then rollback — verify rollback restores previous state
Expected answer points:
- Provenance files (prov files) are SHA256 checksums for chart packages, signed with PGP
- Generated with `helm package --sign` and verified with `helm verify`
- Prov files enable users to verify chart integrity and authenticity before installation
- In supply chain: sign chart in CI/CD, distribute prov file alongside chart tarball, users verify before install
- Harbor integrates with Notary for chart signing and verification
- Prov files protect against tampered charts being deployed to production clusters
Expected answer points:
- Charts can declare dependencies in Chart.yaml with version constraints
- `helm dependency update` fetches dependencies into charts/ directory before packaging
- Pin specific versions in requirements.lock for reproducible installs — commit lock file to source control
- Test that `helm install` works offline with only local chart package — dependencies must be bundled
- If using private chart dependencies, ensure repository containing dependency is added before installing
- Renovate or similar tools can automatically update chart dependencies when new versions are available
Expected answer points:
- ChartMuseum storage usage: alert when >80% of storage limit consumed
- API error rate: alert when 5xx errors exceed threshold — indicates server issues or malformed requests
- API latency: p95 latency above 500ms may indicate performance problems under load
- Harbor chart registry health: alert if Harbor is down — chart pulls will fail across all clusters
- Failed uploads: track failed `curl -F "chart=@..."` requests — indicates authentication or permission issues
- Queue depth for async chart sync jobs: if jobs accumulate, upstream sync is lagging
Further Reading
- Helm Charts - Comprehensive Helm chart development guide
- Helm Versioning and Rollback - Release management and rollback strategies
- OCI Artifacts Distribution - Related guide on OCI artifact distribution
- CI/CD Pipelines - Deployment pipeline patterns
- ChartMuseum Documentation - Official ChartMuseum documentation
- Harbor Documentation - Official Harbor registry documentation
Conclusion
Key Takeaways
- ChartMuseum works for lightweight single-team use; Harbor suits enterprise multi-team environments with image registry needs
- Always regenerate
index.yamlafter pushing charts - Mirror public charts you depend on if you operate in air-gapped environments
- Authentication tokens in CI need to be refreshed for long pipelines
- Harbor supports both OCI artifact mode and traditional chart repository mode; know which your project uses
Repository Checklist
# Add your private repo
helm repo add mycorp https://charts.mycorp.example.com
helm repo update
# Verify a chart is available
helm search repo mycorp/
# Pull a specific version
helm pull mycorp/mychart --version 1.0.0
# Check for deprecated charts
helm repo update
helm search repo mycorp/ --deployed Category
Related Posts
Developing Helm Charts: Templates, Values, and Testing
Create production-ready Helm charts with Go templates, custom value schemas, and testing using Helm unittest and ct.
Helm Versioning and Rollback: Managing Application Releases
Master Helm release management—revision history, automated rollbacks, rollback strategies, and handling failed releases gracefully.
OCI Artifacts: Distributing Container Images and Helm Charts
Package and distribute container images, Helm charts, and other artifacts using the OCI (Open Container Initiative) specification for portable artifact management.