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.

published: reading time: 10 min read

Private Helm chart repositories give teams controlled, auditable access to internal application packages. This guide covers ChartMuseum and Harbor as self-hosted options, plus strategies for working with public charts.

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:

  1. Go to Administration > Registries > New endpoint
  2. Select Helm as the provider
  3. 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 TypeFormatUse
Major2.0.0Breaking changes
Minor1.5.0New features, backward compatible
Patch1.4.1Bug 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:

FactorPrivate RepositoryPublic Repository
Access ControlFine-grained permissionsLimited
Internet DependencyNone (air-gapped friendly)Requires internet
MaintenanceYour responsibilityManaged by provider
DiscoveryTeam-onlyAnyone can find
ComplianceFull controlMay 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

Quick Recap

Key Takeaways

  • ChartMuseum works for lightweight single-team use; Harbor suits enterprise multi-team environments with image registry needs
  • Always regenerate index.yaml after 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

Conclusion

Managing Helm repositories effectively involves choosing the right infrastructure for your organization, whether that is ChartMuseum for lightweight simplicity or Harbor for unified artifact management across teams. Caching strategies reduce external dependencies, and clear versioning policies help users navigate chart lifecycles. For more deployment patterns, see our Helm Charts overview and CI/CD Pipelines guide.

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 #kubernetes #devops

Helm Versioning and Rollback: Managing Application Releases

Master Helm release management—revision history, automated rollbacks, rollback strategies, and handling failed releases gracefully.

#helm #kubernetes #devops

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.

#oci #containers #helm