Rules Configuration

Istio provides a simple Domain-specific language (DSL) to control how API calls and layer-4 traffic flow across various services in the application deployment. The DSL allows the operator to configure service-level properties such as circuit breakers, timeouts, retries, as well as set up common continuous deployment tasks such as canary rollouts, A/B testing, staged rollouts with %-based traffic splits, etc. See routing rules reference for detailed information.

For example, a simple rule to send 100% of incoming traffic for a “reviews” service to version “v1” can be described using the Rules DSL as follows:

destination: reviews.default.svc.cluster.local
route:
- tags:
    version: v1
  weight: 100

The destination is the name of the service to which the traffic is being routed. In a Kubernetes deployment of Istio, the route tag “version: v1” corresponds to a Kubernetes label “version: v1”. The rule ensures that only Kubernetes pods containing the label “version: v1” will receive traffic. Rules can be configured using the istioctl CLI. See the configuring request routing task for examples.

There are two types of rules in Istio, Routes and Destination Policies (these are not the same as Mixer policies). Both types of rules control how requests are routed to a destination service.

Routes

Routes control how requests are routed to different versions of a service. Requests can be routed based on the source and destination, HTTP header fields, and weights associated with individual service versions. The following important aspects must be keep in mind while writing route rules:

Qualify rules by destination

Every rule corresponds to some destination service identified by a destination field in the rule. For example, all rules that apply to calls to the “reviews” service will include the following field.

destination: reviews.default.svc.cluster.local

The destination value SHOULD be a fully qualified domain name (FQDN). It is used by Istio-Manager for matching rules to services. For example, in Kubernetes, a fully qualified domain name for a service can be constructed using the following format: serviceName.namespace.dnsSuffix.

Qualify rules by source/headers

Rules can optionally be qualified to only apply to requests that match some specific criteria such as the following:

1. Restrict to a specific caller. For example, the following rule only apply to calls from the “reviews” service.

destination: ratings.default.svc.cluster.local
match:
  source: reviews.default.svc.cluster.local

The source value, just like destination, MUST be a FQDN of a service.

2. Restrict to specific versions of the caller. For example, the following rule refines the previous example to only apply to calls from version “v2” of the “reviews” service.

destination: ratings.default.svc.cluster.local
match:
  source: reviews.default.svc.cluster.local
  sourceTags:
    version: v2

3. Select rule based on HTTP headers. For example, the following rule will only apply to an incoming request if it includes a “cookie” header that contains the substring “user=jason”.

destination: reviews.default.svc.cluster.local
match:
  httpHeaders:
    cookie:
      regex: "^(.*?;)?(user=jason)(;.*)?$"

If more than one property-value pair is provided, then all of the corresponding headers must match for the rule to apply.

Multiple criteria can be set simultaneously. In such a case, AND semantics apply. For example, the following rule only applies if the source of the request is “reviews:v2” AND the “cookie” header containing “user=jason” is present.

destination: ratings.default.svc.cluster.local
match:
  source: reviews.default.svc.cluster.local
  sourceTags:
    version: v2
  httpHeaders:
    cookie:
      regex: "^(.*?;)?(user=jason)(;.*)?$"

Split traffic between service versions

Each route rule identifies one or more weighted backends to call when the rule is activated. Each backend corresponds to a specific version of the destination service, where versions can be expressed using tags.

If there are multiple registered instances with the specified tag(s), they will be routed to based on the load balancing policy configured for the service, or round-robin by default.

For example, the following rule will route 25% of traffic for the “reviews” service to instances with the “v2” tag and the remaining traffic (i.e., 75%) to “v1”.

destination: reviews.default.svc.cluster.local
route:
- tags:
    version: v2
  weight: 25
- tags:
    version: v1
  weight: 75

Timeouts and retries

By default, the timeout for http requests is 15 seconds, but this can be overridden in a route rule as follows:

destination: "ratings.default.svc.cluster.local"
route:
- tags:
    version: v1
httpReqTimeout:
  simpleTimeout:
    timeout: 10s

The number of retries for a given http request can also be specified in a route rule. The maximum number of attempts, or as many as possible within the default or overridden timeout period, can be set as follows:

destination: "ratings.default.svc.cluster.local"
route:
- tags:
    version: v1
httpReqRetries:
  simpleRetry:
    attempts: 3

Note that request timeouts and retries can also be overridden on a per-request basis.

See the request timeouts task for a demonstration of timeout control.

Injecting faults in the request path

A route rule can specify one or more faults to inject while forwarding http requests to the rule’s corresponding request destination. The faults can be either delays or aborts.

The following example will introduce a 5 second delay in 10% of the requests to the “v1” version of the “reviews” microservice.

destination: reviews.default.svc.cluster.local
route:
- tags:
    version: v1
httpFault:
  delay:
    percent: 10
    fixedDelay: 5s

The other kind of fault, abort, can be used to prematurely terminate a request, for example, to simulate a failure.

The following example will return an HTTP 400 error code for 10% of the requests to the “ratings” service “v1”.

