Traefik can route to services in namespaces other than its own, but it doesn’t do it by default.
Here’s how Traefik discovers and routes to services across Kubernetes namespaces:
Let’s imagine we have a simple web application deployed in a namespace called app-ns and we want Traefik, running in its own traefik-ns, to expose it.
# app-ns/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-app
namespace: app-ns
spec:
replicas: 1
selector:
matchLabels:
app: my-web-app
template:
metadata:
labels:
app: my-web-app
spec:
containers:
- name: web-app
image: nginxdemos/hello:plain-text
ports:
- containerPort: 80
---
# app-ns/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-web-app-service
namespace: app-ns
spec:
selector:
app: my-web-app
ports:
- protocol: TCP
port: 80
targetPort: 80
Now, Traefik needs to be configured to see this service. By default, Traefik’s Kubernetes CRD provider (or Ingress controller provider) only watches the namespace it’s deployed in. To enable cross-namespace routing, we need to tell Traefik to watch other namespaces.
The most common way to do this is by configuring the Traefik Helm chart or static configuration.
Using Helm Values (Recommended for Helm Deployments):
When installing or upgrading Traefik via Helm, you can specify the namespaces to watch.
# values.yaml for Traefik Helm chart
providers:
kubernetesCRD:
enabled: true
allowCrossNamespace: true # This is key!
namespaces:
- traefik-ns # Traefik's own namespace
- app-ns # The namespace where our app service lives
If you’re not using Helm, you’d modify the static configuration of your Traefik deployment. For the Kubernetes CRD provider, this would look something like:
# traefik.yml (static configuration)
providers:
kubernetesCRD:
enabled: true
allowCrossNamespace: true
namespaces:
- traefik-ns
- app-ns
Once Traefik is configured to watch app-ns, you can create a IngressRoute (or Ingress if using the Ingress controller provider) in any namespace, and Traefik will be able to resolve the service my-web-app-service in app-ns.
# traefik-ns/ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-web-app-route
namespace: traefik-ns # Or any other namespace Traefik watches
spec:
entryPoints:
- websecure
routes:
- match: Host(`myapp.example.com`)
kind: Rule
services:
- name: my-web-app-service # Service name
port: 80
namespace: app-ns # Namespace of the service
When a request for myapp.example.com arrives at Traefik, it will look at the IngressRoute. It sees the match condition and the target service. Because Traefik is configured to watch app-ns and allowCrossNamespace: true, it can query the Kubernetes API for my-web-app-service in app-ns and forward the request accordingly.
The core mechanism is Traefik’s ability to query the Kubernetes API. By default, it’s restricted to its own namespace for security and performance. When allowCrossNamespace: true is set and specific namespaces are listed, Traefik’s controller is authorized to fetch service and endpoint information from those other namespaces. It then uses this information to build its internal routing table.
The one detail that trips people up is that the namespace field in the IngressRoute (or Ingress) is mandatory if the service is in a different namespace than the IngressRoute itself. If you omit it, Traefik will assume the service is in the same namespace as the IngressRoute.
The next hurdle is often configuring TLS for these cross-namespace routes, which involves ensuring your IngressRoute can reference Secrets for certificates, and those secrets might also need to be in a namespace Traefik can access.