Rules Configuration

Istio provides a simple configuration model to control how API calls and layer-4 traffic flow across various services in an application deployment. The configuration model allows an 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.

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

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1

This configuration says that traffic sent to the reviews service (specified in the hosts field) should be routed to the v1 subset of the underlying reviews service instances. The route subset specifies the name of a defined subset in a corresponding destination rule configuration:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

A subset specifies one or more labels that identify version-specific instances. For example, in a Kubernetes deployment of Istio, “version: v1” indicates that only pods containing the label “version: v1” will receive traffic.

Rules can be configured using the istioctl CLI, or in a Kubernetes deployment using the kubectl command instead, although only istioctl will perform model validation and is recommended. See the configuring request routing task for examples.

There are four traffic management configuration resources in Istio: VirtualService, DestinationRule, ServiceEntry, and Gateway. A few important aspects of these resources are described below. See networking reference for detailed information.

Virtual Services

A VirtualService defines the rules that control how requests for a service are routed within an Istio service mesh. For example, a virtual service could route requests to different versions of a service or, in fact, to a completely different service than was requested. Requests can be routed based on the request source and destination, HTTP paths and header fields, and weights associated with individual service versions.

Rule destinations

Routing rules correspond to one or more request destination hosts that are specified in a VirtualService configuration. These hosts may or may not be the same as the actual destination workload and may not even correspond to an actual routable service in the mesh. For example, to define routing rules for requests to the reviews service using its internal mesh name reviews or via host bookinfo.com, a VirtualService could have a hosts field something like this:

hosts:
  - reviews
  - bookinfo.com

The hosts field specifies, implicitly or explicitly, one or more fully qualified domain names (FQDN). The short name reviews, above, would implicitly expand to an implementation specific FQDN. For example, in a Kubernetes environment the full name is derived from the cluster and namespace of the VirtualSevice (e.g., reviews.default.svc.cluster.local).

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, a rule can indicate that it only applies to calls from workloads (pods) implementing the reviews service.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
      sourceLabels:
        app: reviews
    ...

The value of sourceLabels depends on the implementation of the service. In Kubernetes, for example, it would probably be the same labels that are used in the pod selector of the corresponding Kubernetes 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.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        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”.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
    ...

If more than one header 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 or OR semantics apply, depending on the nesting. If multiple criteria are nested in a single match clause, then the conditions are ANDed. 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.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
      headers:
        cookie:
          regex: "^(.*?;)?(user=jason)(;.*)?$"
    ...

