Skip to main content
Logo
Overview

traefik-kubernetes-terraform-and-helm-aws

August 13, 2023
3 min read

#traefik-kubernetes-terraform-and-helm-aws

If you are using Traefik in kubernetes but you want to use an AWS ALB (application load balancer) this recipe may work for you. You will note a few important things:

  1. Traefik relies on the underlying kubernetes provider to create an Ingress. If not specified this will be a loadbalancer CLB (classic load balancer). There is a way to make this a NLB (network load balancer) but the AWS provider is not doing an ALB so Traefik can’t do an ALB. This recipe therefore relies on a NodePort service and ties the Ingress (ALB) to the NodePort service via the ingressclass annotation. If you do not like or want to use NodePort this is not for you.
  2. Yet to confirm can this recipe work if you did not intentionally install the AWS LBC (load balancer controller). And does this work on non AWS EKS or self-managed kubernetes on AWS.
  3. Still looking at why the AWS Target group health check is not able to use the /ping or /dashboard. This may be an issue with my security groups but for now I just created manually a IngressRoute /<>-health on the Traefik web entrypoint and updated the Target Group health check either programatically or in the AWS console.
  4. I did not want to complicate this with kubernetes so I am using the simplest way for helm to communicate with the cluster and point to the environment kube config to get to the cluster.
  5. I did some minimal templating to change the helm release name and corresponding kubernetes objects but for this post I just hard coded for simplicity.
  6. I commented out deployment as Daemonset for my testing. You need to decide what is better in your environment Deployment or Daemonset.

providers.tf

Terminal window
provider "helm" {
kubernetes {
config_path = "~/.kube/config-eks"
}
}

versions.tf

Terminal window
terraform {
required_providers {
helm = {
source = "hashicorp/helm"
version = ">= 2.0.1"
}
}
required_version = ">= 0.15"
}

helm values

Terminal window
additionalArguments:
- --providers.kubernetescrd.ingressclass=traefik-pub
#deployment:
# kind: DaemonSet
service:
enabled: true
type: NodePort
service:
enabled: true
type: NodePort
extraObjects:
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: traefik-pub
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/security-groups: sg-<eks-sg1>,<eks-sg2>
#alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig":
# { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:<aws account id>:certificate/b6ead273-66e9-4768-ad25-0924dca35cdb
alb.ingress.kubernetes.io/healthcheck-path: "/traefik-pub-health"
alb.ingress.kubernetes.io/healthcheck-port: "traffic-port"
#alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
spec:
defaultBackend:
service:
name: traefik-pub
port:
number: 80
ingressClass:
enabled: true
isDefaultClass: false
ingressRoute:
dashboard:
enabled: true
# Additional ingressRoute annotations (e.g. for kubernetes.io/ingress.class)
annotations:
kubernetes.io/ingress.class: traefik-pub
# Additional ingressRoute labels (e.g. for filtering IngressRoute by custom labels)
labels: {}
entryPoints:
- traefik
labels: {}
matchRule: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
middlewares: []
tls: {}
rollingUpdate:
maxUnavailable: 1
maxSurge: 1

variables.tf (shortened for documentation)

Terminal window
variable "traefik_name" {
description = "helm release name"
type = string
default = "traefik-pub"
}
variable "namespace" {
description = "Namespace to install traefik chart into"
type = string
default = "test"
}
variable "traefik_chart_version" {
description = "Version of Traefik chart to install"
type = string
default = "21.2.1"
}

chart.tf

Terminal window
resource "helm_release" "traefik" {
namespace = var.namespace
create_namespace = true
name = var.traefik_name
repository = "https://traefik.github.io/charts"
chart = "traefik"
version = var.traefik_chart_version
timeout = var.timeout_seconds
values = [
file("values.yml")
]
set {
name = "deployment.replicas"
value = var.replica_count
}
}