# How to Implement Traffic Splitting and Canary Releases in Easegress

> Easily implement traffic splitting and canary releases with Easegress. Learn how to use its ServiceCanary feature for declarative request routing based on headers URLs or instance labels.

- Repository: [easegress-io/easegress](https://github.com/easegress-io/easegress)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/informer.go))

2. **Spec Generation**: When a canary is detected, the **Worker** in [`pkg/object/meshcontroller/worker/worker.go`](https://github.com/easegress-io/easegress/blob/main/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:

```yaml
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:

```yaml
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:

```yaml
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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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`](https://github.com/easegress-io/easegress/blob/main/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.