How to Implement Traffic Splitting and Canary Releases in Easegress
Yes, Easegress natively supports traffic splitting and canary releases through its ServiceCanary feature, which uses declarative configuration to route requests based on headers, URLs, or service instance labels.
Easegress is a cloud-native traffic orchestration system that provides progressive delivery capabilities without requiring a full service mesh infrastructure. By leveraging the mesh controller built into easegress-io/easegress, you can safely roll out new service versions, conduct A/B testing, and implement sophisticated traffic routing policies using pure YAML configuration.
Core Components of Easegress Canary Releases
ServiceCanary Specification
The ServiceCanary object is the primary resource for defining canary deployments. According to the source code in pkg/object/meshcontroller/spec/spec.go, this specification includes:
- Priority: A numeric value where lower numbers indicate higher priority (evaluated first)
- Selector: Matches target services by name and optional instance labels
- TrafficRules: Defines matching criteria including HTTP headers, URL patterns, and query parameters
When you create a ServiceCanary object using egctl create -f canary.yaml, the mesh controller's informer watches for these changes and triggers a reconciliation loop.
X-Mesh-Service-Canary Header
The constant ServiceCanaryHeaderKey defined in pkg/object/meshcontroller/spec/spec.go corresponds to the HTTP header X-Mesh-Service-Canary. This header serves as the internal routing mechanism:
- The mesh controller's Worker (implemented in
pkg/object/meshcontroller/worker/worker.go) injects this header into requests that match a canary's traffic rules - Downstream services or sidecars inspect this header to determine which version (primary or canary) should handle the request
- The header value corresponds to the
metadata.nameof theServiceCanaryobject
TrafficGate Integration
The TrafficGate object (managed by pkg/object/trafficcontroller/trafficcontroller.go) acts as the HTTP/GRPC server that evaluates traffic rules. When the Worker rebuilds the traffic gate specification in the initTrafficGate method (lines 329-345 in worker.go), it:
- Generates a
TrafficGatespec that includes the canary routing rules - Configures header injection for matching requests
- Updates the running traffic controller without requiring a restart
How Traffic Splitting Works Internally
The architecture follows a controller-worker pattern for dynamic traffic management:
-
Configuration Ingestion: The
MeshControllerwatchesServiceCanaryobjects via Kubernetes-style informers (informer.go) -
Spec Generation: When a canary is detected, the Worker in
pkg/object/meshcontroller/worker/worker.gorebuilds theTrafficGatespecification. This involves:- Mapping the
ServiceCanarypriority to rule evaluation order - Translating
trafficRules(headers, URLs) into match conditions - Setting the
X-Mesh-Service-Canaryheader injection for matched traffic
- Mapping the
-
Runtime Routing: The TrafficGate (HTTPServer/GRPCServer) evaluates incoming requests against the compiled rules. When a match occurs, it injects the canary header and forwards the request to the appropriate service instance selected by the mesh controller's load balancer.
This design allows zero-downtime updates to routing rules—the traffic gate is reconfigured dynamically without dropping existing connections.
Implementing Canary Releases in Practice
Header-Based Routing
Route specific user segments to the canary version using HTTP headers. This example from the Easegress documentation routes users in the "beta-testers" group to the new version:
apiVersion: v2
kind: ServiceCanary
metadata:
name: new-version-canary
spec:
priority: 5
selector:
serviceName: order-service
serviceInstanceLabels:
version: v2
trafficRules:
headers:
X-User-Group: exact: beta-testers
urls:
- exact: /api/v2/*
URL-Based Routing
Migrate specific API endpoints gradually by matching URL patterns:
apiVersion: v2
kind: ServiceCanary
metadata:
name: api-v2-canary
spec:
priority: 3
selector:
serviceName: payment-service
trafficRules:
urls:
- prefix: /api/v2/
- exact: /api/v2/payments
Percentage-Based Traffic Splitting
While Easegress does not expose a direct percentage field in the ServiceCanary spec, you can achieve percentage-based splitting by labeling a subset of service instances. Deploy your canary version to a specific percentage of pods (e.g., 10%) and label them accordingly:
apiVersion: v2
kind: ServiceCanary
metadata:
name: pct-10-canary
spec:
priority: 5
selector:
serviceName: payment-service
serviceInstanceLabels:
canary: "true"
trafficRules:
headers: {}
urls: {}
In this configuration, all traffic destined for payment-service is routed only to instances labeled canary=true. By adjusting the number of pods carrying this label in your deployment, you effectively control the traffic percentage.
Summary
- Easegress provides native canary release support through the
ServiceCanaryresource defined inpkg/object/meshcontroller/spec/spec.go - Traffic routing is header-driven using the
X-Mesh-Service-Canaryheader injected by the Worker inpkg/object/meshcontroller/worker/worker.go - Dynamic updates require no restarts—the TrafficGate is reconfigured in real-time by the TrafficController (
pkg/object/trafficcontroller/trafficcontroller.go) - Flexible matching criteria support headers, URL patterns, and service instance labels for A/B testing, beta programs, and progressive rollouts
- Percentage splitting is achieved by labeling a proportional subset of service instances rather than using a weight field
Frequently Asked Questions
Does Easegress support percentage-based canary deployments?
Yes, but through a different mechanism than traditional weight-based routing. Instead of specifying a percentage in the ServiceCanary spec, you label a specific percentage of your service instances (e.g., canary: "true" on 10% of pods) and configure the canary selector to match only those labeled instances. All matching traffic is then routed exclusively to that subset, effectively achieving the desired traffic split.
What is the X-Mesh-Service-Canary header used for?
The X-Mesh-Service-Canary header is an internal routing mechanism defined as ServiceCanaryHeaderKey in pkg/object/meshcontroller/spec/spec.go. When a request matches a canary's traffic rules, the mesh controller's Worker injects this header into the request before forwarding it downstream. Backend services or sidecars inspect this header to identify which version (primary or canary) should handle the request, enabling version-aware routing decisions.
How does Easegress compare to Istio for canary releases?
While Istio requires a full service mesh with sidecar proxies, Easegress provides canary capabilities through its built-in mesh controller without mandating sidecars for every service. Easegress uses the ServiceCanary CRD and dynamic TrafficGate updates (managed in pkg/object/trafficcontroller/trafficcontroller.go) to achieve similar traffic splitting, header-based routing, and A/B testing patterns. This makes Easegress lighter for scenarios where you need ingress-level canary control without complete mesh adoption.
Can I perform A/B testing with Easegress traffic splitting?
Yes, A/B testing is fully supported by combining ServiceCanary traffic rules with user attributes. You can define multiple canary objects with different priorities that route based on HTTP headers (e.g., X-Device-Type: mobile vs desktop), cookies, or URL paths. Each canary targets a different version of your service, allowing you to compare performance metrics, conversion rates, or user experience between variants while the mesh controller handles the routing logic transparently.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →