A DestinationRule in Istio doesn’t just define how traffic should be routed; it dictates how traffic behaves once it reaches a service, often in ways that surprise people.

Let’s see this in action. Imagine we have a simple v1 and v2 of our reviews service deployed.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
spec:
  # ... standard deployment spec ...
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      containers:
      - name: reviews
        image: my-reviews-service:v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
spec:
  # ... standard deployment spec ...
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
      - name: reviews
        image: my-reviews-service:v2

Now, by default, Istio’s VirtualService will load balance traffic evenly across these two versions. But what if we want to send 90% of traffic to v1 and only 10% to v2 for canary testing? This is where DestinationRule comes in, defining the endpoints that the VirtualService can then split traffic between.

Here’s a DestinationRule that sets up subsets for our reviews service:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews-destrule
spec:
  host: reviews # This must match the service name in the VirtualService
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL # Enforce mTLS between services
  subsets:
  - name: v1
    labels:
      version: v1 # Selects pods with the label app=reviews, version=v1
  - name: v2
    labels:
      version: v2 # Selects pods with the label app=reviews, version=v2

And here’s a VirtualService that uses these subsets to split traffic:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews-vs
spec:
  hosts:
  - reviews # The service name clients will call
  http:
  - route:
    - destination:
        host: reviews
        subset: v1 # Traffic goes to the 'v1' subset defined in DestinationRule
      weight: 90
    - destination:
        host: reviews
        subset: v2 # Traffic goes to the 'v2' subset defined in DestinationRule
      weight: 10

When a client calls the reviews service, the Istio sidecar intercepts the request. It consults the VirtualService for reviews. The VirtualService sees the traffic split percentages and, based on the subset values, knows to direct traffic to specific groups of pods. The DestinationRule is what defines these groups (v1 and v2) and their associated labels, allowing the VirtualService to target them precisely. The trafficPolicy on the DestinationRule applies to all traffic directed to the reviews host, including its subsets. Here, it enforces mutual TLS, ensuring only authenticated and authorized services can communicate with reviews.

The DestinationRule also lets you define load balancing policies per subset. For instance, to use a round-robin load balancer for v1 and a least-request load balancer for v2:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews-destrule
spec:
  host: reviews
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
    loadBalancer:
      simple: ROUND_ROBIN # Default for the host
  subsets:
  - name: v1
    labels:
      version: v1
    # No specific loadBalancer here, inherits from host's trafficPolicy (ROUND_ROBIN)
  - name: v2
    labels:
      version: v2
    trafficPolicy: # Specific policy for this subset
      loadBalancer:
        simple: LEAST_REQUEST

This means requests hitting the v1 subset will cycle through available pods, while requests hitting the v2 subset will be sent to the pod currently serving the fewest active requests.

A common misconception is that DestinationRule is just about defining subsets. While subsets are its most visible feature, the trafficPolicy section is incredibly powerful. It allows you to configure connection pool settings (like max requests per connection, connection timeouts), outlier detection (e.g., ejecting unhealthy pods from the load balancing pool after a certain number of consecutive errors), and TLS settings per host or per subset. This granular control means you can have different connection pooling behaviors for v1 versus v2 of the same service, or enforce mTLS only on certain routes.

The host field in the DestinationRule is crucial: it must match the host field in the VirtualService’s destination block. This is how Istio links the routing rules (VirtualService) to the endpoint definitions and policies (DestinationRule). If you have multiple DestinationRules for the same host, Istio merges them, but it’s generally best practice to have one DestinationRule per host for clarity.

The loadBalancer configuration within a trafficPolicy is applied to the traffic after it has been routed to a specific subset by the VirtualService. If a trafficPolicy is defined at the host level and also within a subset, the subset’s policy overrides the host’s policy for requests directed to that subset.

One thing most people don’t realize is that the outlierDetection configuration within a trafficPolicy can significantly improve service resilience. By defining criteria for what constitutes an "unhealthy" pod (e.g., consecutive 5xx errors, gateway errors, connection errors, or even slow responses), Istio can temporarily remove that pod from the load balancing pool. This prevents cascading failures where a single faulty pod impacts multiple user requests, buying time for the pod to recover or be replaced without disrupting the overall service.

Once you’ve got DestinationRule and VirtualService working together for traffic splitting and load balancing, the next natural step is exploring advanced routing scenarios, like request-based routing using headers or query parameters.

Want structured learning?

Take the full Istio course →