24.9 Publishing Charts to a Repository
Right, so you’ve got a chart. It’s a beautiful, finely-tuned machine of YAML, templating magic, and pure willpower. But right now, it’s just sitting on your laptop, which is about as useful as a race car in a living room. We need to get it on the track. We need to publish it to a repository so other people (or, let’s be honest, your CI/CD system) can actually use it.
Think of a chart repository not as some complex Git monolith, but as a very simple, specialized web server. Its only job is to serve two files: the packaged *.tgz chart archives and an index.yaml file that acts as the catalog for all the charts it has. Helm’s client-side magic does the rest. You can host this repository anywhere you can serve static files: a simple Amazon S3 bucket, a Google Cloud Storage bucket, an Azure Blob Storage container, a GitHub Pages site, or even a local directory served by python -m http.server in a pinch. The key is that Helm needs to be able to get to it over HTTP(S).
Packaging: Making the .tgz File
Before you can upload anything, you need to package your chart directory. This is Helm’s way of taking your sprawling directory of templates, values, and charts and squishing it into a single, versioned tarball. Navigate to the directory above your chart and run:
helm package my-awesome-chart/
This will create a file like my-awesome-chart-1.2.3.tgz. The version is pulled directly from the Chart.yaml file. This is the first and most common pitfall: if you don’t increment the version in Chart.yaml, you’ll just overwrite your old package file locally, and trying to upload the same version to a repo will cause chaos. Helm strictly uses the version number as the unique identifier. Remember, Helm is a package manager; it expects semantic versions. 1.2.3 is great. 0.1.0-my-branch-beta is a valid pre-release version and totally acceptable for testing. version-bob-built-on-tuesday is not and will cause Helm to look at you with profound disappointment.
The Mighty index.yaml File
Here’s the part everyone gets wrong at least once. You don’t just toss the *.tgz files into a bucket and call it a day. The repository needs an index. This index.yaml file is the map that tells Helm what charts are available, what their versions are, and where to download them from.
You do not write this file by hand. That way lies madness and YAML indentation errors. You use the helm repo index command to generate or update it. Let’s say you’ve uploaded your packaged my-awesome-chart-1.2.3.tgz file to the root of your web server. You would then generate the index like this:
# First, if you have a local directory with your .tgz files:
helm repo index ./my-repo-dir/ --url https://my-bucket.fra1.cdn.digitaloceanspaces.com
# This generates (or updates) ./my-repo-dir/index.yaml
The --url flag is critical. It tells Helm the absolute base URL where the charts are hosted. The generated index.yaml will contain entries that point to https://my-bucket.../my-awesome-chart-1.2.3.tgz. If you forget this flag, the index will point to local file paths (file://...), which are utterly useless to anyone else trying to use your repo. Always, always specify the --url.
The Upload and Index Dance
Your workflow for a new chart version should be a strict ritual:
- Package:
helm package my-awesome-chart/(createsmy-awesome-chart-1.2.3.tgz) - Upload: Use your cloud provider’s CLI (e.g.,
aws s3 cp,gsutil cp) to upload the new.tgzfile to your repository bucket/directory. - Download the existing index: If you’re not working on the server itself, download the current
index.yamlfile from your repository to a local directory. This is a crucial best practice everyone learns the hard way. You must merge the new chart into the existing index, not create a new one that only knows about your new chart and forgets every other chart you’ve ever published. - Rebuild the index: Run
helm repo index ./my-local-dir/ --url https://my-repo-url.com --merge ./my-local-dir/index.yaml. The--mergeflag is your best friend here; it takes the existing index you just downloaded, adds the new info for the charts in the local directory, and outputs the complete updated index. - Upload the new index: Upload the updated
index.yamlback to your repository, overwriting the old one.
# A realistic workflow for S3:
helm package my-awesome-chart/
aws s3 cp my-awesome-chart-1.2.3.tgz s3://my-helm-charts/
aws s3 cp s3://my-helm-charts/index.yaml .
helm repo index . --url https://my-helm-charts.s3.amazonaws.com --merge index.yaml
aws s3 cp index.yaml s3://my-helm-charts/index.yaml
Adding Your Repo to Helm
Finally, to let Helm know about your masterpiece of a repository, you add it just like you would any other repo. The name you choose (my-repo in this case) is an alias you’ll use forever.
helm repo add my-repo https://my-bucket.fra1.cdn.digitaloceanspaces.com
helm repo update # This fetches the latest index.yaml from all your added repos
helm search repo my-repo # Should now show 'my-awesome-chart'
And there you have it. You’ve turned a static file storage location into a bona fide Helm chart repository. It’s a few more steps than a git push, but once you automate it in a CI pipeline (which you absolutely should), it becomes bulletproof. Now go on, share that brilliant chart. The world is waiting. Or at least, the other pod in your namespace is.