Creating an Exclusive Helm Repository using Github Pages

A Step-by-Step Guide for Setting Up Your Private or Public Chart Repository

Eduardo Fernandes de Souza
8 min readApr 25, 2023

In this article, we’ll explore how to create a Helm repository that’s exclusive to you using Github Pages. This tutorial is particularly useful if you cannot or do not want to set up something like ChartMuseum. Note that for the non-public way but private repository option you need a Github Enterprise license for a private repository, as private Github pages can only be accessed by enterprise customers.

Before we get to the main point of implementation why should you use a helm chart?

Using Helm Charts can make it easier to deploy complex applications in Kubernetes, as they provide a standardized way of packaging and managing Kubernetes resources. By using a Helm Chart, you can define all of the necessary Kubernetes resources for your application, including services, deployments, and configuration files, in a single package. This can simplify the deployment process and make it easier to manage updates and changes over time.

Let’s implement!

The first step will be to create a repository where this can be private or public.

Create a branch called gh-pages where you will receive the charts that will be published.

The next step will be to configure github pages with the following settings.

Settings -> Pages -> Branch -> gh-pages /(root)

If you have the Github Enterprise license and intend to make the repository private check the following option on the same screen

Now that we have our master branch where it receives the helms charts and gh-pages branch where the index will be published let’s write the actions that will automate this task.

Github Actions has the following structure:

The Helm tool depends on an index file that informs us of the charts positions in a specific repository and gives us access to their download links. In order to create the index, we must refresh it immediately after pushing changes to the primary branch.

  • At the beginning of the list, we come across concurrency: release-helm. This setting informs Github that the action should run only one instance at a time. The reason behind this is that we intend to publish the action to a distinct branch later on, and performing this task in parallel could lead to confusion within Git.
concurrency: release-helm
  • We will have our action triggered when we have new files inside the temp folder on the master branch. “workflow_dispatch” will allow the action to be triggered manually.
on:
workflow_dispatch:
push:
branches:
- master
paths:
- 'temp/**'
  • Checkout code: This step checks out the code from the master branch into the src directory and the code from the gh-pages branch into the dest directory.
- name: Checkout
uses: actions/checkout@v2
with:
path: 'src'
ref: 'master'
fetch-depth: 0

- name: Checkout
uses: actions/checkout@v2
with:
path: 'dest'
ref: 'gh-pages'
fetch-depth: 0
  • Install Helm: This step installs Helm, which is a package manager for Kubernetes.
- name: Install Helm
uses: azure/setup-helm@v1
  • Update and push to master branch: This step updates the new files and pushes them to the master branch. It first creates an index file for the Helm charts, merges it with the existing index file in the dest directory.
helm repo index ./temp --merge ../dest/index.yaml --url https://raw.githubusercontent.com/eduardo854/helm-repository/gh-pages/helm/

If you go through the private repository path, pay attention that the URL must be a “raw.githubusercontent.com” address, not the URL randomly generated by the page settings. This is because that endpoint supports basic authentication.

“ — merge” This is important for us to be able to preserve the “created” date of each tgz in the index.yaml that already exists inside the gh-pages branch. If it wasn’t done this way, for each new index.yaml generated we would have the date “created” replaced with the current date and time.

After that, the code will copy the new helm charts from the temp directory to the helm directory in both the dest directory and the src directory.

It removes the contents of the temp directory and commits the changes to the master branch.

shopt -s extglob

With extglob enabled, you can use the !(pattern) to match anything that does not match the given pattern.

