Linkerd’s TrafficSplit resource isn’t just a fancy load balancer; it’s the key to enabling sophisticated, zero-downtime deployments by letting you precisely control how traffic flows between different versions of your application.
Imagine you have a stable v1 of your service and you’ve just deployed v2. You want to send a small percentage of real user traffic to v2 to test it out, but you don’t want to risk overwhelming it or impacting your users if something goes wrong. This is where TrafficSplit shines.
Let’s see it in action. Suppose we have two deployments, my-app-v1 and my-app-v2, both running the same application but with different code. We also have a Service named my-app that acts as the single entry point for our application.
Here’s a TrafficSplit resource that directs 90% of traffic to v1 and 10% to v2:
apiVersion: split.smi-specs.io/v1alpha2
kind: TrafficSplit
metadata:
name: my-app-split
namespace: default
spec:
service: my-app
backends:
- service: my-app-v1
weight: 900m
- service: my-app-v2
weight: 100m
When this TrafficSplit is applied, Linkerd intercepts traffic destined for the my-app service. It then consults the TrafficSplit configuration and distributes incoming requests according to the specified weights. In this case, for every 100 requests, 90 will be sent to the my-app-v1 Kubernetes Service, and 10 will be sent to my-app-v2.
The real power comes from how Linkerd’s proxy, running as a sidecar to your application pods, makes these routing decisions. When a request arrives at the my-app service’s Kubernetes Service object, it’s first routed to a Linkerd proxy. This proxy, aware of the TrafficSplit policy, determines which backend Service (my-app-v1 or my-app-v2) should receive the request based on the configured weights. The proxy then forwards the request to the appropriate destination.
The weight field uses a "milliroute" system: 900m means 900 out of 1000 units of traffic, effectively 90%. You can adjust these weights dynamically without any application downtime. Want to send 50% to v2? Simply update the TrafficSplit to:
apiVersion: split.smi-specs.io/v1alpha2
kind: TrafficSplit
metadata:
name: my-app-split
namespace: default
spec:
service: my-app
backends:
- service: my-app-v1
weight: 500m
- service: my-app-v2
weight: 500m
Linkerd’s proxies will immediately begin adhering to this new distribution. This allows for gradual rollouts, canary deployments, and A/B testing with minimal risk. You can start with 1% traffic to v2, monitor its performance and error rates using Linkerd’s observability features, and gradually increase the percentage if all looks good, eventually shifting 100% of traffic to the new version before retiring the old one.
What most people miss is that the service field in the TrafficSplit refers to the destination Kubernetes Service that your application clients are configured to talk to. The backends list refers to other Kubernetes Service objects that actually point to your different deployment versions. Linkerd’s control plane watches these TrafficSplit resources and configures the sidecar proxies in your application’s pods to perform the intelligent routing. The proxies themselves don’t magically know about v1 and v2; they are instructed by the control plane based on the TrafficSplit manifest.
This mechanism of dynamic routing based on external policy is fundamental to progressive delivery strategies.