Deploy Traefik v3 as Kubernetes Ingress Controller: Dynamic Routing, Security Middlewares, and Let’s Encrypt SSL

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Standard Kubernetes Ingress resources break down quickly once your cluster grows past a handful of services. You end up juggling messy annotation snippets, wrestling with flaky regex rewrites, and installing separate controller bundles just to get basic TLS certificates and rate limiting.

Traefik v3 fixes these headaches. Built around native Custom Resource Definitions (CRDs), it handles dynamic routing, Let’s Encrypt generation, and middleware chaining out of the box without third-party plugins.

Quick Start: Installing Traefik v3 with Helm

You can get Traefik v3 running in about five minutes. Helm simplifies the entire process by deploying the controller into its own namespace and setting up port routing for HTTP, HTTPS, and the admin dashboard.

Pull down the official Traefik repository and refresh your local index:

helm repo add traefik https://traefik.github.io/charts
helm repo update

Create a basic values-quickstart.yaml file. This configuration sets up two pods for resilience, exposes ports 80 and 443, and enables the internal web dashboard:

# values-quickstart.yaml
deployment:
  enabled: true
  replicas: 2

ingressRoute:
  dashboard:
    enabled: true
    matchRule: Host(`traefik.local`)
    entryPoints: ["web"]

ports:
  web:
    port: 8000
    exposedPort: 80
  websecure:
    port: 8443
    exposedPort: 443

service:
  type: LoadBalancer

Deploy the chart into a clean traefik namespace:

helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace \
  -f values-quickstart.yaml

Wait 30 to 60 seconds for your cloud provider (such as AWS NLB or GCP Cloud Load Balancing) to provision an external IP:

kubectl get svc -n traefik traefik -w

Before pointing production DNS records at the cluster, test the administrative interface locally using a port forward:

kubectl port-forward -n traefik $(kubectl get pods -n traefik -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].metadata.name}') 9000:9000

Visit http://localhost:9000/dashboard/ in your browser. You will see an interactive overview of all active entry points, routers, and backend services.

Core Architecture: Dynamic Routing with CRDs

Traditional Kubernetes Ingress objects rely heavily on vendor-specific annotations. These annotations make manifests brittle and difficult to validate during CI/CD checks. Traefik bypasses this problem using three dedicated Custom Resource Definitions: IngressRoute, Middleware, and TraefikService.

IngressRoute vs Standard Kubernetes Ingress

Traefik still parses standard Ingress objects for backward compatibility. However, native IngressRoute manifests offer far cleaner routing syntax. Instead of unreadable NGINX rewrite regexes, you can write readable Boolean expressions like Host(`api.example.com`) && PathPrefix(`/v1`).

Deploying a Sample Application with Dynamic Routing

Spin up a lightweight HTTP echo service running two replicas in your default namespace:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-app
  template:
    metadata:
      labels:
        app: demo-app
    spec:
      containers:
      - name: web
        image: hashicorp/http-echo
        args: ["-text=Hello from Traefik v3 Ingress!"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: demo-service
  namespace: default
spec:
  ports:
  - port: 80
    targetPort: 5678
  selector:
    app: demo-app

Expose this deployment using an IngressRoute custom resource:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: demo-ingress-route
  namespace: default
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`demo.example.com`) && PathPrefix(`/api`)
      kind: Rule
      services:
        - name: demo-service
          port: 80

Apply these manifests with kubectl apply -f app.yaml. Traefik watches the Kubernetes API server for resource events. It updates its internal routing table in under 50 milliseconds without dropping in-flight TCP connections or reloading the core binary.

Advanced Configuration: Security Middlewares & Automated SSL

Production environments need hardened HTTP headers, dynamic rate throttling, and zero-touch TLS lifecycle management.

1. Configuring Automated ACME SSL (Let’s Encrypt)

Traefik includes an embedded ACME client. It handles the full certificate issuance and renewal lifecycle on its own. It saves the resulting keys to disk, so you do not need to install or maintain cert-manager CRDs for standalone ingress setups.

