In this post we will use terraform to deploy a helm release to kubernetes.
Kubernetes
For this demonstration I will be using kind to deploy a local Kubernetes cluster to the operating system that I am running this on, which will be Ubuntu Linux. For a more in-depth tutorial on Kind, you can see my post on Kind for Local Kubernetes Clusters.
Installing the Pre-Requirements
We will be installing terraform, docker, kind and kubectl on Linux.
Install terraform:
1 2 3 4 |
|
Verify that terraform has been installed:
1
|
|
Which in my case returns:
1 2 |
|
Install Docker on Linux (be careful to curl pipe bash - trust the scripts that you are running):
1
|
|
Then running docker ps
should return:
1
|
|
Install kind on Linux:
1 2 3 4 |
|
Then to verify that kind was installed with kind --version
should return:
1
|
|
Create a kubernetes cluster using kind:
1
|
|
Now install kubectl:
1 2 |
|
Then to verify that kubectl was installed:
1
|
|
Which in my case returns:
1 2 |
|
Now we can test if kubectl can communicate with the kubernetes api server:
1
|
|
In my case it returns:
1 2 |
|
Terraform
Now that our pre-requirements are sorted we can configure terraform to communicate with kubernetes. For that to happen, we need to consult the terraform kubernetes provider’s documentation.
As per their documentation they provide us with this snippet:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
And from their main page, it gives us a couple of options to configure the provider and the easiest is probably to read the ~/.kube/config
configuration file.
But in cases where you have multiple configurations in your kube config file, this might not be ideal, and I like to be precise, so I will extract the client certificate, client key and cluster ca certificate and endpoint from our ~/.kube/config
file.
If we run cat ~/.kube/config
we will see something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
First we will create a directory for our certificates:
1
|
|
I have truncated my kube config for readability, but for our first file certs/client-cert.pem
we will copy the value of client-certificate-data:
, which will look something like this:
1 2 |
|
Then we will copy the contents of client-key-data:
into certs/client-key.pem
and then lastly the content of certificate-authority-data:
into certs/cluster-ca-cert.pem
.
So then we should have the following files inside our certs/
directory:
1 2 3 4 5 6 7 |
|
Now make them read only:
1
|
|
Now that we have that we can start writing our terraform configuration. In providers.tf
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Your host might look different to mine, but you can find your host endpoint in ~/.kube/config
.
For a simple test we can list all our namespaces to ensure that our configuration is working. In a file called namespaces.tf
, we can populate the following:
1 2 3 4 5 |
|
Now we need to initialize terraform so that it can download the providers:
1
|
|
Then we can run a plan which will reveal our namespaces:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
We can now remove our namespaces.tf
as our test worked:
1
|
|
Helm Releases with Terraform
We will need two things, we need to consult the terraform helm release provider documentation and we also need to consult the helm chart documentation which we are interested in.
In my previous post I wrote about Everything you need to know about Helm and I used the Bitnami Nginx Helm Chart, so we will use that one again.
As we are working with helm releases, we need to configure the helm provider, I will just extend my configuration from my previous provider config in providers.tf
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
We will create three terraform files:
1
|
|
And our values yaml in helm-chart/nginx/values.yaml
:
1
|
|
Then you can copy the values file from https://artifacthub.io/packages/helm/bitnami/nginx?modal=values into helm-chart/nginx/values.yaml
.
In our main.tf
I will use two ways to override values in our values.yaml
using set
and templatefile
. The reason for the templatefile, is when we want to fetch a value and want to replace the content with our values file, it could be used when we retrieve a value from a data source as an example. In my example im just using a variable.
We will have the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
As you can see we are referencing a NAME_OVERRIDE
in our values.yaml
, I have cleaned up the values file to the following:
1 2 3 4 5 6 7 |
|
The NAME_OVERRIDE
must be in a ${}
format.
In our variables.tf
we will have the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
And lastly our outputs.tf
:
1 2 3 |
|
Now that we have all our configuration ready, we can initialize terraform:
1
|
|
Then we can run a plan to see what terraform wants to deploy:
1
|
|
The plan output shows the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
Once we are happy with our plan, we can run a apply:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Then we can verify if the pod is running:
1 2 3 |
|
Importing Helm Releases into Terraform State
If you have an existing helm release that was deployed with helm and you want to transfer the ownership to terraform, you first need to write the terraform code, then import the resources into terraform state using:
1
|
|
Where the last argument is <namespace>/<release-name>
. Once that is imported you can run terraform plan and apply.
If you want to discover all helm releases managed by helm you can use:
1
|
|
Thank You
Thanks for reading, feel free to check out my website, feel free to subscribe to my newsletter or follow me at @ruanbekker on Twitter.
- Linktree: https://go.ruan.dev/links
- Patreon: https://go.ruan.dev/patreon