destination: "ratings.default.svc.cluster.local"
route:
- tags:
    version: v1
httpFault:
  abort:
    percent: 10
    httpStatus: 400

Sometimes delays and abort faults are used together. For example, the following rule will delay by 5 seconds all requests from the “reviews” service “v2” to the “ratings” service “v1” and then abort 10 percent of them:

destination: ratings.default.svc.cluster.local
match:
  source: reviews.default.svc.cluster.local
  sourceTags:
    version: v2
route:
- tags:
    version: v1
httpFault:
  delay:
    fixedDelay: 5s
  abort:
    percent: 10
    httpStatus: 400

To see fault injection in action, see the fault injection task.

Rules have precedence

Multiple route rules could be applied to the same destination. The order of evaluation of rules corresponding to a given destination, when there is more than one, can be specified by setting the precedence field of the rule.

destination: reviews.default.svc.cluster.local
precedence: 1

The precedence field is an optional integer value, 0 by default. Rules with higher precedence values are evaluated first. If there is more than one rule with the same precedence value the order of evaluation is undefined.

When is precedence useful? Whenever the routing story for a particular service is purely weight based, it can be specified in a single rule, as shown in the earlier example. When, on the other hand, other criteria (e.g., requests from a specific user) are being used to route traffic, more than one rule will be needed to specify the routing. This is where the rule precedence field must be set to make sure that the rules are evaluated in the right order.

A common pattern for generalized route specification is to provide one or more higher priority rules that qualify rules by source/headers to specific destinations, and then provide a single weight-based rule with no match criteria at the lowest priority to provide the weighted distribution of traffic for all other cases.

For example, the following 2 rules, together, specify that all requests for the “reviews” service that includes a header named “Foo” with the value “bar” will be sent to the “v2” instances. All remaining requests will be sent to “v1”.

destination: reviews.default.svc.cluster.local
precedence: 2
match:
  httpHeaders:
    Foo:
      exact: bar
route:
- tags:
    version: v2
---
destination: reviews.default.svc.cluster.local
precedence: 1
route:
- tags:
    version: v1
  weight: 100

Notice that the header-based rule has the higher precedence (2 vs. 1). If it was lower, these rules wouldn’t work as expected since the weight-based rule, with no specific match criteria, would be evaluated first which would then simply route all traffic to “v1”, even requests that include the matching “Foo” header. Once a rule is found that applies to the incoming request, it will be executed and the rule-evaluation process will terminate. That’s why it’s very important to carefully consider the priorities of each rule when there is more than one.

Destination policies

Destination policies describe various routing related policies associated with a particular service version, such as the load balancing algorithm, the configuration of circuit breakers, health checks, etc. Unlike route rules, destination policies cannot be qualified based on attributes of a request such as the calling service or HTTP request headers.

However, the policies can be restricted to apply to requests that are routed to backends with specific tags. For example, the following load balancing policy will only apply to requests targeting the “v1” version of the “reviews” microservice.

destination: reviews.default.svc.cluster.local
tags:
  version: v1
loadBalancing: RANDOM

Circuit breakers

A simple circuit breaker can be set based on a number of criteria such as connection and request limits.

For example, the following destination policy sets a limit of 100 connections to “reviews” service version “v1” backends.

destination: reviews.default.svc.cluster.local
tags:
  version: v1
circuitBreaker:
  simpleCb:
    maxConnections: 100

The complete set of simple circuit breaker fields can be found here.

Destination policy evaluation

Similar to route rules, destination policies are associated with a particular destination however if they also include tags their activation depends on route rule evaluation results.

The first step in the rule evaluation process evaluates the route rules for a destination, if any are defined, to determine the tags (i.e., specific version) of the destination service that the current request will be routed to. Next, the set of destination policies, if any, are evaluated to determine if they apply.

NOTE: One subtlety of the algorithm to keep in mind is that policies that are defined for specific tagged destinations will only be applied if the corresponding tagged instances are explicitly routed to. For example, consider the following rule, as the one and only rule defined for the “reviews” service.

destination: reviews.default.svc.cluster.local
tags:
  version: v1
circuitBreaker:
  simpleCb:
    maxConnections: 100

Since there is no specific route rule defined for the “reviews” service, default round-robin routing behavior will apply, which will presumably call “v1” instances on occasion, maybe even always if “v1” is the only running version. Nevertheless, the above policy will never be invoked since the default routing is done at a lower level. The rule evaluation engine will be unaware of the final destination and therefore unable to match the destination policy to the request.

You can fix the above example in one of two ways. You can either remove the tags: from the rule, if “v1” is the only instance anyway, or, better yet, define proper route rules for the service. For example, you can add a simple route rule for “reviews:v1”.

destination: reviews.default.svc.cluster.local
route:
- tags:
    version: v1

Although the default Istio behavior conveniently sends traffic from all versions of a source service to all versions of a destination service without any rules being set, as soon as version discrimination is desired rules are going to be needed.

Therefore, setting a default rule for every service, right from the start, is generally considered a best practice in Istio.