Save this configuration as values-production.yaml to enable automatic HTTP-01 challenges and force HTTPS redirects. Note that we set replicas to 1 because a single ReadWriteOnce volume cannot be shared across multiple nodes:

# values-production.yaml
deployment:
  replicas: 1

persistence:
  enabled: true
  name: data
  accessMode: ReadWriteOnce
  size: 1Gi
  path: /data

additionalArguments:
  - "[email protected]"
  - "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
  - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
  - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
  - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
  - "--entrypoints.web.http.redirections.entrypoint.scheme=https"

These arguments redirect incoming port 80 traffic to HTTPS. They also set up the letsencrypt resolver to solve challenges across port 80 seamlessly.

Push these configuration changes to your running release:

helm upgrade traefik traefik/traefik -n traefik -f values-production.yaml

2. Enforcing Security Middlewares

Middlewares sit directly in the request path between Traefik and your downstream pods. They allow you to rewrite headers, inject authentication tokens, and block abusive traffic before requests reach your application code.

Here is a production middleware manifest. It applies essential OWASP security headers and caps incoming traffic at 100 requests per second with a burst allowance of 50:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: app-security-headers
  namespace: default
spec:
  headers:
    frameDeny: true
    sslRedirect: true
    browserXssFilter: true
    contentTypeNosniff: true
    stsIncludeSubdomains: true
    stsPreload: true
    stsSeconds: 31536000
    customResponseHeaders:
      X-Robots-Tag: "none,noindex,nofollow"
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: app-ratelimit
  namespace: default
spec:
  rateLimit:
    average: 100
    burst: 50

3. Combining TLS and Middlewares in an IngressRoute

Link your security policies and automated TLS resolver to an HTTPS IngressRoute:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: demo-secure-route
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`app.example.com`)
      kind: Rule
      services:
        - name: demo-service
          port: 80
      middlewares:
        - name: app-security-headers
        - name: app-ratelimit
  tls:
    certResolver: letsencrypt

In high-throughput environments—processing over 12,000 requests per second across 45 microservices—this setup holds steady. Sub-millisecond routing overhead keeps p99 latencies under 5ms while preventing burst spikes from overwhelming backend databases.

Day-2 Operations: Production Readiness

Running Traefik reliably under sustained production load requires planning around state management, global rules, and observability.

Handle ACME Storage Locks in High Availability Clusters

Traefik writes ACME certificate data into a single local file (acme.json). Standard Kubernetes persistent volumes (EBS, GPD, or Ceph RBD) use ReadWriteOnce mode, which prevents multiple pods from writing concurrently. If you scale Traefik to multiple replicas with a shared file resolver, file lock collisions will corrupt your certificates.

Choose one of two battle-tested options for multi-replica ingress pools:

  • Delegate issuance to cert-manager: Run cert-manager independently. It writes TLS certificates into native Kubernetes Secret objects, which multiple Traefik pods can mount concurrently using tls.secretName.
  • Upgrade to Traefik Enterprise: If you prefer native clustering without third-party operators, the enterprise version coordinates certificates across distributed nodes via Raft consensus.

Apply Global Middlewares to EntryPoints

Referencing the same security headers across fifty separate microservice manifests introduces human error. Instead, attach universal middlewares directly to your entry point definitions in Helm:

ports:
  websecure:
    middlewares:
      - default-app-security-headers@kubernetescrd

Traefik will enforce HSTS and rate limits globally, even if developers forget to define middlewares in their local service manifests.

Monitor Golden Signals with Prometheus

Traefik exposes native Prometheus telemetry on port 9100. Turn on metrics collection inside your Helm values:

metrics:
  prometheus:
    entryPoint: metrics
    addEntryPointsLabels: true
    addServicesLabels: true

Pair this endpoint with a Prometheus Operator ServiceMonitor. Track traefik_entrypoint_request_duration_seconds_bucket to catch latency regressions before they impact users, and set alerts on traefik_service_requests_total{code=~"5.."} for real-time error detection.

Share: