Boat steering wheel picture

Find Out How To Terraform Helm Charts

Orchestrate your Helm charts with Terraform as any other cloud resources

Guillaume Vincent
Guillaume Vincent

Terraform is a well-known infrastructure as code tool in the DevOps ecosystem. You can manage plenty of cloud and service resources via the provider concept :

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"

# Configure the AWS Provider
provider "aws" {
  region = "us-east-1"

Helm is a package manager for Kubernetes applications event the more complex via charts. Basically, it templates the YAML components from a single file containing the custom values. There are Terraform providers for Helm and Kubernetes to integrate them in your codebase.

In this article, we'll set up a monitoring stack with Prometheus and Grafana. Terraform will configure the chart values to make them communicate together. When you use the Helm provider the charts are considered as resources. Reused attributes from a Helm chart in another will create a dependency and manage the deployment orchestration.


You need to install the following dependencies before starting :

Do not forget to enable the Kubernetes feature in Docker desktop

Terraform Project


Repeating values are specified in variables in :

  • The kube_config variable contains the path to the Kubernetes configuration to ensure the connection
  • The namespace variable is needed to create it and to deploy/upgrade the Helm charts.
  • The grafana_password is the credentials to connect to the web interface. The value has to be feed via the command line to not expose the secret.


The providers are defined in file. The kubernetes provider is needed to manage the namespace. The helm provider has a kubernetes block for cluster connection :



The contains a resource for the Helm chart. The default values are overridden via set blocks :

Deploy the Prometheus Helm chart :

$ terraform init
Initializing the backend...
Initializing provider plugins...
- Using previously-installed hashicorp/kubernetes v1.13.3
- Using previously-installed hashicorp/helm v1.3.2
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.
* hashicorp/helm: version = "~> 1.3.2"
* hashicorp/kubernetes: version = "~> 1.13.3"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
$ terraform apply -var grafana_password=$GRAFANA_PASSWORD
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
Terraform will perform the following actions:
# helm_release.prometheus will be created
  + resource "helm_release" "prometheus" {
      + atomic                     = false
      + chart                      = "prometheus"
      + cleanup_on_fail            = false
      + create_namespace           = false
      + dependency_update          = false
      + disable_crd_hooks          = false
      + disable_openapi_validation = false
      + disable_webhooks           = false
      + force_update               = false
      + id                         = (known after apply)
      + lint                       = false
      + max_history                = 0
      + metadata                   = (known after apply)
      + name                       = "prometheus"
      + namespace                  = "staging"
      + recreate_pods              = false
      + render_subchart_notes      = true
      + replace                    = false
      + repository                 = ""
      + reset_values               = false
      + reuse_values               = false
      + skip_crds                  = false
      + status                     = "deployed"
      + timeout                    = 300
      + verify                     = false
      + version                    = "11.16.7"
      + wait                       = true
+ set {
          + name  = "podSecurityPolicy\\.enabled"
          + value = "true"
      + set {
          + name  = "server\\.persistentVolume\\.enabled"
          + value = "false"
      + set {
          + name  = "server\\.resources"
          + value = <<~EOT
                  "cpu": "200m"
                  "memory": "50Mi"
                  "cpu": "100m"
                  "memory": "30Mi"
# kubernetes_namespace.this will be created
  + resource "kubernetes_namespace" "this" {
      + id = (known after apply)
+ metadata {
          + generation       = (known after apply)
          + name             = "staging"
          + resource_version = (known after apply)
          + self_link        = (known after apply)
          + uid              = (known after apply)
Plan: 2 to add, 0 to change, 0 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
kubernetes_namespace.this: Creating...
kubernetes_namespace.this: Creation complete after 0s [id=staging]
helm_release.prometheus: Creating...
helm_release.prometheus: Still creating... [10s elapsed]
helm_release.prometheus: Still creating... [20s elapsed]
helm_release.prometheus: Still creating... [30s elapsed]
helm_release.prometheus: Still creating... [40s elapsed]
helm_release.prometheus: Creation complete after 49s [id=prometheus]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

The resources are up and running in the staging namespace :

The Prometheus Kubernetes resources
The Prometheus Kubernetes resources

Configure port forwarding to connect to the Prometheus web interface :

$ kubectl port-forward -n staging svc/prometheus-server 8080:80
Forwarding from -> 9090
Forwarding from [::1]:8080 -> 9090

Open your browser and go to http://locahost:8080

The Prometheus web interface
The Prometheus web interface


The contains the following settings :

  • The username and password to access the web interface
  • The configuration to query Prometheus metrics
  • The dashboard to import to visualize the Kubernetes metrics

The bullets points above are done in the grafana-values.yml template file below :

This rendered grafana-values.ymlis used inside helm_release resource :

Redo an apply to make the changes withterraform apply -var grafana_password=$GRAFANA_PASSWORD

The Final Grafana Dashboard

Configure the port-forwarding for Grafana :

$ kubectl port-forward -n staging svc/grafana 3000:80                                                                                                                                                                                                                                                           
Forwarding from -> 3000
Forwarding from [::1]:3000 -> 3000

Connect to http://localhost:3000 to access the Grafana login page (the password is the value of $GRAFANA_PASSWORD ) :

The Grafana login page
The Grafana login page

The imported dashboard is visible and we can enjoy the metrics of the Kubernetes cluster :

The imported Kubernetes dashboard in Grafana
The imported Kubernetes dashboard in Grafana



Guillaume Vincent

DevOps Engineer & AWS Certified Solution Architect. Cloud enthusiast and automation addict