Traefik is an excellent declarative ingress controller for Kubernetes. If you don't need all the features of cloud-managed Application Load Balancers, Traefik can be a fantastic alternative.
However, there are certain limitations of Traefik on cloud platforms. It can handle the TLS/SSL layer only through Kubernetes Secret or Let's Encrypt, meaning it cannot leverage AWS ACM for resolving SSL certificates. This limitation stems from AWS ACM itself, as it can only be used with resources like ALB and CloudFront.
However, you may want to have both 1) SSL termination by ACM and 2) support for Traefik-specific features (Middleware, Circuit Breaker, etc.) all in one place. Fortunately, I have tested a system that allows you to continue using an AWS ACM-provided SSL certificate while handling ingress routing with Traefik. Here is the high-level architecture of the proposed system:
To set up this system, you'll first need an EKS cluster with the AWS Load Balancer Controller add-on. You can bootstrap the cluster using eksctl.
Once the cluster is ready, deploy Traefik in web
mode only, disabling the websecure
entrypoint.
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
spec:
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik
containers:
- image: docker.io/traefik:v3.0
name: traefik
ports:
- name: "web"
containerPort: 80
args:
- "--entrypoints.web.address=:80/tcp"
- "--api.dashboard=false"
- "--providers.kubernetescrd"
Next, create a service for the Traefik deployment/daemonset and set its type to NodePort (ALB requires the service to be of NodePort type for its backend).
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
ports:
- name: web
nodePort: 30080
port: 80
protocol: TCP
targetPort: web
selector:
app: traefik
type: NodePort
Next, create an ALB Ingress with the appropriate annotations for ACM UUID, Name, and Class.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-southeast-1:0000000000:certificate/cb6cf41e-a6f4-4fd3-9aa5-44503f317420
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/load-balancer-name: my-lb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/success-codes: 200-404
alb.ingress.kubernetes.io/target-type: instance
name: traefik
spec:
ingressClassName: alb
rules:
- http:
paths:
- backend:
service:
name: traefik
port:
name: web
path: /*
pathType: ImplementationSpecific
Once applied, an ALB will be created. You can then route any HTTPS traffic through the ALB, and ultimately, it will be routed using Traefik within your Kubernetes Cluster. A sample IngressRoute
object would look like this:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-apps
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host(`a.example.com`)
services:
- name: app-a
port: 80
- kind: Rule
match: Host(`b.example.com`)
services:
- name: app-b
port: 80