Terraform
Deploy applications with the Helm provider
Helm is a package management tool for deploying applications to Kubernetes clusters. Helm charts help you define, install, and upgrade Kubernetes applications. Helm charts expose dozens of useful configurations and automatically set up complex resources.
The Terraform Helm provider allows you to deploy and manage your Kubernetes applications dynamically and securely. Using Terraform, you can provision clusters and deploy applications in the same apply operation. When you pass cluster authentication parameters to the Helm provider, Terraform's built-in dependency graph ensures proper ordering in resource creation.
In this tutorial, you will deploy the Nginx Helm chart to a Kubernetes cluster with Terraform. Nginx is a widely used webserver and it serves a static HTML file by default so you can verify the deployment.
Prerequisites
To run this tutorial, you will need:
- Terraform installed locally
- A running Kubernetes cluster. Follow the quick-start below, or for more in-depth instructions follow the Provision an EKS Cluster tutorial and do not destroy your cluster.
Create your EKS cluster
Create a new directory for your project.
$ mkdir terraform_project
Change into your project directory.
$ cd terraform_project
Clone the EKS cluster tutorial repo.
$ git clone https://github.com/hashicorp/learn-terraform-provision-eks-cluster
Change into the repository directory.
$ cd learn-terraform-provision-eks-cluster
In your editor, open terraform.tf
and comment out the cloud block.
terraform.tf
terraform {
/*
cloud {
workspaces {
name = "learn-terraform-eks"
}
}
*/
## ...
Run terraform init
.
$ terraform init
Initializing modules...
Downloading registry.terraform.io/terraform-aws-modules/eks/aws 19.5.1 for eks...
- eks in .terraform/modules/eks
- eks.eks_managed_node_group in .terraform/modules/eks/modules/eks-managed-node-group
- eks.eks_managed_node_group.user_data in .terraform/modules/eks/modules/_user_data
- eks.fargate_profile in .terraform/modules/eks/modules/fargate-profile
Downloading registry.terraform.io/terraform-aws-modules/kms/aws 1.1.0 for eks.kms...
- eks.kms in .terraform/modules/eks.kms
- eks.self_managed_node_group in .terraform/modules/eks/modules/self-managed-node-group
- eks.self_managed_node_group.user_data in .terraform/modules/eks/modules/_user_data
Downloading registry.terraform.io/terraform-aws-modules/vpc/aws 3.19.0 for vpc...
- vpc in .terraform/modules/vpc
Initializing the backend...
Initializing provider plugins...
##...
Terraform has been successfully initialized!
##...
Apply the EKS cluster configuration. Respond yes
at the prompt to confirm the operation.
$ terraform apply
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
## ...
Plan: 55 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ cluster_endpoint = (known after apply)
+ cluster_name = (known after apply)
+ cluster_security_group_id = (known after apply)
+ region = "us-east-2"
Do you want to perform these actions in workspace "learn-terraform-eks"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
## ...
Apply complete! Resources: 55 added, 0 changed, 0 destroyed.
Outputs:
cluster_endpoint = "https://XXXXX.gr7.us-east-2.eks.amazonaws.com"
cluster_name = "education-eks-XXXX"
cluster_security_group_id = "sg-XXXX"
region = "us-east-2"
It may take up to 10 minutes to deploy your EKS cluster.
Clone the example repository
After deploying your EKS cluster, change into your terraform_project
directory.
$ cd ..
Clone the example repository for this tutorial.
$ git clone https://github.com/hashicorp/learn-terraform-helm.git
Change into the repository directory.
$ cd learn-terraform-helm
This configuration uses data from the state file for your EKS cluster. Confirm the state file's path in your kubernetes.tf
file. If you deployed the EKS cluster in the quickstart above your state data source path is "../learn-terraform-provision-eks-cluster/terraform.tfstate"
.
learn-terraform-helm/kubernetes.tf
## ...
data "terraform_remote_state" "eks" {
backend = "local"
config = {
path = "../learn-terraform-provision-eks-cluster/terraform.tfstate"
}
}
The path
may be different on your machine, so modify the path to the state file if necessary.
Tip
We recommend using provider-specific data sources when convenient. terraform_remote_state
is more flexible, but requires access to the whole Terraform state.
Review the Helm configuration
In your editor, open learn-terraform-helm/helm_release.tf
.
learn-terraform-helm/helm_release.tf
provider "helm" {
kubernetes {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", data.aws_eks_cluster.cluster.name]
command = "aws"
}
}
}
The helm
provider block establishes your identity to your Kubernetes cluster. The host
and the cluster_ca_certificate
use your aws_eks_cluster
state data source to construct a method for logging in to your cluster. The exec
argument gets a short-lived token to authenticate to your EKS cluster.
Now, review the helm_release
resource block.
learn-terraform-helm/helm_release.tf
## ...
resource "helm_release" "nginx" {
name = "nginx"
repository = "https://charts.bitnami.com/bitnami"
chart = "nginx"
values = [
file("${path.module}/nginx-values.yaml")
]
}
The helm_release
resource deploys the nginx
Helm chart from the Bitnami chart repository to your Kubernetes cluster. The values
parameter overrides the chart's default values. The file
function merges custom values from the nginx-values.yaml
file with the chart's default values.
Next, open the nginx-values.yaml
file.
learn-terraform-helm/nginx-values.yaml
replicaCount: 1
The configuration uses the custom values in this file to override the chart's default values during deployment. You will modify these values later in this tutorial.
For more information about Helm values files, visit the Helm documentation.
Review the Helm chart
Helm charts are composed of two primary files: a Chart.yaml
file and a values file.
The Chart.yaml
file includes core information about the application you are deploying. The required values are the chart API version, the chart's name, and the chart's SemVer 2 version. For more information on chart configuration files, visit the Helm chart yaml
file documentation.
annotations:
category: Infrastructure
licenses: Apache-2.0
apiVersion: v2
appVersion: 1.23.3
## ...
name: nginx
sources:
- https://github.com/bitnami/containers/tree/main/bitnami/nginx
- https://www.nginx.org
version: 13.2.23
Deploy Nginx
Now initialize your configuration that deploys the helm chart.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Reusing previous version of hashicorp/kubernetes from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Reusing previous version of hashicorp/helm from the dependency lock file
- Using previously-installed hashicorp/aws v4.52.0
- Using previously-installed hashicorp/helm v2.8.0
- Using previously-installed hashicorp/kubernetes v2.17.0
Terraform has been successfully initialized!
##...
Run terraform apply
. Respond yes
at the prompt to confirm the operation.
$ terraform apply
data.terraform_remote_state.eks: Reading...
## ...
Terraform will perform the following actions:
## ...
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ nginx_endpoint = (known after apply)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
helm_release.nginx: Creating...
## ...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
nginx_endpoint = "http://adfc43040b9cb4ce19e0bba76947fe77-986443180.us-east-2.elb.amazonaws.com"
Verify Nginx
To verify that your Nginx deployment is working, visit the URL from the nginx_endpoint
output. It may take up to five minutes for Nginx to become available.
$ curl $(terraform output -raw nginx_endpoint)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Modify Nginx
Now open learn-terraform-helm/nginx-values.yaml
.
Add the following to the bottom of the file, and save the file.
learn-terraform-helm/nginx-values.yaml
serverBlock: |-
server {
listen 0.0.0.0:8080;
location / {
default_type text/html;
return 200 "hello!\n";
}
}
This serverBlock
custom value configures Nginx to return a custom HTTP response.
Now, redeploy nginx
with the updated values. Respond yes
at the prompt to confirm the operation.
$ terraform apply
## ...
Plan: 0 to add, 1 to change, 0 to destroy.
Changes to Outputs:
~ nginx_endpoint = "http://adfc43040b9cb4ce19e0bba76947fe77-986443180.us-east-2.elb.amazonaws.com" -> (known after apply)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
helm_release.nginx: Modifying... [id=nginx]
## ...
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Outputs:
nginx_endpoint = "http://adfc43040b9cb4ce19e0bba76947fe77-986443180.us-east-2.elb.amazonaws.com"
Finally, verify the change.
$ curl $(terraform output -raw nginx_endpoint)
hello!
Clean up your infrastructure
Destroy the infrastructure you created in this tutorial. Respond yes
at the prompt to confirm the operation.
$ terraform destroy
##...
Plan: 0 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
helm_release.nginx: Destroying... [id=nginx]
helm_release.nginx: Still destroying... [id=nginx, 10s elapsed]
helm_release.nginx: Still destroying... [id=nginx, 20s elapsed]
helm_release.nginx: Destruction complete after 28s
Destroy complete! Resources: 1 destroyed.
Change into your EKS cluster configuration directory.
$ cd ../learn-terraform-provision-eks-cluster
Destroy your EKS cluster. Respond yes
at the prompt to confirm the operation.
$ terraform destroy
##...
Plan: 0 to add, 0 to change, 55 to destroy.
Changes to Outputs:
- cluster_endpoint = "https://XXXX.gr7.us-east-2.eks.amazonaws.com" -> null
- cluster_name = "education-eks-Lh9k4i0u" -> null
- cluster_security_group_id = "sg-0b89a05da52641c12" -> null
- region = "us-east-2" -> null
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
##...
Destroy complete! Resources: 55 destroyed.
Next steps:
In this tutorial, you used Terraform to deploy Nginx to your EKS cluster with a Helm chart.
To learn more about Kubernetes and Helm, refer to the following resources:
- Deploy Consul with Helm tutorial
- Manage Kubernetes Resources via Terraform
- Review the
templatefile()
function to create templatized Helm values files