Building a Helmfile CI/CD Pipeline
In my previous post, I described a Helmfile deployment for observability around website monitoring. Now, as your monitoring needs grow, that Helmfile deployment will undergo more and more changes. To properly handle this at a larger scale, CI/CD is a must. In this post, we'll take a quick run through of a basic CI/CD pipeline for a Helmfile deployment.
Now, as we'll recall, our Helmfile configuration is as follows:
1repositories:
2- name: grafana
3 url: https://grafana.github.io/helm-charts
4- name: prometheus-community
5 url: https://prometheus-community.github.io/helm-charts
6
7releases:
8 - name: grafana
9 namespace: observability
10 chart: grafana/grafana
11 values:
12 - ./grafana/values.yaml
13
14 - name: prometheus-operator
15 namespace: observability
16 chart: prometheus-community/kube-prometheus-stack
17 values:
18 - ./prometheus-operator/values.yaml
19
20 - name: prometheus-blackbox-exporter
21 namespace: observability
22 chart: prometheus-community/prometheus-blackbox-exporter
23 values:
24 - ./prometheus-blackbox-exporter/values.yaml
25 needs:
26 - observability/prometheus-operator
As our needs grow, we may be adding more endpoints to our blackbox exporter deployment, adding custom jobs to our Prometheus Operator, or maybe even deploying new data sources to Grafana. All of these changes can be done through our Helmfile configuration. But once these changes start happening more, we want to start adding some process around changes. To do this, we'll be building a simple GitLab CI pipeline that does the following:
- On a feature branch (i.e. not the main branch), we'll run a
helmfile diff
on our configuration - On the main branch, we'll run a
helmfile apply
- In between these two steps, we'll have a merge request process where both the code changes and the
helmfile diff
can be reviewed
Since this is a relatively short pipeline, let's get it all down now and go through each piece.
1---
2stages:
3 - diff
4 - apply
5
6default:
7 image: chatwork/helmfile
8 tags:
9 - home-lab
10
11diff:
12 stage: diff
13 script:
14 - |
15 cd helm-charts
16 helmfile diff
17 except:
18 - main
19
20apply:
21 stage: apply
22 script:
23 - |
24 cd helm-charts
25 helmfile apply
26 only:
27 - main
So, as stated before, we have 2 stages, "diff" and "apply". In our default block, we define a few sensible defaults. In our case, the image for both of our stages (i.e. an image that has helmfile on it) and we also specify our runner tag.
From there, the stages are actually pretty simple. In both stages, we'll change our directory to the directory with the helmfile.yaml
, and in one we run diff, the other we run apply. The important parts in these two stages to make our merge request process possible, are the except
and only
blocks. On the diff block, we use except
to only run on branches that aren't named "main". Similarly, for apply, we'll use only
to restrict that stage to the main branch.
There's not much more to it than that honestly. One nice thing I'll note in this gitlab-ci.yml file, is our multi-line shorthand - |
. This is an alternative to doing something like this:
1script:
2- foo
3- bar
4- foobar
Both achieve the same thing, but personally, I like the method I've gone with much more :-)
And with that, I'll tie a bow on this post. Thanks for reading, and stay tuned for more!