GitLab CI can deploy Helm charts to Kubernetes by leveraging its CI/CD features to automate the process of building, packaging, and releasing your application.
Let’s see it in action. Imagine you have a simple web application, and you want to deploy it to a Kubernetes cluster using Helm. Your GitLab repository contains your application code, a Dockerfile to build your container image, and a Helm chart in a charts/ directory.
Here’s a snippet of a .gitlab-ci.yml file that accomplishes this:
stages:
- build
- deploy
variables:
IMAGE_NAME: registry.gitlab.com/$CI_PROJECT_PATH/$CI_COMMIT_REF_SLUG
HELM_CHART_PATH: charts/my-app
build_image:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
- docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
- docker push $IMAGE_NAME:latest
only:
- main
deploy_to_kubernetes:
stage: deploy
image: alpine/helm:latest
script:
- helm upgrade --install my-release $HELM_CHART_PATH \
--namespace my-namespace \
--set image.repository=$IMAGE_NAME \
--set image.tag=$CI_COMMIT_SHA \
--create-namespace
environment:
name: production
url: http://my-app.example.com
only:
- main
In this pipeline:
-
build_imagejob:- Uses the
docker:latestimage anddocker:dind(Docker-in-Docker) service to build a Docker image for your application. - Logs into the GitLab Container Registry using predefined CI/CD variables (
$CI_REGISTRY_USER,$CI_REGISTRY_PASSWORD,$CI_REGISTRY). - Tags the image with the commit SHA (
$CI_COMMIT_SHA) for immutability andlatest. - Pushes both tags to the GitLab Container Registry.
- Uses the
-
deploy_to_kubernetesjob:- Uses the
alpine/helm:latestimage, which conveniently includes the Helm client. - Executes
helm upgrade --install. This command is idempotent: ifmy-releasedoesn’t exist in themy-namespaceKubernetes namespace, it will be installed; otherwise, it will be upgraded. $HELM_CHART_PATHpoints to your Helm chart directory.--set image.repository=$IMAGE_NAMEand--set image.tag=$CI_COMMIT_SHAoverride values within your Helm chart’svalues.yamlfile, dynamically injecting the newly built container image. This is crucial for deploying the correct version of your application.--create-namespaceensures the specified namespace exists before deployment.- The
environmentblock links this deployment to a GitLab environment, providing visibility and tracking.
- Uses the
This setup ensures that every time you push to the main branch, a new container image is built and pushed, and then Helm is used to deploy that specific image version to your Kubernetes cluster.
The real power here is how GitLab CI acts as the orchestrator. It handles the authentication to your container registry, manages the build environment, and then provides the Helm client to interact with your Kubernetes cluster. You’ll need to configure your Kubernetes credentials as a CI/CD variable (e.g., KUBE_CONFIG) or use a service account with appropriate permissions, and ensure your GitLab Runner has access to the Kubernetes cluster.
The helm upgrade --install command is a bit magical because it combines installation and upgrade logic. If you’re managing multiple Helm releases or complex dependencies, you might find yourself needing to manage Helm repositories within your CI pipeline using helm repo add and helm repo update before running helm upgrade.
Understanding how Helm charts are structured, particularly the values.yaml file and how to override its values using --set or --set-string, is key to customizing deployments. You can also pass entire YAML files using --values your-custom-values.yaml.
The next logical step is to explore how to manage different environments (staging, production) with separate Helm releases and configurations, potentially using different branches or tags to trigger deployments to those environments.