How to Host Helm Charts with the GitLab Package Registry

Host Helm charts with the GitLab Package Registry: create a Helm chart, add the GitLab repo, then package and push charts to store them alongside your code.

Helm helps you manage Kubernetes applications. Helm Charts help you define, install, and upgrade even the most complex Kubernetes application. Helm charts are a collection of Kubernetes YAML manifests distributed as a single package. They make it faster and easier to deploy complex applications in your cluster. Using GitLab as a ledger allows your team to store charts with your code in an organization-managed repository.

Also check:

Using the Helm GitLab repository

Helm chart support in the package registry arrived in GitLab 14.1 and is available on all tiers, including Free. If you use GitLab.com, or a self-managed instance on any supported release, you already have everything you need. If you run your own server, see How to Install GitLab CE on Rocky Linux / AlmaLinux 9.

Switch over to your GitLab instance. Either create a new project or find an existing one. Using the left sidebar, navigate to Deploy > Package registry within your project (older GitLab versions label this Packages & Registries > Package Registry). If you don’t see the menu, head to Settings > General, expand the “Visibility, project features, permissions” section, and enable the Package registry toggle.

Creating a Helm chart

To create a helm chart, use the helm create command.

➜ helm create nginx
Creating nginx

Helm create a directory with the name you supplied. The directory contains the templates and chart definition. Inspect using this command:

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

4 directories, 10 files

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

helm install nginx ./nginx

Package for distribution

To distribute helm chart, it has to be hosted in a repo. You can build the helm chart into a compressed file for ease of distribution using this command:

➜ helm package nginx

Successfully packaged chart and saved it to: /tmp/helm/nginx-0.1.0.tgz

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

nginx/Chart.yaml
nginx/values.yaml
nginx/templates/NOTES.txt
nginx/templates/_helpers.tpl
nginx/templates/deployment.yaml
nginx/templates/hpa.yaml
nginx/templates/ingress.yaml
nginx/templates/service.yaml
nginx/templates/serviceaccount.yaml
nginx/templates/tests/test-connection.yaml
nginx/.helmignore

Publish a package in Gitlab Package registry

For this, you need a username and an access token. To create a personal access token, select your avatar, then Edit profile > Access tokens (called Personal access tokens in newer releases), and add a token with the api scope. The write_repository scope might look correct but won’t actually work; it only facilitates access using Git over HTTP, whereas Helm requires API integration. A deploy token with the read_package_registry and write_package_registry scopes also works and is a better fit for automation. See the GitLab Helm repository docs for details.

Once built, a chart can be uploaded to the desired channel with curl or helm cm-push:

With curl:

curl --fail-with-body --request POST \
    --form 'chart=@mychart-0.1.0.tgz' \
    --user  <username>:<access_token> \
    https://gitlab.example.com/api/v4/projects/<project_id>/packages/helm/api/<channel>/charts
  • <username>: the GitLab username or the deploy token username.
  • <access_token>: the personal access token or the deploy token.
  • <project_id>: the project ID (like 42) or the URL-encoded path of the project (like group/project).
  • <channel>: the name of the channel (like stable).

This is the output on my server

➜ curl --request POST \
    --form 'chart=@nginx-0.1.0.tgz' \
    --user api-token:glpat-xxxxxxxxxxxxx \
    https://gitlab.com/api/v4/projects/34000009/packages/helm/api/helm/charts

{"message":"201 Created"}

With the helm cm-push plugin

For this you will need the plugin installed. Use this command:

helm plugin install https://github.com/chartmuseum/helm-push

Helm 4 verifies plugin signatures by default, and helm-push is not signed, so on Helm 4 the install fails unless you skip verification explicitly:

helm plugin install https://github.com/chartmuseum/helm-push --verify=false

The plugin command is helm cm-push, not helm push. Since Helm 3.7, helm push is a built-in command that pushes charts to OCI registries, which is not what the GitLab Helm channel API expects.

Then you need to register it with your Helm client to begin with. Use this command:

helm repo add --username  <username> --password  <access_token> citizix \
    https://gitlab.example.com/api/v4/projects/<project_id>/packages/helm/<channel>
helm cm-push mychart-0.1.0.tgz citizix
  • <username>: the GitLab username or the deploy token username.
  • <access_token>: the personal access token or the deploy token.
  • <project_id>: the project ID (like 42).
  • <channel>: the name of the channel (like stable).

This is it in my machine

➜ helm repo add --username api-token --password glpat-xxxxx citizix https://gitlab.com/api/v4/projects/34000000/packages/helm/stable

"citizix" has been added to your repositories

Then push

➜ helm cm-push nginx-0.1.0.tgz citizix

Pushing nginx-0.1.0.tgz to citizix...
Done.

Confirm

➜ helm search repo citizix
NAME        CHART VERSION APP VERSION DESCRIPTION
citizix/nginx 0.1.0         1.16.0      A Helm chart for Kubernetes

Using Charts in the Repository

With the chart in your repository, you can deploy it into your Kubernetes cluster. helm install commands should work straightaway:

# load the contents of repositories
helm repo update

# install the chart (Helm 3+ requires a release name)
helm install nginx citizix/nginx

This will start a new chart deployment into your active cluster. Use the --kubeconfig and --namespace Helm flags if necessary to select an appropriate Kubernetes configuration file and specify the namespace to deploy into.

Accessing GitLab’s Repository in a CI Pipeline

As with its other package formats, GitLab’s Helm repository benefits from built-in integration with the software’s CI/CD system. Your pipelines will receive preset environment variables which simplify the chart publication process. You don’t need to set any custom CI variables to configure authentication.

Here’s an example pipeline which packages a chart and publishes it to the stable channel of your project’s repository:

stages:
  - helm-package
  - helm-publish

helm-package:
  stage: helm-package
  image:
    name: alpine/helm:latest
    entrypoint: [""]
  script:
    - helm package my-chart
  artifacts:
    paths:
      - "*.tgz"

helm-publish:
  stage: helm-publish
  image: curlimages/curl:latest
  script:
    - |
      for chart in *.tgz; do
        curl --fail-with-body --request POST \
          --user "gitlab-ci-token:${CI_JOB_TOKEN}" \
          --form "chart=@${chart}" \
          "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/api/stable/charts"
      done

CI_JOB_TOKEN, CI_API_V4_URL and CI_PROJECT_ID are predefined in every job, so the job token authenticates the upload with no extra setup. Don’t use $CI_REGISTRY and helm push here: those target the project’s container registry (OCI), not the Helm package registry.

Last updated on Nov 10, 2026 12:49 +0300
comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy