Introduction
Applications deployed on Kubernetes typically consist of multiple Kubernetes resources, such as deployments, services, config maps, and so on. Application developers can package those resources together to make it easier to install and upgrade them holistically. Helm is a very popular package manager for Kubernetes.
When using Helm, applications are packaged in the form of Helm charts, which can be installed either from the local file system or from a remote chart repository. If you want to distribute your Helm charts through a chart repository, there are many options available, such as GCS or S3 buckets, GitHub pages, or JFrog Artifactory. A chart repository is really just an HTTP server that hosts an index.yaml
file together with a bunch of packaged charts in form of .tgz
files.
If you need your chart repository to be private, i.e. password protected, and you do not have an S3 bucket or JFrog Artifactory handy, you can convert any private GitHub repository into a private chart repository. While GitHub pages is typically recommended as a free alternative, I have not found a way to implement a private chart repository using GitHub pages.
In this post I am going to walk you through the steps needed to set up a private GitHub repository to use it as a private Helm chart repository. The post is structured as follows. First, we will introduce the Helm chart repository structure. Afterwards, we are going to explain how to use a private GitHub repository as a Helm chart repository. The next section illustrates how to push to the repository via a GitHub Actions workflow. We are following up by explaining how to install charts from the newly created repository. The post is closed by discussing advantages and disadvantages of the presented approach.
Chart Repository Structure
As mentioned already in the introduction, the main component of any chart repository is the index file. The index file is a YAML file called index.yaml
and it contains metadata about all the packages, including the information of the respective Chart.yaml
files. Each entry in the index file also points to the location of the chart package, which is a .tgz
file.
Note that it is not mandatory for the .tgz
files and the index.yaml
to be co-located, but it is often the case. The following listing shows an example repository layout.
.
|- index.yaml
|- mychart-0.1.2.tgz
|- mychart-0.2.0.tgz
|- yourchart-1.0.0.tgz
In this case, the index file would contain information about the two charts mychart
and yourchart
in the respective versions. Next, let's see how we can configure a private GitHub repository so that we can use it as a chart repository.
Private GitHub Chart Repository Setup
First, you'll have to create a private GitHub repository that will function as the chart repository. Inside, you configure a new GitHub Actions workflow by creating a file called .github/workflows/update-index.yml
with the following content:
# yourorg/helm-chart-repository/.github/workflows/update-index.yml
name: Update Index
on:
push:
branches: [ main ]
paths:
- '**.tgz'
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Git Checkout
uses: actions/checkout@v2
- name: Helm Installation
uses: azure/setup-helm@v1.1
with:
version: v3.7.0
- name: Update Index
run: |
helm repo index .
git config --global user.email "yourbot@yourorg.com"
git config --global user.name "YourOrg Bot"
git add index.yaml
git commit -m "Update chart index"
git push
This file defines a workflow that updates the helm repository index file every time a chart package (.tgz
) is updated. It then commits and pushes the changes. To publish a new chart version, simply commit a packaged version of your chart (.tgz
). You can package your chart using helm package
:
helm package $CHART_NAME --version "$CHART_VERSION"
After you pushed your changes, the GitHub Actions workflow will run and update the repository index file. The index file is going to look similar to the following one:
# yourorg/helm-chart-repository/index.yaml
apiVersion: v1
entries:
my-chart:
- apiVersion: v2
appVersion: 0.1.0
created: "2021-11-09T19:05:08.827079146Z"
description: My chart is amazing
digest: 399637d8794fd211d5e63e4bb77e40ab9f2292ab0d5394fb607e878225e70e2e
name: my-chart
type: application
urls:
- my-chart-0.1.0+fa0e2a7.tgz
version: 0.1.0+fa0e2a7
- apiVersion: v2
appVersion: 0.1.0
created: "2021-11-09T19:05:08.69877266Z"
description: My chart is amazing
digest: 24ce7b3276ed063f245213d8f8dbd18f07d9fb083747771f7ace55271bfe91ea
name: my-chart
type: application
urls:
- my-chart-0.1.0+0ac530b.tgz
version: 0.1.0+0ac530b
generated: "2021-11-09T19:05:08.690772398Z"
Now that we have the Helm chart repository configured and know how to push new charts to it manually, let's see how to automate this in another GitHub Actions workflow.
Pushing to the Private Repository from Another Workflow
Imagine we are storing the source code of a Helm chart in another GitHub repository, and you want to package and push any changes automatically to the chart repository we created. We can accomplish this by creating another GitHub Actions workflow file with the following content:
# yourorg/my-chart/.github/workflows/helm.yml
name: Helm
jobs:
publish:
runs-on: ubuntu-20.04
steps:
- name: Chart Checkout
uses: actions/checkout@v2
- name: Helm Installation
uses: azure/setup-helm@v1.1
with:
version: v3.7.0
- name: Helm Repository Checkout
uses: actions/checkout@v2
with:
repository: yourorg/helm-chart-repository
token: ${{ secrets.YOUR_BOT_GH_TOKEN }}
fetch-depth: 0
persist-credentials: true
ref: main
path: helm-chart-repository
- name: Helm Package
run: helm package my-chart --version "0.1.0+$(git rev-parse --short "$GITHUB_SHA")" -d helm-chart-repository
- name: Helm Push
env:
GITHUB_TOKEN: ${{ secrets.YOUR_BOT_GH_TOKEN }}
run: |
git config --global user.email "yourbot@yourorg.com"
git config --global user.name "YourOrg Bot"
CHART_PACKAGE_NAME="my-chart-0.1.0+$(git rev-parse --short "$GITHUB_SHA").tgz"
cd helm-chart-repository
git add "$CHART_PACKAGE_NAME"
git commit -m "$CHART_PACKAGE_NAME"
git push origin main
This workflow is going to run in the source code repository and will package up your chart, commit and push it to the chart repository. Note that you will need to grant permissions to the workflow to push changes to the chart repository. This can be achieved by providing a GitHub API token in a secondary checkout@v2
action that has the required permissions (e.g. full access to org repos).
Installing from the Private Repository
Now that we've seen how to set up our private chart repository and how to push to it, let's use it to install a chart! First, you have to add the repository to your local Helm repository list. To authenticate, you must provide a GitHub API token that can read from the chart repository. It has to be provided using HTTP Basic Auth but it does not seem to matter whether you provide it as username, password, or both.
helm repo add yourorg \
--username "${GITHUB_TOKEN}" \
--password "${GITHUB_TOKEN}" \
"https://raw.githubusercontent.com/yourorg/helm-chart-repository/main/"
Once the repository is added, you can search it or install charts from it. Note that you'll have to update the local repository index when looking for new versions.
helm repo update
helm search repo my-chart --devel
And that's it! This is how you can transform any private GitHub repository into a private Helm chart repository.
Discussion
Before we end the post, I want to note that this solution is far from ideal. It is one possible option in your tool belt and might be great if you need to setup something but have no access to other alternatives. There are some caveats, however.
First, although this solution gives you a private repository, access management is not very flexible. You need to use API keys that can be difficult to manage and might have too wide permissions. Also, a chart developer can easily use their permission to overwrite other charts / publish new versions of other charts, injecting malicious code. Secondly, it requires setup both on the repository side but also every project that wants to push to the repository. This can be quite tedious, compared to a managed solution such as Artifactory. Thirdly, you are limited by GitHub repository limits. They shouldn't hit you too soon but are still something to be aware of.
In my opinion it would be sufficient for many use cases if it was possible to install charts directly from git. You simply specify a git repository and a version (hash) to use when running helm install
and it pulls the chart from git directly. I see the benefit of the simple repository API (webserver + index.yaml
) but still, installing from git would be an amazing feature.
Cover image by Loik Marras on Unsplash
If you liked this post, you can support me on ko-fi.
Top comments (3)
Ideally I wouldnt have to compress the files to tgz
Not sure how you handled this, but helm pull repo/chart after providing correct --username and --password (token) gives me 404 not found
Are you positive that the token you use has access to the repo? If your repo requires SSO, you might have to enable SSO on the token. Can you use the token through the GitHub API directly to access the project?