When multiple versions of a service run side by side -- for example, a stable baseline and one or more canary deployments -- you need a way to send each request to the correct version. Service Mesh (ASM) solves this with traffic labels: custom HTTP headers that the TrafficLabel CustomResourceDefinition (CRD) attaches to requests. You define routing rules that match these headers and direct traffic to the corresponding workload version.
Label-based routing relies on two Istio resources that work together:
DestinationRule -- Groups workload instances into named subsets. Each subset selects Pods by Kubernetes labels (typically a
versionlabel). This resource defines *where* traffic can go.VirtualService -- Evaluates routing rules top to bottom and sends each request to the first matching subset. A catch-all route at the end handles unmatched traffic. This resource defines *which* traffic goes *where*.
Routing rules are evaluated sequentially from top to bottom. The first rule that matches a request wins, and subsequent rules are skipped. Always place a default route at the end to catch unmatched traffic.
Core example
The following minimal configuration routes requests with the header asm-labels-test: test1 to the test1 subset, and sends all other requests to the base subset:
# DestinationRule: define the subsets
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: dr-productpage
spec:
host: productpage
subsets:
- name: test1
labels:
version: test1
- name: base
labels:
version: base
---
# VirtualService: route by header value
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-productpage
spec:
hosts:
- productpage
http:
- match:
- headers:
asm-labels-test:
exact: test1
route:
- destination:
host: productpage
subset: test1
- route:
- destination:
host: productpage
subset: baseApply both resources:
kubectl apply -f dr-productpage.yaml
kubectl apply -f vs-productpage.yamlVerify the routing:
# Request with label header goes to test1 subset
curl -H "asm-labels-test: test1" http://<productpage-url>
# Request without the header goes to base subset
curl http://<productpage-url>For more subsets and advanced configurations, see the sections below.
Prerequisites
Before you begin, make sure that you have:
Traffic labels configured through the TrafficLabel CRD. For details, see Label traffic
Create a destination rule
A destination rule defines the available subsets for a service. Each subset maps to a group of Pods identified by a Kubernetes label.
Create a file named
dr-productpage.yamlwith the following content.This example defines subsets
test1,test2,test3, andbasefor theproductpageservice. Each subset selects Pods whoseversionlabel matches the subset name:apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: dr-productpage spec: host: productpage subsets: - name: test1 labels: version: test1 - name: test2 labels: version: test2 - name: test3 labels: version: test3 ... - name: testn labels: version: testn - name: base labels: version: baseApply the destination rule:
kubectl apply -f dr-productpage.yaml
Create a virtual service
A virtual service defines the routing logic. Each rule matches requests by header value and routes them to the corresponding subset. Rules are evaluated top to bottom -- the first match wins.
Create a file named
vs-productpage.yamlwith the following content.In this example, a request with
asm-labels-test: test1goes to thetest1subset, one withtest2goes totest2, and so on. The final route without amatchblock catches all remaining requests and sends them to thebasesubset:apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: vs-productpage spec: hosts: - productpage http: - match: - headers: asm-labels-test: exact: test1 route: - destination: host: productpage subset: test1 - match: - headers: asm-labels-test: exact: test2 route: - destination: host: productpage subset: test2 - match: - headers: asm-labels-test: exact: test3 route: - destination: host: productpage subset: test3 - route: - destination: host: productpage subset: baseThe following table describes the key fields:
Field
Description
match.headers.asm-labels-test
The traffic label name to match against
match.headers.exact
The exact traffic label value required for a match
route.destination.subset
The destination subset that receives matching traffic
Apply the virtual service:
kubectl apply -f vs-productpage.yaml
Verify the routing rules
After you apply both resources, confirm that traffic routes correctly:
# Confirm the resources exist
kubectl get destinationrule dr-productpage
kubectl get virtualservice vs-productpage
# Send a test request with a traffic label header
# Replace <productpage-url> with your service URL
curl -H "asm-labels-test: test1" http://<productpage-url>The request with asm-labels-test: test1 should reach a Pod in the test1 subset. Test with other header values (test2, test3) to confirm each subset receives the expected traffic. A request without the asm-labels-test header should fall through to the base subset.
Header-based routing depends on each service in the call chain forwarding the traffic label header. If an intermediate service drops the header, downstream routing rules silently fail. Make sure that your application or the ASM sidecar propagates the asm-labels-test header end to end.
Simplify the virtual service with variable syntax
When many workload versions exist, listing a match block for each one makes the virtual service verbose. Replace the explicit matches with the $asm-labels-test variable syntax. ASM resolves the variable at runtime and routes traffic to the subset whose name matches the header value. If the target subset is unavailable, traffic shifts to other available versions:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-productpage
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
subset: $asm-labels-testConfigure fallback routing
With ASM Enterprise Edition, traffic automatically falls back to a backup service when the target subset is unavailable -- for example, when the subset is not defined or no matching Pod exists.
Specify the backup target with the fallback field under route:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-productpage
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
subset: $asm-labels-test
fallback:
target:
host: productpage
subset: baseThe following table describes the fallback fields:
Field | Description |
target.host | The service to receive fallback traffic |
target.subset | The subset to receive fallback traffic |
Related information
Label traffic -- Configure traffic labels with the TrafficLabel CRD