If instead, the criteria appear in separate match clauses, then only one of the conditions must apply (OR semantics):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
    - headers:
        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 labels. If there are multiple registered instances with the specified label(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” label and the remaining traffic (i.e., 75%) to “v1”.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 75
    - destination:
        host: reviews
        subset: v2
      weight: 25

Timeouts and retries

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

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
    - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    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:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
    - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    retries:
      attempts: 3
      perTryTimeout: 2s

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.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percent: 10
        fixedDelay: 5s
    route:
    - destination:
        host: ratings
        subset: v1

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”.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      abort:
        percent: 10
        httpStatus: 400
    route:
    - destination:
        host: ratings
        subset: v1

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:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - sourceLabels:
        app: reviews
        version: v2
    fault:
      delay:
        fixedDelay: 5s
      abort:
        percent: 10
        httpStatus: 400
    route:
    - destination:
        host: ratings
        subset: v1

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

HTTP route rules have precedence

When there are multiple rules for a given destination, they are evaluated in the order they appear in the VirtualService, i.e., the first rule in the list has highest priority.

Why is priority important? Whenever the routing story for a particular service is purely weight based, it can be specified in a single rule. 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 priority must be carefully considered 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, and then provide a single weight-based rule with no match criteria last to provide the weighted distribution of traffic for all other cases.

For example, the following VirtualService contains 2 rules that, 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”.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - headers:
        Foo:
          exact: bar
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

Notice that the header-based rule has the higher priority. 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 Rules

A DestinationRule configures the set of policies to be applied to a request after VirtualService routing has occurred. They are intended to be authored by service owners, describing the circuit breakers, load balancer settings, TLS settings, etc..

A DestinationRule also defines addressable subsets (i.e., named versions) of the corresponding destination host. These subsets are used in VirtualService route specifications when sending traffic to specific versions of the service.

The following DestinationRule configures policies and subsets for the reviews service:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
  - name: v3
    labels:
      version: v3

Notice that multiple policies (e.g., default and v2-specific) can be specified in a single DestinationRule configuration.

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 DestinationRule sets a limit of 100 connections to reviews service version “v1” backends.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
    trafficPolicy:
      connectionPool:
        tcp:
          maxConnections: 100

See the circuit-breaking task for a demonstration of circuit breaker control.

DestinationRule evaluation

Similar to route rules, policies are associated with a particular host however if they are subset specific, activation depends on route rule evaluation results.

The first step in the rule evaluation process evaluates the route rules in the VirtualService corresponding to the requested host, if there are any defined, to determine the subset (i.e., specific version) of the destination service that the current request will be routed to. Next, the set of policies corresponding to the selected subset, 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 subsets will only be applied if the corresponding subset is explicitly routed to. For example, consider the following configuration, as the one and only rule defined for the reviews service (i.e., there are no route rules in a corresponding VirtualService.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
    trafficPolicy:
      connectionPool:
        tcp:
          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 subset policy to the request.

You can fix the above example in one of two ways. You can either move the traffic policy up a level to make it apply to any version:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
  subsets:
  - name: v1
    labels:
      version: v1

or, better yet, define proper route rules for the service. For example, you can add a simple route rule for “reviews:v1”.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1

Although the default Istio behavior conveniently sends traffic from any source 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.

Service Entries

A ServiceEntry is used to add additional entries into the service registry that Istio maintains internally. It is most commonly used to enable requests to services outside of an Istio service mesh. For example, the following ServiceEntry can be used to allow external calls to services hosted under the *.foo.com domain.

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: foo-ext-svc
spec:
  hosts:
  - *.foo.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS

The destination of a ServiceEntry is specified using the hosts field, which can be either a fully qualified or wildcard domain name. It represents a white listed set of one or more services that services in the mesh are allowed to access.

A ServiceEntry is not limited to external service configuration, it can be of two types: mesh-internal or mesh-external. Mesh-internal entries are like all other internal services but are used to explicitly add services to the mesh. They can be used to add services as part of expanding the service mesh to include unmanaged infrastructure (e.g., VMs added to a Kubernetes-based service mesh). Mesh-external entries represent services external to the mesh. For them, mTLS authentication is disabled and policy enforcement is performed on the client-side, instead of on the usual server-side for internal service requests.

Service entries work well in conjunction with virtual services and destination rules as long as they refer to the services using matching hosts. For example, the following rule can be used in conjunction with the above ServiceEntry rule to set a 10s timeout for calls to the external service at bar.foo.com.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bar-foo-ext-svc
spec:
  hosts:
    - bar.foo.com
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
    timeout: 10s

Rules to redirect and forward traffic, to define retry, timeout and fault injection policies are all supported for external destinations. Weighted (version-based) routing is not possible, however, since there is no notion of multiple versions of an external service.

See the egress task for a more about accessing external services.

Gateways

A Gateway configure a load balancer for HTTP/TCP traffic, most commonly operating at the edge of the mesh to enable ingress traffic for an application.

Unlike Kubernetes Ingress, Istio Gateway only configures the L4-L6 functions (e.g., ports to expose, TLS configuration). Users then can use standard Istio rules to control HTTP requests as well as TCP traffic entering a Gateway by binding a VirtualService to it.

For example, the following simple Gateway configures a load balancer to allow external https traffic for host bookinfo.com into the mesh:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - bookinfo.com
    tls:
      mode: SIMPLE
      serverCertificate: /tmp/tls.crt
      privateKey: /tmp/tls.key

To configure the corresponding routes, a VirtualService must be defined for the same host and bound to the Gateway using the gateways field in the configuration:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - bookinfo.com
  gateways:
  - bookinfo-gateway # <---- bind to gateway
  http:
  - match:
    - uri:
        prefix: /reviews
    route:
    ...

See the ingress task for a complete ingress gateway example.

Although primarily used to manage ingress traffic, a Gateway can also be used to model a purely internal or egress proxy. Irrespective of the location, all gateways can be configured and controlled in the same way. Refer to the gateway reference for details.