Helm charts are a package manager for Kubernetes, allowing you to define, install, and upgrade even the most complex Kubernetes applications. GitHub Actions is a CI/CD platform that lets you automate your software development workflows. Combining them lets you automate the deployment of your Kubernetes applications.
Here’s a simple example of a GitHub Actions workflow that deploys a Helm chart to a Kubernetes cluster.
First, you need a Helm chart. Let’s assume you have a chart in a repository, for example, my-app/charts/my-chart.
name: Deploy My App
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: 'v3.10.0' # Specify your desired Helm version
- name: Configure Kubernetes credentials
uses: azure/k8s-set-context@v3
with:
method: 'kubeconfig'
kubeconfig: ${{ secrets.KUBECONFIG }} # Your kubeconfig file content as a secret
- name: Deploy Helm chart
run: helm upgrade --install my-release ./my-app/charts/my-chart --namespace my-namespace --create-namespace
Let’s break down what’s happening here:
on: push: branches: - main: This tells the workflow to run whenever code is pushed to themainbranch.jobs: deploy:: Defines a job nameddeploy.runs-on: ubuntu-latest: Specifies that the job will run on a fresh Ubuntu runner.steps:: A sequence of tasks to be executed.Checkout code: This action checks out your repository’s code so the workflow can access your Helm chart.Set up Helm: This action downloads and sets up the specified version of Helm on the runner.Configure Kubernetes credentials: This action configureskubectlto connect to your Kubernetes cluster. It uses akubeconfigfile, which you should store as a GitHub secret namedKUBECONFIG. Themethod: 'kubeconfig'indicates that you’re providing the full kubeconfig content.Deploy Helm chart: This is the core step.helm upgrade --install: This command upgrades an existing release or installs it if it doesn’t exist.my-release: This is the name you give to your Helm release../my-app/charts/my-chart: This is the path to your Helm chart within your checked-out repository.--namespace my-namespace: Specifies the Kubernetes namespace to deploy into.--create-namespace: If the namespace doesn’t exist, this flag will create it.
To use this workflow, you need to:
- Create a file named
deploy.yaml(or any other.yamlname) in your repository’s.github/workflows/directory. - Store your Kubernetes
kubeconfigcontent as a GitHub secret namedKUBECONFIG. You can get yourkubeconfigfile from your cluster provider or by runningkubectl config view --raw. - Ensure your Helm chart is located at
./my-app/charts/my-chartin your repository, or adjust the path in theruncommand accordingly.
The most surprising truth about Helm deployments from CI/CD is that helm upgrade --install is not idempotent in the way many expect for simple configuration changes. While it won’t fail if the chart is already installed, it relies on Helm’s internal state tracking for successful upgrades, which can sometimes lead to subtle drift if manual changes are made directly to the Kubernetes resources managed by Helm.
When you run helm upgrade --install my-release ./my-app/charts/my-chart, Helm compares the desired state defined by your chart with the current state of the my-release in the my-namespace. If there are differences, it generates a Kubernetes manifest that represents the changes and applies them to your cluster. It also stores a record of the deployed release’s manifest and configuration in a ConfigMap within the Kubernetes cluster itself, which is how Helm tracks what’s installed and what version it is. This allows subsequent helm upgrade commands to know what to compare against.
The helm upgrade --install command is a powerful tool for managing application lifecycles in Kubernetes. It allows you to declaratively define your application’s desired state using Helm charts and then automate the process of applying those changes to your cluster. This not only simplifies deployments but also ensures consistency and reproducibility across different environments.
One thing most people don’t know is how Helm handles secrets and sensitive configuration. By default, Helm charts might store sensitive information in plain text within the chart’s values.yaml file or directly in the generated Kubernetes manifests. For production environments, it’s crucial to integrate with external secret management systems like HashiCorp Vault or Kubernetes Secrets, often by using tools like helm-secrets or by fetching secrets dynamically during the Helm deployment process.
The next concept you’ll likely encounter is managing Helm chart dependencies and handling complex deployment strategies like blue-green or canary deployments.