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.name of the ServiceCanary object

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:

  1. Generates a TrafficGate spec that includes the canary routing rules
  2. Configures header injection for matching requests
  3. 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:

  1. Configuration Ingestion: The MeshController watches ServiceCanary objects via Kubernetes-style informers (informer.go)

  2. Spec Generation: When a canary is detected, the Worker in pkg/object/meshcontroller/worker/worker.go rebuilds the TrafficGate specification. This involves:

    • Mapping the ServiceCanary priority to rule evaluation order
    • Translating trafficRules (headers, URLs) into match conditions
    • Setting the X-Mesh-Service-Canary header injection for matched traffic
  3. 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 ServiceCanary resource defined in pkg/object/meshcontroller/spec/spec.go
  • Traffic routing is header-driven using the X-Mesh-Service-Canary header injected by the Worker in pkg/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →