In this article, we delve into the dynamic world of Traefik, a cutting-edge ingress controller, and unveil how to harness its power seamlessly within an EKS environment using Terraform. Learn how this dynamic duo can effortlessly handle ingress traffic, streamline routing
Link to Github code repo here
Prerequisites:
- AWS Account: You must have an active AWS account. If you don't have one, you can sign up for an AWS account on the AWS website. You can create it here
- IAM User or Role: Create an IAM (Identity and Access Management) user or role in your AWS account with the necessary permissions to create and manage EKS clusters. At a minimum, the user or role should have permissions to create EKS clusters, EC2 instances, VPCs, and related resources.
- AWS CLI: Install and configure the AWS Command Line Interface (CLI) on your local machine. You'll use the AWS CLI to interact with your AWS account and configure your AWS credentials. You can download it here
- Terraform Installed: Install Terraform on your local machine. You can download Terraform from the official Terraform website and follow the installation instructions for your operating system here
Terraform
We would use a sample Terraform EKS code, created in a previous article, you can find more detailed description here
Since we would use helm to install Traefik application to created cluster in terraform let's add the following to provider.tf
:
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.16.1"
}
helm = {
source = "hashicorp/helm"
version = ">= 2.8.0"
}
}
}
- This block declares the required Terraform providers and their versions. It specifies that the kubernetes provider should be at least version 2.16.1, and the helm provider should be at least version 2.8.0.
locals {
eks_endpoint = module.eks.cluster_endpoint
eks_ca_certificate = module.eks.cluster_certificate_authority_data
}
- The locals block defines local variables for the EKS cluster's endpoint (eks_endpoint) and the cluster's CA certificate (eks_ca_certificate). These variables are sourced from the outputs of an EKS module, we would need it later
provider "kubernetes" {
host = local.eks_endpoint
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", local.cluster_name]
command = "aws"
}
cluster_ca_certificate = base64decode(
local.eks_ca_certificate
)
}
- This block configures the kubernetes provider, specifying the EKS cluster's endpoint as the host. It employs the aws CLI to authenticate, obtaining the required credentials using the eks get-token command. The cluster's CA certificate is base64-decoded for secure communication.
provider "helm" {
kubernetes {
host = local.eks_endpoint
cluster_ca_certificate = base64decode(
local.eks_ca_certificate
)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["eks", "get-token", "--cluster-name", local.cluster_name]
command = "aws"
}
}
}
- The helm provider block configures Helm to interact with the EKS cluster. It specifies the EKS cluster's endpoint and CA certificate, similar to the Kubernetes provider. The aws CLI is used for authentication, obtaining the required credentials with the eks get-token command
Traefik.tf
To make things clear we would create a separate file for Traefik install - traefik.tf
:
resource "helm_release" "traefik" {
count = var.enable_traefik_helm_release ? 1 : 0
name = var.traefik_helm_release_name
namespace = var.traefik_k8s_namespace
repository = var.traefik_helm_repo
chart = var.traefik_helm_chart
version = var.traefik_helm_chart_version
timeout = var.traefik_helm_chart_timeout_seconds
create_namespace = true
}
Count
attribute is conditional, creating the Traefik Helm release only if the variable enable_traefik_helm_release is set to trueName
andNamespace
provides a customizable way to name the Traefik installation and define the Kubernetes namespacerepository
,chart
andversion
- defines the Helm chart details, including the repository URL, the chart name, and the desired version to deploy.timeout
- specifies the maximum time (in seconds) Terraform waits for the Helm chart to be deployed before timing out. It allows customization of the deployment timeout duration.create_namespace
- Indicates that Terraform should create the Kubernetes namespace specified invar.traefik_k8s_namespace
if it does not already exist. This ensures the designated namespace is available for the ArgoCD deployment.
Variables.tf
Since we using variables let's define them in variables.tf
:
variable "enable_traefik_helm_release" {
type = bool
default = true
description = "Enable/disable Traefik Helm chart deployment on EKS"
}
variable "traefik_helm_repo" {
type = string
default = "https://traefik.github.io/charts"
description = "Traefik Helm chart repository URL"
}
variable "traefik_helm_chart" {
type = string
default = "traefik"
description = "Traefik Helm chart name"
}
variable "traefik_helm_release_name" {
type = string
default = "traefik"
description = "Traefik Helm release name"
}
variable "traefik_helm_chart_version" {
type = string
default = "20.8.0"
description = "Traefik Helm chart version to deploy"
}
variable "traefik_helm_chart_timeout_seconds" {
type = number
default = 300
description = "Timeout value for Helm chart install/upgrade operations"
}
variable "traefik_k8s_namespace" {
type = string
default = "traefik"
description = "Kubernetes namespace to use for the Traefik Helm release"
}
Deployment
In order to initialize terraform and download modules run:
`terraform init`
You can also check which resources terraform is planning to create by running:
terraform plan
To provision resources run:
terraform apply
Testing
After Terraform applied you should see similar output:
Apply complete! Resources: 61 added, 0 changed, 0 destroyed.
Outputs:
connect_to_eks = "aws eks --region <YOUR_REGION> update-kubeconfig --name <CLUSTER_NAME> --profile default"
endpoint = "<CLUSTER_ENDPOINT>"
Execute the command from connect_to_eks
output in order to generate kubeconfig file:
aws eks --region <YOUR_REGION> update-kubeconfig --name <CLUSTER_NAME> --profile default
Verify conectivity to the cluster with kubectl:
kubectl get no
You should see list of nodes:
NAME STATUS ROLES AGE VERSION
ip-10-0-1-9.ec2.internal Ready <none> 33m v1.27.7-eks-e71965b
ip-10-0-3-76.ec2.internal Ready <none> 34m v1.27.7-eks-e71965b
Now we can check if Traefik is up and running:
kubectl get po --namespace traefik
NAME READY STATUS RESTARTS AGE
traefik-84cb5c7444-k9cp8 1/1 Running 0 12m
Check if your loadbalancer is ready to use, you should see similar output. Copy value of your external IP, we will use it to expose our test app:
kubectl get svc --namespace traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 172.20.14.232 ac304e54c6f0d4aaeb137ba0f9d15d26-1652635264.us-east-1.elb.amazonaws.com 80:31550/TCP,443:32735/TCP 13m
Now let's deploy test application to see if it working corectly
We would deploy basic nginx application. First copy it locally to your PC:
wget https://raw.githubusercontent.com/cloudtipss/Traefik-Eks/main/testapp/test.yaml
File contains Deployment, Service and Ingress. Replace host
value in a Service Block with external IP from a previous step
Now you can apply it, run the following command from a folder you copied test.yaml:
kubectl apply -f ./test.yaml
deployment.apps/nginx created
service/nginx created
ingress.networking.k8s.io/nginx created
Now let's verify our app is running and listening on a host we provided:
curl -k https://ac304e54c6f0d4aaeb137ba0f9d15d26-1652635264.us-east-1.elb.amazonaws.com/
<!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>
As you can see Nginx application is up and running!
You can find source code in our Github repo