Traefik¶
Traefik (GitHub) is a cloud-native reverse proxy and ingress controller designed for dynamic service discovery in container orchestrators. Unlike Nginx Ingress which relies on annotation-heavy Ingress resources and periodic config reloads, Traefik watches the Kubernetes API directly and reconfigures routing in real-time as services appear or disappear — no HUP signals, no config generation, no race conditions between discovery and routing.
What distinguishes Traefik from other ingress controllers in this space: it defines routing through IngressRoute CRDs rather than annotations, making routing rules first-class Kubernetes objects that are composable, version-controlled, and reconcilable by GitOps controllers. Middleware (auth, rate limiting, header manipulation) is declared as separate CRD objects and chained declaratively — a model closer to a service mesh's traffic policy than a traditional reverse proxy's monolithic config.
Traefik also natively supports the emerging Gateway API standard, providing an incremental migration path away from its proprietary CRDs when the ecosystem matures.
Overview¶
| Property | Value |
|---|---|
| Namespace | traefik |
| Type | HelmRelease (chart: traefik v32.1.1) |
| Layer | Foundation services |
| Chart | traefik v32.1.1 |
| Status | Enabled |
| Source | apps/base/traefik/ |
Dependencies¶
Upstream — required before Traefik starts¶
No upstream Flux dependencies — starts immediately.
Downstream — services that depend on Traefik¶
| Service | Dependency type | Reason |
|---|---|---|
traefik-config |
Flux dependsOn |
Requires Traefik |
kagent |
Flux dependsOn |
Requires Traefik |
agentgateway |
Flux dependsOn |
Requires Traefik |
Purpose¶
Traefik is the platform's sole ingress controller, routing external traffic to 15+ services across multiple namespaces via .local domains. It sits in the foundation layer with zero dependencies — starting immediately on cluster bootstrap — and serves as a prerequisite for traefik-config (which declares the IngressRoute/Middleware CRDs), kagent, and agentgateway.
In this platform it operates as a NodePort service bound to fixed ports on the Kind cluster nodes, allowing the host machine to reach any routed service through a single stable entrypoint without LoadBalancer infrastructure. All routing decisions are expressed as IngressRoute CRDs managed through the same GitOps pipeline as the services themselves.
Why Traefik over Nginx Ingress or Envoy: The platform routes to services spanning many namespaces with per-service middleware chains (authentication, CORS, path stripping). Nginx Ingress encodes this in annotations — which are untyped, unvalidatable, and don't compose across objects. Traefik's IngressRoute CRDs make each routing rule and middleware a discrete, reconcilable Kubernetes resource that Flux can manage, diff, and prune like any other manifest. Cross-namespace routing is first-class (allowCrossNamespace: true) rather than requiring explicit namespace grants. The built-in dashboard provides immediate routing visibility during development without deploying a separate observability tool. Envoy (via Istio or standalone) would deliver equivalent L7 capability but at 10x the operational complexity and resource cost for a local development cluster.
Features¶
| Feature | Detail |
|---|---|
| Cross-namespace CRD routing | kubernetesCRD with allowCrossNamespace enables a single Traefik instance to route to services in any namespace without per-namespace ingress controllers or explicit grants |
| Dual provider mode | Both IngressRoute CRDs and standard Ingress resources are served simultaneously, allowing gradual migration and third-party chart compatibility |
| Pod anti-affinity (HA) | requiredDuringSchedulingIgnoredDuringExecution on hostname topology ensures replicas never co-locate on the same node, eliminating single-node failure as a traffic black hole |
| JSON access logs with header redaction | Structured JSON access logs keep general fields but explicitly redact Authorization, Cookie, and Proxy-Authorization headers — queryable without leaking credentials into log aggregation |
| NodePort fixed-port binding | Ports 30080 and 30443 are statically assigned for Kind cluster compatibility, giving the host machine deterministic ingress endpoints without cloud LoadBalancer provisioning |
| Secure dashboard | Dashboard enabled with insecure mode explicitly disabled — accessible only through authenticated IngressRoute rather than an open internal port |
| Telemetry suppression | Version check and anonymous usage reporting disabled via globalArguments, preventing unexpected outbound traffic from the cluster and eliminating startup latency from DNS resolution to Traefik's telemetry endpoints |
| Health ping endpoint | Dedicated ping endpoint enabled for liveness/readiness probes and Flux healthCheck verification independent of traffic-serving ports |
Configuration¶
All values sourced from base/services/environment.env
(base); per-environment overrides in clusters/stages/dev/.../environment.env.
| Parameter | Dev | Prod |
|---|---|---|
TRAEFIK_CHART_VERSION |
32.1.1 |
32.1.1 |
TRAEFIK_CPU_LIMIT |
500m |
2000m |
TRAEFIK_CPU_REQUEST |
500m |
200m |
TRAEFIK_MEMORY_LIMIT |
256Mi |
1Gi |
TRAEFIK_MEMORY_REQUEST |
256Mi |
256Mi |
TRAEFIK_REPLICA_COUNT |
1 |
2 |
Operations¶
Pod stuck Pending due to anti-affinity conflict¶
Symptoms: Traefik pod remains in Pending state. kubectl describe pod shows: 0/N nodes are available: N node(s) didn't match pod anti-affinity rules This occurs when replica count exceeds available nodes (common in single-node Kind).
kubectl get pods -n traefik -l app.kubernetes.io/name=traefik
kubectl describe pod -n traefik -l app.kubernetes.io/name=traefik | grep -A5 Events
kubectl get nodes -o wide
# If single-node cluster: reduce replica count in cluster-vars ConfigMap or temporarily patch anti-affinity
kubectl get configmap cluster-vars -n flux-system -o yaml | grep TRAEFIK_REPLICA_COUNT
# For Kind (single node), set TRAEFIK_REPLICA_COUNT=1 in cluster-vars and reconcile
flux reconcile kustomization traefik --with-source -n flux-system
HelmRelease reconciliation failed¶
Symptoms: flux get helmreleases -n flux-system shows traefik with Ready=False. Typical messages: Helm upgrade failed: ..., values don't meet the specifications, or chart version not found in repository.
flux get helmreleases -n flux-system | grep traefik
kubectl describe helmrelease traefik -n flux-system | tail -30
kubectl get helmrepository traefik -n flux-system -o yaml | grep -A5 status
# Verify chart version exists in upstream repo
helm repo add traefik-upstream https://helm.traefik.io/traefik && helm search repo traefik-upstream/traefik --versions | head -10
# Check variable substitution resolved correctly
kubectl get configmap cluster-vars -n flux-system -o yaml | grep TRAEFIK
# Force reconciliation after fixing
flux reconcile helmrelease traefik -n flux-system
IngressRoutes not routing traffic (cross-namespace)¶
Symptoms: HTTP requests return 404 despite IngressRoute existing. kubectl get ingressroute -A shows the route is created but Traefik dashboard shows no corresponding router entry.
kubectl get ingressroute -A
# Verify Traefik is watching the target namespace (CRD provider)
kubectl logs -n traefik -l app.kubernetes.io/name=traefik --tail=50 | grep -i 'error\|warn\|skip'
# Check if IngressRoute references a service in another namespace correctly
kubectl get ingressroute <route-name> -n <route-namespace> -o yaml | grep -A3 services
# Verify the backend service and port exist
kubectl get svc -A | grep <backend-service>
# Check Traefik RBAC can read IngressRoutes across namespaces
kubectl get clusterrole -l app.kubernetes.io/name=traefik -o yaml | grep -A5 ingressroute
NodePort unreachable from host on Kind¶
Symptoms: curl localhost:30080 returns connection refused despite Traefik pods running and ready. Service shows correct NodePort allocation in kubectl get svc -n traefik.
kubectl get svc -n traefik -o wide
kubectl get pods -n traefik -o wide
# Verify Kind cluster has port mappings configured (kind-config extraPortMappings)
docker ps --format '{{.Names}} {{.Ports}}' | grep kind
# Check if container port matches NodePort expectations
docker port $(docker ps -q --filter name=kind-control-plane) | grep 30080
# If no port mapping exists, the Kind config needs extraPortMappings for 30080 and 30443
# Test connectivity from inside the cluster
kubectl run curl-test --rm -i --restart=Never --image=curlimages/curl -- curl -s http://traefik.traefik.svc:8000
Traefik CrashLoopBackOff on startup¶
Symptoms: Pod repeatedly crashes with CrashLoopBackOff. Logs show entrypoint binding errors like listen tcp :8000: bind: address already in use or invalid flag errors after chart upgrade.
kubectl logs -n traefik -l app.kubernetes.io/name=traefik --previous --tail=100
# Check for duplicate entrypoint definitions (additionalArguments conflicting with ports config)
kubectl get helmrelease traefik -n flux-system -o jsonpath='{.spec.values.additionalArguments}'
kubectl get helmrelease traefik -n flux-system -o jsonpath='{.spec.values.ports}'
# Look for port conflicts with other pods on the same node
kubectl get pods -A -o wide | grep $(kubectl get pod -n traefik -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].spec.nodeName}')
# If flag errors after chart upgrade, check chart changelog for removed/renamed arguments
helm show values traefik/traefik --version $(kubectl get helmrelease traefik -n flux-system -o jsonpath='{.spec.chart.spec.version}') | head -50
Flux health check timeout for Traefik Kustomization¶
Symptoms: flux get kustomizations -n flux-system shows traefik with Ready=False and message Health check failed after 3m0s: Deployment/traefik/traefik not ready.
flux get kustomizations -n flux-system | grep traefik
kubectl get deployment traefik -n traefik -o wide
kubectl rollout status deployment/traefik -n traefik --timeout=30s
kubectl get events -n traefik --sort-by=.lastTimestamp | tail -20
# Check if HelmRelease is stuck (Kustomization waits for deployment, which waits for HelmRelease)
flux get helmreleases -n flux-system | grep traefik
# If deployment exists but replicas not ready, check pod-level issues
kubectl describe deployment traefik -n traefik | grep -A10 Conditions
kubectl get pods -n traefik -l app.kubernetes.io/name=traefik -o yaml | grep -A5 containerStatuses
Related¶
apps/base/traefik/— Kubernetes manifestsbase/services/traefik.yaml— Flux Kustomizationbase/services/environment.env— environment variables
Generated from service-catalog.json at commit 165b485 · catalog sha 4d088b0b3a67b4c4