Simon Emms

Software Engineer, Technical Leader, Solutions Designer

Using GitLab Pages to Host a Helm Registry

Published:

To see this in action, check out gitlab.com/MrSimonEmms/helm-repo

Helm is a great way of sharing Kubernetes resources and making them reusable. The documentation provides a way of creating a registry using a Docker image that you can host yourself. This provides lots of functionality, such as authentication and commands to interact with it. If you have your own infrastructure and need authentication, this is a great way to start. However, if you're publishing an open-source project, or you don't need authentication then managing infrastructure is an expense and overhead you don't need.

Enter GitLab Pages.

What is GitLab Pages

GitLab Pages is a way of publishing static files to the internet. It also allows you to use any URL you want and can be configured to use Let's Encrypt TLS certificates.

As a Helm Registry is simply an index.yaml file and a collection of .tar.gz files, this makes GitLab Pages a great option for hosting your registry.

Setting Up Your Repo

To set the repository up, you actually only need three files configured.

The packages directory is used in case you want to set up a website to read the index.yaml. This is outside the scope of this post, but can be copied from my Helm Registry source code

/packages/index.html

This file is required for GitLab Pages to trigger building of the website. Even though it's not required for the Helm Registry, without it, this won't be published as a website.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Helm Registry</title>
</head>
<body>
  My Helm Registry
</body>
</html>

/packages/index.yaml

This is the contents of the Helm Registry. Eventually, this will contain a list of all the packages published to your registry.

apiVersion: v1
entries: {}

/.gitlab-ci.yml

This file controls how the GitLab CI/CD builds the package. There are two tasks here:

  • the add_helm_chart task is run when a trigger is received. It downloads the Helm chart, adds it to the index.yaml file and commits it to the repository
  • the pages task is run when a commit is pushed to the master branch. It publishes the packages directory as your website.
stages:
  - init
  - publish

image: node

variables:
  GIT_REPO_DIR: ./git-repo
  HELM_REPO_DIR: ./packages

add_helm_chart:
  rules:
    - if: '$CI_PIPELINE_TRIGGERED == "true" && $PROJECT_CHART_REPO != null && $PROJECT_OWNER != null && $TAG_NAME != null && $CHART_DIR != null && $CHART_NAME != null'
  image: registry.gitlab.com/mrsimonemms/gitlab-ci-tasks/kubectl-helm
  stage: init
  before_script:
    - git remote set-url origin https://${GITLAB_USER_LOGIN}:${GITLAB_TOKEN}@gitlab.com/${CI_PROJECT_PATH}.git
    - git config --global user.email "${GITLAB_USER_EMAIL}"
    - git config --global user.name "${GITLAB_USER_NAME}"
    - git checkout -B ${CI_COMMIT_REF_NAME}
    - git pull origin ${CI_COMMIT_REF_NAME}
    - cd ${HELM_REPO_DIR}
  script:
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/${PROJECT_OWNER}/${PROJECT_CHART_REPO}.git ${GIT_REPO_DIR}
    - cd ${GIT_REPO_DIR}
    - git checkout ${TAG_NAME}
    - cd -
    - helm package ${GIT_REPO_DIR}/${CHART_DIR}/${CHART_NAME} -d .
    - helm repo index --url ${HELM_REPO_URL} --merge index.yaml .
    - rm -Rf ${GIT_REPO_DIR}
    - git status
    - git add .
    - "git commit -m \"chore: add ${PROJECT_OWNER}/${PROJECT_CHART_REPO} ${TAG_NAME} to Helm repo\""
    - git status
    - git push origin ${CI_COMMIT_REF_NAME}

pages:
  stage: publish
  script: mv ${HELM_REPO_DIR} public
  artifacts:
    paths:
      - public
  only:
    - master
  except:
    - triggers

Configuration

For this to work, various bits of configuration must be done:

Configure Custom URL (optional)

If you want to host this on a custom URL, you can add this in the Settings -> Pages section. Follow the instructions on screen to add the DNS records.

If you don't do this, you can use the default gitlab.io URL.

Create a Personal Access Token

Create a Personal Access Token with the api scope selected (from the documentation, you should also be able to use the write_repository scope although I've not tested it with that).

Add CI/CD Variables

In the Settings -> CI/CD section for your repository, create some variables:

  • GITLAB_TOKEN - this is the value of the Personal Access Token above. This value should be both protected and masked
  • HELM_REPO_URL - this is the URL to host the repository on. This must be the fully qualified domain, including https:// at the start. As an example, my value is https://helm.simonemms.com. This doesn't need to be protected or masked but won't hurt if they are.

Create a Pipeline Trigger

In the Settings -> CI/CD section for your repository, create a Pipeline Trigger. A good description would be "Add Helm chart to registry", although the exact working is up to you.

Keep a note of both the project ID in the example (in the format https://gitlab.com/api/v4/projects/xxxx/trigger/pipeline) and the token.


Adding a Chart to your Registry

As this uses git clone to get the project, this can get any public repository or any private repo that's owned by the same user/group as the Helm Registry.

Now you've set the Helm Registry repository up, you can begin to integrate this with other repositories that contain the Helm charts you wish to publish. Ultimately, this is a simple cURL call.

This worked example will use values from gitlab.com/MrSimonEmms/openfaas-amqp1.0-connector. You will need to replace these with your own values.

export CHART_DIR=chart # Location of the Helm chart directory in the repository
export CHART_NAME=openfaas-amqp1.0-connector # Location of the chart with the Helm chart directory
export CI_PROJECT_NAMESPACE=MrSimonEmms # In GitLab CI/CD, this is pre-filled
export CI_PROJECT_NAME=openfaas-amqp1.0-connector # In GitLab CI/CD, this is pre-filled
export HELM_REPO_TRIGGER_TOKEN=xxxxxxxx # The trigger token for the Helm Registry project (generated above)
export HELM_REPO_PROJECT_ID=123456 # The project ID of the Helm Registry project (see the trigger configuration above)
export VERSION=v1.0.0 # The branch or tag to publish

curl -f -X POST \
  -F token=${HELM_REPO_TRIGGER_TOKEN} \
  -F ref=master \
  -F variables[PROJECT_OWNER]=${CI_PROJECT_NAMESPACE} \
  -F variables[PROJECT_CHART_REPO]=${CI_PROJECT_NAME} \
  -F variables[TAG_NAME]=${VERSION} \
  -F variables[CHART_DIR]=${CHART_DIR} \
  -F variables[CHART_NAME]=${CHART_NAME} \
  https://gitlab.com/api/v4/projects/${HELM_REPO_PROJECT_ID}/trigger/pipeline

This will trigger the add_helm_chart job inside the GitLab CI/CD config. After a few minutes, you will see a new commit to the master branch and then you will find the chart added to the index.yaml file.

That's pretty much all there is to hosting your own Helm Registry in GitLab Pages. Also, this doesn't matter if a specific version is added via the trigger multiple times - Helm will manage that for you.


Credits

Photo by Bruce Warrington

Do you like this article?