Traefik Mesh TrafficSplit: Weighted Canary Routing Between Deployments
Learn how SMI TrafficSplit in Traefik Mesh maps to Traefik weighted load balancing for canary routing, with a worked example, verification steps, and common pitfalls.
03 Jun 2026, 07:26 UTC

The problem: gradual traffic shift without changing client endpoints
If you run two versions of an application in Kubernetes and want to canary a new release, you need a way to send a controlled share of traffic to the new version while clients keep calling the same Service name. In Traefik Mesh, the SMI TrafficSplit resource is the supported mechanism for this: it declares relative weights for backend Services, and the controller translates that into Traefik weighted load balancing. The useful takeaway is that you do not need to change client code or DNS; you define a stable root Service and a TrafficSplit that points to version-specific Services.
How TrafficSplit maps to Traefik weighted load balancing
Traefik Mesh watches SMI custom resources. When you apply a TrafficSplit, the controller reconciles it into Traefik dynamic configuration. Internally, it creates a Traefik weighted service that references the backend Services you list. The Traefik data plane then performs the actual distribution on each request. Clients resolve and connect to the root Service name; the mesh intercepts and routes based on the weights.
Worked example: splitting traffic between two Deployments
Assume you have two Deployments, app-v1 and app-v2, each with pods exposing port 8080. Create three Services in the same namespace: app-v1 and app-v2 selecting their respective pods, and a stable root Service app. The root Service does not need to select pods directly once the mesh intercepts it, but keeping a selector can create phantom endpoints if pods remain behind it.
apiVersion: v1
kind: Service
metadata:
name: app
namespace: default
spec:
selector:
app: app
ports:
- port: 80
targetPort: 8080
---
apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
name: app-canary
namespace: default
spec:
service: app
backends:
- service: app-v1
weight: 90
- service: app-v2
weight: 10
Replace default with your target namespace and adjust the Service names and weights to match your release. Confirm the exact apiVersion your cluster serves before applying; a mismatched version is rejected or silently ignored.
Weights are ratios, not guarantees
The controller normalizes weights into relative ratios. A 90/10 split does not guarantee exactly 90 percent and 10 percent of requests; it sets the proportion used by the load balancer. Keep weights simple and verify the effective ratio by observation.
Access control is separate from splitting
A TrafficSplit controls distribution, not authorization. Depending on mesh configuration, callers may also need a matching SMI TrafficTarget and HTTPRouteGroup to reach the root Service. A split alone does not necessarily authorize the caller.
Limits and common mistakes
API version mismatches
Confirm the installed SMI CRD version before applying a manifest. If the apiVersion does not match what the cluster serves, the object is rejected or ignored.
Namespace boundaries
Keep the TrafficSplit and every referenced Service in the same namespace. Cross-namespace splits commonly surface as no endpoints or 503 responses.
Port and readiness mismatches
Backend Services must expose the port that root-Service clients use, and pods must be Ready. Port mismatches or unready pods look like split failures even though the configuration is accepted.
Phantom endpoints from root Service selectors
Do not assume the root Service selector still matters once the mesh intercepts it. If the root Service selects pods directly, those pods can become endpoints and skew the observed split. Point the root Service at a dummy selector or leave it selecting a non-existent label if your mesh setup requires a selector.
Project lifecycle
Traefik Mesh has been deprecated and archived upstream. Treat this as a pattern for existing installations and plan migration rather than adopting it for new production traffic. Verify compatibility with your current Kubernetes release before relying on it.
Verifying the split
Run these commands from a machine with kubectl access to the cluster and permissions to read SMI resources and Traefik Mesh components.
List installed SMI CRDs and versions:
kubectl get crd | grep smi kubectl api-resources | grep trafficsplitLook for a CRD such as
trafficsplits.split.smi-spec.io. If it is absent, the controller is not installed or uses a different API group.Read the object back to confirm acceptance:
kubectl get trafficsplit app-canary -n default -o yamlConfirm the spec shows
service: appand the two backends with weights. If the object is missing, check theapiVersionin your manifest.Check controller logs for reconciliation:
kubectl logs -n traefik-mesh -l app=traefik-mesh --tail=100Look for log lines referencing the TrafficSplit name. The namespace and label selector vary by installation.
Inspect the generated Traefik weighted service:
kubectl port-forward -n traefik-mesh svc/traefik 8080:8080Then query the Traefik API at
http://localhost:8080/api/http/servicesand look for a weighted service referencing both backends. The API path and port depend on your installation.Exercise the split from an in-cluster pod:
kubectl run -it --rm curl --image=curlimages/curl --restart=Never -- shFrom inside the pod, loop requests to the root Service and count responses from each version. Small samples can look uneven; gather enough requests to see the ratio.
Reverting the change
Because applying a TrafficSplit changes cluster state, revert by either deleting the resource or updating weights to send all traffic to the original version. For example, set app-v1 to weight 1 and app-v2 to weight 0, or remove the TrafficSplit entirely:
kubectl delete trafficsplit app-canary -n default
After deletion, traffic returns to the root Service behavior defined by the mesh defaults. If the root Service has no valid endpoints without the split, clients may see connection failures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.