Mastering Traefik Mesh: A Lightweight, Non‑Intrusive Service Mesh for Kubernetes
This guide introduces Traefik Mesh, a lightweight, non‑intrusive service mesh built on Traefik and SMI‑compatible Kubernetes, explains its sidecar‑free architecture, details installation via Helm, outlines static and dynamic configuration options, and provides step‑by‑step examples for deploying and testing services with traffic routing, retries, ACLs, and traffic splitting.
Non‑intrusive Service Mesh
Traefik meshis a lightweight service mesh that is simple to install and use. It is built on
Traefikand conforms to the latest SMI (Service Mesh Interface) specifications for Kubernetes clusters.
The main feature of
Traefik meshis its
non‑intrusivenature: deploying it does not modify existing Kubernetes objects.
Traefik meshoperates without sidecars; routing is handled by a proxy running on each node, and the mesh controller runs in a separate
Podthat processes configuration and deployment for the proxy nodes.
Its logic relies on
CoreDNS, which is lightly reconfigured to allow
Meshendpoints alongside standard Kubernetes endpoints.
Installation
Prerequisites: Kubernetes 1.11+ CoreDNS 1.3+ Helm v3
Installation is straightforward with Helm:
<code>helm repo add traefik-mesh https://helm.traefik.io/mesh
helm repo update</code>Download the chart:
<code>helm pull traefik-mesh/traefik-mesh</code>Extract the chart:
<code>tar xf traefik-mesh-3.0.6.tgz</code>Traefik mesh deploys four services:
controller – the mesh controller that analyses and applies configuration.
proxy – the data‑plane proxy handling traffic on each node.
tracing – tracing configuration.
metrics – monitoring configuration.
Install the mesh:
<code>helm install traefik-mesh .</code>The mesh requires a compatible
CoreDNSConfigMap. Example modifications:
<code>#### Begin Maesh Block
maesh:53 {
errors
rewrite continue {
name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh default-{1}-6d61657368-{2}.default.svc.cluster.local
answer name default-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.default\.svc\.cluster\.local {1}.{2}.maesh
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
#### End Maesh Block
#### Begin Traefik Mesh Block
traefik.mesh:53 {
errors
rewrite continue {
name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.traefik.mesh default-{1}-6d61657368-{2}.default.svc.cluster.local
answer name default-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.default\.svc\.cluster\.local {1}.{2}.traefik.mesh
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
#### End Traefik Mesh Block</code>If CoreDNS reports the error "plugin/forward: this plugin can only be used once per Server Block", check that the ConfigMap does not contain duplicate
forwardsections.
Configuration
Traefik mesh configuration is split into static and dynamic parts.
Static Configuration
Specify image versions for the
controllerand
Traefikcomponents.
Set log level and format for
controllerand
proxies.
Choose the mesh mode (default
HTTP).
Enable
tracingsupport.
Activate ACL mode to block all traffic unless explicitly allowed via SMI traffic targets.
Dynamic Configuration
Dynamic settings are applied through Kubernetes annotations and SMI objects. Supported parameters include:
Traffic‑Type (http, tcp, udp)
Scheme (http, https, h2c)
Retry attempts
Circuit‑Breaker expression
Rate‑Limit (average and burst)
Traffic‑Split
Traffic‑Target
Example annotation for a service:
<code>mesh.traefik.io/traffic-type: "http"
mesh.traefik.io/retry-attempts: "2"</code>Access control is defined with an
HTTPRouteGroupand a corresponding
TrafficTargetthat grants a client ServiceAccount permission to access specific routes.
Example Deployment
The following manifests deploy a namespace
whoamiwith two applications (HTTP and TCP) and the necessary ServiceAccounts, Deployments, Services, and a client pod.
<code>apiVersion: v1
kind: Namespace
metadata:
name: whoami
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: whoami-server
namespace: whoami
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: whoami-client
namespace: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami
namespace: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
serviceAccount: whoami-server
containers:
- name: whoami
image: traefik/whoami:v1.6.0
imagePullPolicy: IfNotPresent
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami-tcp
namespace: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami-tcp
template:
metadata:
labels:
app: whoami-tcp
spec:
serviceAccount: whoami-server
containers:
- name: whoami-tcp
image: traefik/whoamitcp:v0.1.0
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: whoami
labels:
app: whoami
spec:
type: ClusterIP
ports:
- port: 80
name: whoami
selector:
app: whoami
---
apiVersion: v1
kind: Service
metadata:
name: whoami-tcp
namespace: whoami
labels:
app: whoami-tcp
spec:
type: ClusterIP
ports:
- port: 8080
name: whoami-tcp
selector:
app: whoami-tcp
---
apiVersion: v1
kind: Pod
metadata:
name: whoami-client
namespace: whoami
spec:
serviceAccountName: whoami-client
containers:
- name: whoami-client
image: giantswarm/tiny-tools:3.9
command:
- "sleep"
- "3600"</code>Check deployment status:
<code>kubectl get all -n whoami</code>Test connectivity:
<code># kubectl -n whoami exec whoami-client -- curl -s whoami.whoami.svc.cluster.local
Hostname: whoami-576cb59fd-qvnl7
IP: 127.0.0.1
IP: 172.16.235.193
RemoteAddr: 172.16.7.181:33150
GET / HTTP/1.1
Host: whoami.whoami.svc.cluster.local
User-Agent: curl/7.64.0
Accept: */*
# kubectl -n whoami exec -ti whoami-client -- nc whoami-tcp.whoami.svc.cluster.local 8080
my data
Received: my data</code>To enable Traefik mesh for the services, add the appropriate annotations:
<code>apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: whoami
labels:
app: whoami
annotations:
mesh.traefik.io/traffic-type: "http"
mesh.traefik.io/retry-attempts: "2"
spec:
type: ClusterIP
ports:
- port: 80
name: whoami
selector:
app: whoami
---
apiVersion: v1
kind: Service
metadata:
name: whoami-tcp
namespace: whoami
labels:
app: whoami-tcp
annotations:
mesh.traefik.io/traffic-type: "tcp"
spec:
type: ClusterIP
ports:
- port: 8080
name: whoami-tcp
selector:
app: whoami-tcp</code>After adding the annotations, the service DNS can be accessed via the
traefik.meshdomain instead of
svc.cluster.local:
<code># Before: curl whoami.whoami.svc.cluster.local
# After: curl whoami.whoami.traefik.mesh</code>Both the original and mesh‑enabled addresses remain functional, allowing users to choose their preferred method.
References: https://traefik.io/traefik/ https://smi-spec.io/ https://coredns.io/
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.