Exposing public applications on AWS EKS with Traefik

Artur Bartosik
5 min readJan 12, 2024

In this short guide, I’ll walk you through the process of exposing applications on AWS EKS using Traefik. Despite Traefik often being perceived as having complex configurations and unclear documentation, I aim to equip you with a straightforward setup that you can easily apply to your solution. Let’s streamline the process and make exposing applications on the cloud a hassle-free experience.

Exposing public applications on AWS EKS with Traefik

Prerequisites

As always I encourage you to install kubectx + kubens and configure shorter aliases to navigate Kubernetes easily.

Install & Configure Traefik

All resources you can find in my GitHub repo

First, check if the Ingress Class has been added with installation of AWS Load Balancer Controller from my EKS setup repo.

kubectl get ingressclas

-------------------------
NAME CONTROLLER
alb ingress.k8s.aws/alb

We use this Ingress Controller to provision the main NLB pointing to our Traefik proxy.

Before we install the official Traefik helm chart let's take a few minutes to look at the helm values file helm/traefik.yaml.

#1
ports:
web:
expose: false
websecure:
port: 8443
expose: true
exposedPort: 443
protocol: TCP
tls:
enabled: false
traefik:
port: 9000
expose: true
exposedPort: 9000
protocol: TCP
tls:
enabled: false
postgres:
port: 5432
expose: true
exposedPort: 5432
protocol: TCP
rabbitmq:
port: 5672
expose: true
exposedPort: 5672
protocol: TCP

#2
ingressRoute:
dashboard:
enabled: false

service:
#3
annotations:
external-dns.alpha.kubernetes.io/hostname: traefik.<YOUR_DOMAIN>, rabbitmq.<YOUR_DOMAIN>, postgres.<YOUR_DOMAIN> #4
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443, 9000"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: <YOUR_CERTIFICATE_ARN> #5
service.beta.kubernetes.io/load-balancer-source-ranges: 0.0.0.0/0
globalArguments:
- "--api.insecure=false"

#6
logs:
general:
level: INFO
access:
enabled: false

At the top we define the Trafik port (#1). There are the network entry points into Traefik. We see dedicated ports defined for PostgreSQL and AMQP for RabbitMQ. The web port responsible for HTTP has been disabled and we have only left the HTTPS websecure open. Next, we disable default Ingress Route for Traefik dashboard (#2). Later we will create custom route for it. At the Traefik service section (#3) we define specific annotations for External DNS and AWS Load Balancer Controller. Here you need to know that by using these annotations you configure the AWS NLB and DNS records for Route53. Adjust external-dns.alpha.kubernetes.io/hostname with your root domain (#4) and service.beta.kubernetes.io/aws-load-balancer-ssl-cert with ACM certificate ARN (#5).

For more information please refer to the documentation:

The logging section (#6) is obvious. I advise setting log level to debug during the first setup as the info level is not too verbose.

So now, after adjustment in helm/traefik.yaml you are ready to install Traefik:

helm repo add traefik https://helm.traefik.io/traefik
helm install traefik traefik/traefik --create-namespace --namespace=network --values=helm/traefik.yaml

Right after, you should see NLB being created with the following list of listeners.

NLB Listeners
NLB Listeners

DNS records should also appear in the Route53 console.

Route53 records
Route53 records

If something doesn’t happen, look for the answer in logs.

kubectl logs -f aws-load-balancer-controller- -n kube-system
kubectl logs -f external- -n kube-system
kubectl logs -f traefik- -n network

The next step will be adding the Traefik dashboard route.

With the installation of Traefik, its CRD’s are installed. Check our first router definitions in network/traefik-dashboard-route.yaml . First, we add a k8s secret (#1) that will hold the credentials for the Basic Auth, then we define the BA as Traefik Middleware (#2) and finally we create an IngressRoute which will be our routing path (#3). Remember to change your domain in the Host rule.

#1
apiVersion: v1
kind: Secret
metadata:
name: dashboard-basic-auth-creds
namespace: network
type: kubernetes.io/basic-auth
stringData:
username: admin
password: admin

---

#2
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: dashboard-basic-auth
namespace: network
spec:
basicAuth:
secret: dashboard-basic-auth-creds

---

#3
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: dashboard
namespace: network
spec:
entryPoints:
- traefik
routes:
- kind: Rule
match: Host(`traefik.<YOUR_DOMAIN>`) #4
middlewares:
- name: dashboard-basic-auth
namespace: network
services:
- kind: TraefikService
name: api@internal

Apply the dashboard route.

kubectl apply -f network/traefik-dashboard-route.yaml

After a few seconds, when Traefik react to adding a new definition, the dashboard should be available in the browser under the below URL (The trailing slash is mandatory):

https://traefik.<YOUR_DOMAIN>:9000/dashboard/

Install sample apps (RabbitMQ & PostgreSQL)

Now let’s add more apps on different ports to check Traefik’s capabilities better.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install rabbitmq bitnami/rabbitmq --create-namespace --namespace=messaging -f helm/rabbitmq.yaml
helm install postgres bitnami/postgresql --create-namespace --namespace=database -f helm/postgres.yaml

Add Traefik routes for:

  • Postgres port 5432
  • AMQP RabbitMQ port 5672
  • HTTPS RabbitMQ management panel
kubectl apply -f network/postgres-route.yaml
kubectl apply -f network/rabbitmq-route.yaml

List all Traefik routes

kubectl get ingressroute,ingressroutetcps --all-namespaces`

-------------------------
NAMESPACE NAME
messaging ingressroute.traefik.containo.us/rabbitmq-http
network ingressroute.traefik.containo.us/dashboard

NAMESPACE NAME
database ingressroutetcp.traefik.containo.us/postgres
messaging ingressroutetcp.traefik.containo.us/rabbitmq-amqp

You should see two HTTP routes (Traefik dashboard, RabbitMQ panel) and two TCP routes (PostgreSQL and AQMP RabbitMQ). This state should be reflected in the Traefik panel. I encourage you to explore it because it is really rich in information and intuitive.

Traefik dashboard
Traefik dashboard

The final test will be to check if routing to test applications works correctly.

To check PostgreSQL try to connect with:

psql -h postgres.<YOUR_DOMAIN> -p 5432 -U root
# pass 'root' passwor

To check RabbitMQ AMQP connectivity execute my Python script. Update URL in utils/rabbitmq_ampq_test.py before:

python3 utils/rabbitmq_ampq_test.py

RabbitMQ admin panel should be accessible on:

https://rabbitmq.<YOUR_DOMAIN>

Final Thoughts

As you can see, working with Traefik can be simple. In our lab we needed a single AWS NLB to expose several applications from different Kubernetes namespaces and on different ports. It’s a good benchmark of simplicity. This sort of approach also has limitations, but it’s a different topic. Be aware that other are other solutions in this Ingress segment such as Nginx Ingress Controller and HAProxy Ingress Controller. As always, I encourage you to experiment and form your own opinion. However, I hope I have helped you get through the basic setup more conveniently.

--

--

Artur Bartosik

DevOps & Serverless Enthusiast. AWS, GCP, and K8S certified. Home page: https://abartosik.dev