- name: Update New Files and push to master branch
shell: bash
working-directory: src
run: |
helm repo index ./temp --merge ../dest/index.yaml --url https://raw.githubusercontent.com/eduardo854/helm-repository/gh-pages/helm/
mkdir -p ../dest/helm
echo "Copying files..."
shopt -s extglob
mkdir -p ./helm/
echo "n" | cp -pr ./temp/!(index.yaml) ../dest/helm/
echo "n" | cp -pr ./temp/!(index.yaml) ./helm/
echo "n" | cp -pr ./temp/index.yaml ../dest/
echo "y" | rm -rf ./temp/*
git config user.name "helm"
git config user.email "your-email@example.com"
git add .
git commit -m "Updated from ref: $GITHUB_SHA"
git push
  • Push new files to gh-pages branch: This step pushes the new files from the dest directory to the gh-pages branch. It adds all the new and untracked files to the git index, commits the changes with a message that includes the unique identifier of the commit, and finally pushes the changes to the gh-pages branch.
- name: Push New Files
shell: bash
working-directory: dest
run: |
git config user.name "helm"
git config user.email "your-email@example.com"
git add $(git ls-files -o --exclude-standard)
git add index.yaml
git commit -m "Updated from ref: $GITHUB_SHA"
git push

Complete github action script:

name: Release Helm Charts

concurrency: release-helm

on:
workflow_dispatch:
push:
branches:
- master
paths:
- 'temp/**'

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
path: 'src'
ref: 'master'
fetch-depth: 0

- name: Checkout
uses: actions/checkout@v2
with:
path: 'dest'
ref: 'gh-pages'
fetch-depth: 0

- name: Install Helm
uses: azure/setup-helm@v1

- name: Update New Files and push to master branch
shell: bash
working-directory: src
run: |
helm repo index ./temp --merge ../dest/index.yaml --url https://raw.githubusercontent.com/eduardo854/helm-repository/gh-pages/helm/
mkdir -p ../dest/helm
echo "Copying files..."
shopt -s extglob
mkdir -p ./helm/
echo "n" | cp -pr ./temp/!(index.yaml) ../dest/helm/
echo "n" | cp -pr ./temp/!(index.yaml) ./helm/
echo "n" | cp -pr ./temp/index.yaml ../dest/
echo "y" | rm -rf ./temp/*
git config user.name "helm"
git config user.email "your-email@example.com"
git add .
git commit -m "Updated from ref: $GITHUB_SHA"
git push

- name: Push New Files
shell: bash
working-directory: dest
run: |
git config user.name "helm"
git config user.email "your-email@example.com"
git add $(git ls-files -o --exclude-standard)
git add index.yaml
git commit -m "Updated from ref: $GITHUB_SHA"
git push

Now that we’re done with the actions let’s create a simple helm application package

helm create test-app

After that Helm creates a directory with the following layout:

test-app/
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ └── service.yaml
└── values.yaml
2 directories, 7 files

Let’s create the package for this application

helm package test-app

The test-app-0.1.0.tgz file has been created. Let’s push this file to the master repository inside the temp folder and see the actions in action 😜

Update New Files and push to master branch

remote: Permission to eduardo854/helm-repository.git denied to github-actions[bot].

fatal: unable to access ‘https://github.com/eduardo854/helm-repository/': The requested URL returned error: 403
Error: Process completed with exit code 128.

To fix this issue, you may need to grant the github-actions[bot] account permission to push to the repository. This can be done by adding the github-actions[bot] account as a collaborator to the repository with the “Write” permission level.

Settings -> General -> Workflow Permissions -> Read and write permissions -> Don’t forget to click “Save”

Alternatively, if you don’t want to grant the github-actions[bot] account permission to push directly to the repository, you can use a personal access token (PAT) with the necessary permissions instead. You can create a PAT in your GitHub account settings and then add it as a secret in your repository. You can then use the PAT in your workflow to authenticate the git push command. To do this, you would replace the git push command in the script with something like this:

git push https://USERNAME:PAT@github.com/eduardo854/helm-repository.git

Username and PAT you can replace with environment secrets.

Settings -> Secrets and variables -> New repository secret -> Add secret
git push https://${{ secrets.USERNAME }}:${{ secrets.PAT }}@github.com/eduardo854/helm-repository.git

At the end of this article we will perform the integration of the repository with Kubernetes I will teach you how to create a Personal Access Token. This part remains as knowledge in case you do not want to grant permission to the workflow in the repository but rather use a default PAT from your organization.

Re-run failed job

After the action is completed, you will be able to view the created helm index in your branch gh-pages and access with web browser.

https://eduardo854.github.io/helm-repository/index.yaml

Now finally you can use your helm charts with kubernetes for a public repository just add the repository:

helm repo add helm-repository https://raw.githubusercontent.com/eduardo854/helm-repository/gh-pages/
helm repo update

To use as a private repository:

helm repo add helm-repository https://raw.githubusercontent.com/eduardo854/helm-repository/gh-pages/ --username <Your Username> --password <Your PAT token>
helm repo update

For a quick example of how to create your PAT token with the necessary permissions follow the instructions below:

Settings -> Developer settings
Personal access tokens -> Fine-grained tokens -> Generate new token

Enter the Token name and select the “only select repository” option to maintain good security practices.

below click on repository permissions:

Check read and write on Contents and just read on Metadata

Contents -> Read and write
Metadata -> Read-only

Now you can get your PAT with the correct permissions for the helm-repository.

In the repository permissions, make sure you have the following permissions:

  • Read access to codespaces metadata and metadata
  • Read and Write access to code

You may check the official github documentation for more details and understanding of how the personal access token works.

If you want to access the example repository created for this article, access the following helm-repository.

Other ways to create a chart repository can be found in the helm documentation

Feel free to praise, criticize or ask questions about this article. I will be happy to improve, thank you!

--

--