Terraform
Updated September 2026: Terraform licensing, Kubernetes provider v3 resource names and current HashiCorp links.
100Days Resources
Learning Resources
- https://youtu.be/UleogrJkZn0
- https://youtu.be/HmxkYNv1ksg
- https://youtu.be/l5k1ai_GBDE
- https://developer.hashicorp.com/terraform/tutorials/kubernetes/kubernetes-provider
- https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/getting-started
Example Notes
With Terraform, you have a DevOps first approach. It is a source-available tool, originally developed by HashiCorp. Terraform was open source (MPL 2.0) through version 1.5; since version 1.6 it is licensed under the Business Source License 1.1. OpenTofu, a fork governed by the Linux Foundation, remains open source under MPL 2.0.
It is an infrastructure provisioning tool that allows you to store your infrastructure set-up as code.
Normally, you would have:
- Provisioning the Infrastructure
- Usually has top be done within a specific order
- Deploying the application
It has a strong open community and is pluggable by design — meaning that it is used by vast number of organisations
Allows you to manage your infrastructure as code in a declarative format.
What would be the alternative?
- Pressing buttons in a UI — the problem with this is that it is not repeatable across machines
Especially important in the microservices world! It would otherwise be more time-consuming and error-prone to set-up all the resources needed for every microservice.
What is a declarative approach?
Current state vs. desired state
Define what the end-result should be.
When you are first defining your resources, this is less needed. However, once you are adding or changing resources, this is a lot more important. It does not require you to know how many resources and what resources are currently available but it will just compare what is the current state and what has to happen to create the desired state.
Different stages of using Terraform:
- Terraform file that defines our resources e.g. VM, Kubernetes cluster, VPC
- Plan Phase — Terraform command: Compares the desired state to what currently exists on our cluster if everything looks good:
- Apply Phase: Terraform is using your API token to spin up your resources
When you defined your Terraform resources, you define a provider:
Connects you to a cloud provider/infrastructure provider. A provider can also be used to spin up platforms and manage SAAS offerings
So, beyond IAAS, you can also manage other platforms and resources through Terraform.
You can configure your provider in either of the following ways:
- Use cloud-specific auth plugins (for example,
eks get-token,az get-token,gcloud config) - Use oauth2 token
- Use TLS certificate credentials
- Use a
kubeconfigfile by settingconfig_pathand, optionally,config_context(otherwise the default context is used) - Use username and password (HTTP Basic Authorization)
Let's try out Terraform
- Install Terraform
- Initialise cloud provider
- Run "terraform init"
- Set-up a security group
- Make sure that you set up the file
- Try whether or not it works with "terraform plan" . Here we would expect something to add but not necessarily something to change or to destroy.
- Don't display your credentials openly, you would probably want to use something like Ansible vault or similar to store your credentials, do not store in plain text
- Once we have finished setting up our resources, we want to destroy them "terraform destroy"
tf is the file extension that Terraform uses
Note that you can find all available information on a data source.
Common question: What is the difference between Ansible and Terraform
- They are both used for provisioning the infrastructure
- However, Terraform also has the power to provision the infrastructure
- Ansible is better for configuring the infrastructure and deploying the application
- Both could be used in combination
I am doing this example on my local kind cluster — have a look at one of the previous videos to see how to set-up kind
We are using a mixture of the following tutorials
- https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/getting-started
- https://developer.hashicorp.com/terraform/tutorials/kubernetes/kubernetes-provider
Create your cluster e.g. with kind
kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30201
hostPort: 30201
listenAddress: "0.0.0.0"
Then run
kind create cluster --name terraform-learn --config kind-config.yaml
For our terraform.tfvars file, we need the following information
hostcorresponds withclusters.cluster.server.client_certificatecorresponds withusers.user.client-certificate.client_keycorresponds withusers.user.client-key.cluster_ca_certificatecorresponds withclusters.cluster.certificate-authority-data.
To get those, run: "kubectl config view --minify --flatten --context=kind-terraform-learn"
# terraform.tfvars
host = "https://127.0.0.1:32768"
client_certificate = "LS0tLS1CRUdJTiB..."
client_key = "LS0tLS1CRUdJTiB..."
cluster_ca_certificate = "LS0tLS1CRUdJTiB..."
This is our terraform .tf file
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 3.0"
}
}
}
variable "host" {
type = string
}
variable "client_certificate" {
type = string
}
variable "client_key" {
type = string
}
variable "cluster_ca_certificate" {
type = string
}
provider "kubernetes" {
host = var.host
client_certificate = base64decode(var.client_certificate)
client_key = base64decode(var.client_key)
cluster_ca_certificate = base64decode(var.cluster_ca_certificate)
}
resource "kubernetes_namespace_v1" "test" {
metadata {
name = "nginx"
}
}
resource "kubernetes_deployment_v1" "test" {
metadata {
name = "nginx"
namespace = kubernetes_namespace_v1.test.metadata.0.name
}
spec {
replicas = 2
selector {
match_labels = {
app = "MyTestApp"
}
}
template {
metadata {
labels = {
app = "MyTestApp"
}
}
spec {
container {
image = "nginx"
name = "nginx-container"
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service_v1" "test" {
metadata {
name = "nginx"
namespace = kubernetes_namespace_v1.test.metadata.0.name
}
spec {
selector = {
app = kubernetes_deployment_v1.test.spec.0.template.0.metadata.0.labels.app
}
type = "NodePort"
port {
node_port = 30201
port = 80
target_port = 80
}
}
}
Now we can run
terraform init
terraform plan
terraform apply
Make sure that all your resources are within the right path and it should work.
An independent edition of the open-source 100 Days of Kubernetes book, published under the Apache License 2.0. Not affiliated with or endorsed by the original authors, the Linux Foundation or the Cloud Native Computing Foundation. Kubernetes® is a registered trademark of the Linux Foundation. About this edition · Advertise