Get started with GitLab's Helm Package Registry

Philip Welz ·
Oct 18, 2021 · 8 min read · Leave a comment

In our 14.1 release, we offered the ability to add Helm charts to the GitLab Package Registry. Here's everything you need to know to leverage application deployment with these new features.

The role of container images

The de-facto standard is to package applications into OCI Images which are often just referred to as container images and more often as Docker containers. The Open Container Initiative was launched in 2015 by Docker and other companies to define industry standards around container image formats and runtimes. GitLab introduced an OCI conform Container Registry with the release of GitLab 8.8 in May 2016.

Today, a common and widely adopted approach is to deploy applications with Helm charts to Kubernetes. This will be covered in this blog together with the feature release in GitLab 14.1 of adding Helm Charts to the GitLab Package Registry.

Install software to Kubernetes

In the DevOps era, APIs became incredibly popular, helping to drive demand for Kubernetes.

The core of Kubernetes' control plane is the API server. The API server exposes an HTTP REST API that lets end users, different parts of your cluster, and external components communicate with one another.

To interact with the API server we can use the command-line tool kubectl - although it would be also possible to use software development kits (SDKs) or any client that understands REST like curl that was released 1997.

But which data format is best to use?

Modern APIs most likely use JSON. JSON is a human-readable format that provides provide access to machine-readable data. Here is an example for Kubernetes:

    "kind": "Pod",
    "apiVersion": "v1",
    "metadata": {
        "name": "nginx",
        "creationTimestamp": null,
        "labels": {
            "run": "nginx"
    "spec": {
        "containers": [
                "name": "nginx",
                "image": "nginx",
                "resources": {}
        "restartPolicy": "Always",
        "dnsPolicy": "ClusterFirst"
    "status": {}

One downside of JSON is that comments are not supported. That is one several reasons why YAML stepped in and took the spot as the de-facto language to use for declarative configurations. The Kubernetes API transforms YAML to JSON behind the scenes. As you can easily convert back and forth between both, YAML tends to be more user-friendly. Nginx example Pod in YAML:

apiVersion: v1
kind: Pod
  creationTimestamp: null
    run: nginx
  name: nginx
  # NOTE: If no tag is specified latest will be used
  - image: nginx
    name: nginx
    # TODO
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Now you are ready to save our YAML code in a file called nginx.yaml and deploy it into Kubernetes:

$ kubectl apply --filename=nginx.yaml 

Create a Helm chart

Applying YAML configuration files can get overwhelming, especially when needing to deploy into several environments or wanting to version the manifests. It is also cumbersome to maintain plain YAML files for more complex deployments which can easily extend to more than 1000 lines per file.

Instead, how about using a format that packages our applications and makes them easily reproducible with templates? How about adding our own versioning scheme to this packaged application? How about deploying the same version with a few lines of code to multiple environments? This all comes with Helm.

To create a Helm package you have to ensure that the Helm CLI is installed on your system (example with Homebrew on macOS: brew install helm).

$ helm create nginx 

Inspect the created Helm boilerplate files with ls -lR or tree on the CLI. This Helm chart can also be tested in a sandbox environment to verify it is operational.

├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

NOTE: You can read more about the starter Chart here.

Kindly Helm creates a starter chart directory along with the common files and directories used in a chart with NGINX as an example. We again can install this into our Kubernetes cluster:

$ helm install nginx .

Package Distribution

Thus far, we have learned that applications are packaged in containers and are installed using a Helm chart. Both methods require central distribution storage that is publicly accessible, or accessible in your local network environment where the Kubernetes clusters are running.

The Helm documentation provides insights on running your own Helm registry, similar to hosting your own Docker container registry.

What if we could avoid Do It Yourself DevOps and have both containers and Helm charts in one central DevOps platform? After maturing the container registry in GitLab, community contributors helped add the Helm chart registry in 14.1.

Building the container image and Helm chart is part of the CI/CD pipeline stages and jobs. The missing bit is the automated production deployment using Helm charts in your Kubernetes cluster.

An additional benefit in CI/CD is reusing the authentication mechanism, and working in the same trust environment with security jobs before actually uploading and publishing any containers and charts.

Build the Helm Chart

$ helm package nginx 

The command creates a new tar.gz archive ready to upload. Before doing so, you can inspect the archive with the tar command to verify its content.

$ tar ztf nginx-0.1.0.tgz


Push the Helm chart to the registry

With the helm-push plugin for Helm we can now upload the chart to the GitLab Helm Package Registry:

$ helm repo add --username <username> --password <personal_access_token> <REGISTRY_NAME><project_id>/packages/helm/stable
$ helm push nginx-0.1.0.tgz nginx

This step should be automated for a production-ready deployment with a GitLab CI/CD job.

  image: dtzar/helm-kubectl
    - 'helm repo add --username gitlab-ci-token --password ${CI_JOB_TOKEN} ${CI_PROJECT_NAME} ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable'
  - upload
  stage: upload
    - 'helm plugin install'
    - 'helm push ./charts/podtatoserver-0.1.0.tgz ${CI_PROJECT_NAME}'

Install the Helm chart

First, add the Helm chart registry to your local CLI configuration and test the manual installation.

$ helm repo add --username <username> --password <personal_access_token> <REGISTRY_NAME><project_id>/packages/helm/stable
$ helm install --name nginx <REGISTRY_NAME>/nginx

Once it works, you can continue with adding an automated installation job into the CI/CD pipeline.

  image: alpine/helm
    - 'helm repo add --username gitlab-ci-token --password ${CI_JOB_TOKEN} ${CI_PROJECT_NAME} ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable'
  - install
  stage: install
    - 'helm repo update'
    - 'helm install --name nginx ${CI_PROJECT_NAME}/nginx'

Complete your DevOps lifecycle

You can learn more about the newest GitLab registries for Helm and Terraform in this #EveryoneCanContribute cafe session and inspect the deployment repository.

Try the Helm chart registry and share your workflows. Are there any features missing to complete your DevOps lifecycle? Let us know on Discord.

Cover image by Joseph Barrientos on Unsplash

“Improve your CD workflows with the new Helm Chart registry in @gitLab” – Philip Welz

Click to tweet

Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license