I have never understood the value of Helm. There I said it. I may be ostracized by the K8’s community but I just do not like Helm. The templating language is overly complicated (compared to something like Jinja), and in my opinion adds more complexity than is necessary to generate a simple yml file. This is not an article about the Terraform K8s provider which is terrible.

Yes yes, I get the value of the deployment versions, but that can also be easily solved in lots of other ways without a Tiller dependency.

Why Terraform

I use Terraform for all of our AWS infrastructure. I use it to build our network layer, VPN’s, Subnets. I use it to build REDIS instances, RDS Postgres DB’s, ACM Certificates, Generate IAM roles. Everything in AWS is managed via Terraform.

One of the weirdest things I have noticed with the rise of K8s is the additional rise of hard coding values. Maybe I just haven’t seen anyone do it right yet (very possible) but in every experience I have had with Helm, Ksonnet, or insert other k8s tool here, I have yet to see people who are not hard coding values like ACM arns for external ELB’s, IAM roles for kube2iam annotations, or any other AWSy type thing that you may be using. And I can’t help but ask myself why this is? I picture most people like this when hardcoding things.

EDIT: I did speak with a friend Erik over at CloudPosse, and they have come up with a clever way of doing this as well using Terraform -> SSM -> Chamber/Env Var -> Helm. Reach out to Erik at CloudPosse for more info.

With Terraform, I can take advantage of the templating resource to dynamically inject AWS resources using things like remote state. Consider the following.

data "template_file" "service_template" {

template = "${file("${path.module}/templates/service.tpl")}" vars {

env = "${var.environment}"

image = "${var.image}"

service = "${var.service}"

region = "${var.vpc_region}"

vpc_cidr = "${data.terraform_remote_state.networking.cidr}"

iam_role = "${data.terraform_remote_state.eks.role_arn}"

log_level = "${var.log_level}" #---------------------------------------------------#

# ELB Settings

#---------------------------------------------------#

acm_arn = "${data.terraform_remote_state.acm.certificate_arn}"

external_dns_endpoint = "${local.external_dns_endpoint}" #---------------------------------------------------#

# Replica Settings

#---------------------------------------------------#

replicas = "${var.replicas}"

max_replicas = "${var.max_replicas}"

min_replicas = "${var.min_replicas}"

nginx_replicas = "${var.nginx_replicas}"

nginx_max_replicas = "${var.nginx_max_replicas}"

nginx_min_replicas = "${var.nginx_min_replicas}" #---------------------------------------------------#

# Container Resource

#---------------------------------------------------#

cpu_limit = "${var.cpu_limit}"

cpu_request = "${var.cpu_request}"

memory_limit = "${var.memory_limit}"

memory_req = "${var.memory_req}"

cpu_scale_target = "${var.cpu_scale_target}"

nginx_cpu_limit = "${var.nginx_cpu_limit}"

nginx_memory_limit = "${var.nginx_memory_limit}"

nginx_cpu_scale_target = "${var.nginx_cpu_scale_target}"

}

} resource "local_file" "template" {

content = "${data.template_file.service_template.rendered}"

filename = "${local.template_output_path}"

}

Most important out of this is the remote state statements

vpc_cidr = "${data.terraform_remote_state.networking.supernet_cidr}"

iam_role = "${data.terraform_remote_state.eks.kube2iam_role_arn}"

acm_arn = "${data.terraform_remote_state.acm.certificate_arn}"

Or you can even create inline resources and pass them directly to the template

iam_role = "${aws_iam_role.this.arn}"

Once you have the rendered Terraform template object you can use the local_file resource and give yourself a local file with which to use kubectl (or whatever other tool you use)

resource "local_file" "template" {

content = "${data.template_file.service_template.rendered}"

filename = "${local.template_output_path}"

}

Now it’s as easy as saying

kubectl apply -f filename

This can get even more clever if you use Terragrunt, you can template all of your -k8s files in terraform in groups and output them all to a single directory for an easy standup of a new environment.

Additionally, Terraform is adding lots of even better/more powerful templating syntax in the soon to be released (hopefully by 2025) Terraform 0.12.

If you insist on Helm

For whatever god forsaken reason (fine versioning and rollbacks are cool), then I propose using Terraform to render your values.yaml files for your Helm templates, this way you can still get the dynamic variable generation injected into your Helm charts. No more hard coding!

Let’s Connect!

Linkedin: https://www.linkedin.com/in/cstobie/

If you like Drone stuff: https://www.instagram.com/stobiewankenobi/

Follow us on Twitter 🐦 and Facebook 👥 and join our Facebook Group 💬.

To join our community Slack 🗣️ and read our weekly Faun topics 🗞️, click here⬇