Skip to main content

Gateway API (Alpha)

Alpha Feature

Gateway API routing support is currently in alpha. While functional, it has some limitations in complex multi-service environments. See Limitations below.

If your cluster uses the Kubernetes Gateway API for traffic management, you can enable routing by setting gatewayAPI.enabled to true under your mesh provider's helm values during operator installation. This causes the Signadot Operator to create derived HTTPRoute and GRPCRoute resources that route sandbox traffic alongside your existing baseline routes.

Gateway API uses source-side routing, where the routing decision happens at the source of a request. When Service A calls Service B, the proxy handling outbound traffic from Service A examines the request headers and decides whether to send it to Service B's baseline or sandbox based on the routing key.

Service A Pod                     Service B Pods

Main Container ┌─────────────┐
│ │ Sandbox │
▼ ┌──▶│ Service B │
Envoy/Proxy ──────────────────┤ └─────────────┘
(Routing decision here) ⚡ │
│ │ ┌─────────────┐
│ └──▶│ Baseline │
│ │ Service B │
└─────────────┘

How It Works

When you create a sandbox that forks a workload, the Signadot Operator:

  1. Discovers baseline routes: Finds all HTTPRoute and GRPCRoute resources that have backendRefs pointing to the service associated with your baseline workload.

  2. Creates derived routes: For each baseline route, creates derived route(s) with additional header-matching rules that look for routing keys in OpenTelemetry Baggage headers, W3C Trace State headers, or custom headers.

  3. Routes sandbox traffic: When a request contains a matching routing key, the derived route directs it to the sandboxed workload's service instead of the baseline.

Enabling Gateway API Routing

Gateway API routing must be enabled under your service mesh configuration. Enable it during operator installation or upgrade:

# values.yaml
istio:
enabled: true
gatewayAPI:
enabled: true

Or via command line:

helm install signadot-operator signadot/operator \
--set istio.enabled=true \
--set istio.gatewayAPI.enabled=true \
--set agent.clusterToken='<cluster-token>'

Requirements

  1. Gateway API CRDs must be installed in your cluster (HTTPRoute, GRPCRoute, Gateway, etc.)

  2. Istio or Linkerd must be running as the Gateway API implementation

  3. Baseline HTTPRoute or GRPCRoute resources must exist with backendRefs pointing to your baseline services

Example Baseline HTTPRoute

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: frontend-route
namespace: hotrod
spec:
parentRefs:
- name: my-gateway
namespace: gateway-system
rules:
- matches:
- path:
type: PathPrefix
value: /api
headers:
- name: x-env
value: production
backendRefs:
- name: frontend
port: 8080

Excluding Routes

To prevent Signadot from creating derived routes for a specific HTTPRoute or GRPCRoute, add the ignore annotation:

metadata:
annotations:
routing.signadot.com/ignore: "true"

Specificity-Based Routing

Gateway API uses specificity-based routing to determine which route handles a request. When multiple HTTPRoutes could match a request, the route with the most specific match wins. Specificity is determined by factors like path length, path match type (Exact > Prefix), and number of header matches.

Signadot leverages this by creating derived routes that add header-matching rules for routing keys. When a request contains a routing key, the derived route is more specific than the baseline route (same path match plus additional header match), so it takes precedence and routes to the sandbox.

Limitations

Because specificity is evaluated globally across all HTTPRoute resources, a baseline route for a different service could potentially be more specific than a sandbox's derived route if that baseline has more header matches.

This is unlikely to occur when services use distinct path prefixes (e.g., /api/users/* vs /api/orders/*). If your environment has complex routing where multiple services share paths and rely on header matching, consider using Istio VirtualServices or DevMesh instead.