|
| 1 | +--- |
| 2 | +bodyclass: docs |
| 3 | +headline: Request Routing |
| 4 | +layout: docs |
| 5 | +sidenav: doc-side-concepts-nav.html |
| 6 | +title: Request Routing |
| 7 | +type: markdown |
| 8 | +--- |
| 9 | + |
| 10 | +{% capture overview %} |
| 11 | +This page introduces the idea of application layer routing rules, that can |
| 12 | +be used to manipulate how API calls are routed to different versions of a service. |
| 13 | +{% endcapture %} |
| 14 | + |
| 15 | +{% capture body %} |
| 16 | +## Overview |
| 17 | + |
| 18 | +Istio provides a simple Domain-specific language (DSL) to |
| 19 | +control how API calls and layer-4 traffic flow across various |
| 20 | +microservices in the application deployment. The DSL allows the operator to |
| 21 | +configure service-level properties such as circuit breakers, timeouts, |
| 22 | +retries, as well as set up common continuous deployment tasks such as |
| 23 | +canary rollouts, A/B testing, staged rollouts with %-based traffic splits, |
| 24 | +etc. See routing rules reference for detailed information. _link TBD_ |
| 25 | + |
| 26 | +For example, a simple rule to send 100% of incoming traffic for a "reviews" |
| 27 | +microservice to version "v1" can be described using the Rules DSL as |
| 28 | +follows: |
| 29 | + |
| 30 | +```yaml |
| 31 | +destination: reviews.default.svc.cluster.local |
| 32 | +route: |
| 33 | +- tags: |
| 34 | + version: v1 |
| 35 | + weight: 100 |
| 36 | +``` |
| 37 | +
|
| 38 | +The destination is the name of the service to which the traffic is being |
| 39 | +routed. In a Kubernetes deployment of Istio, the route *tag* "version: v1" |
| 40 | +corresponds to a Kubernetes *label* "version: v1". The rule ensures that |
| 41 | +only Kubernetes pods containing the label "version: v1" will receive |
| 42 | +traffic. Rules can be configured using the |
| 43 | +[istioctl CLI](../reference/istioctl.md). See |
| 44 | +[configuring request routing](../tasks/request-routing.html) section for |
| 45 | +more information and examples. |
| 46 | +
|
| 47 | +There are two types of rules in Istio, **Routes** and **Destination |
| 48 | +Policies** (these are not the same as Mixer policies). Both types of rules |
| 49 | +control how requests are routed to a destination service. |
| 50 | +
|
| 51 | +## Routes |
| 52 | +
|
| 53 | +Routes control how requests are routed to different versions of a |
| 54 | +service. Requests can be routed based on the source and destination, HTTP |
| 55 | +header fields, and weights associated with individal service versions. The |
| 56 | +following important aspects must be keep in mind while writing route rules: |
| 57 | +
|
| 58 | +### Qualify rules by destination |
| 59 | +
|
| 60 | +Every rule corresponds to some destination microservice identified by a |
| 61 | +*destination* field in the rule. For example, all rules that apply to calls |
| 62 | +to the "reviews" microservice will include the following field. |
| 63 | +
|
| 64 | +```yaml |
| 65 | +destination: reviews.default.svc.cluster.local |
| 66 | +``` |
| 67 | +
|
| 68 | +The *destination* value SHOULD be a fully qualified domain name (FQDN). It |
| 69 | +is used by Istio-Manager for matching rules to services. For example, |
| 70 | +in Kubernetes, a fully qualified domain name for a service can be |
| 71 | +constructed using the following format: *serviceName.namespace.dnsSuffix*. |
| 72 | +
|
| 73 | +### Qualify rules by source/headers |
| 74 | +
|
| 75 | +Rules can optionally be qualified to only apply to requests that match some |
| 76 | +specific criteria such as the following: |
| 77 | +
|
| 78 | +_1. Restrict to a specific caller_. For example, the following rule only |
| 79 | +apply to calls from the "reviews" microservice. |
| 80 | +
|
| 81 | +```yaml |
| 82 | +destination: ratings.default.svc.cluster.local |
| 83 | +match: |
| 84 | + source: reviews.default.svc.cluster.local |
| 85 | +``` |
| 86 | +
|
| 87 | +The *source* value, just like *destination*, MUST be a FQDN of a service. |
| 88 | +
|
| 89 | +_2. Restrict to specific versions of the caller_. For example, the following |
| 90 | +rule refines the previous example to only apply to calls from version "v2" |
| 91 | +of the "reviews" microservice. |
| 92 | +
|
| 93 | +```yaml |
| 94 | +destination: ratings.default.svc.cluster.local |
| 95 | +match: |
| 96 | + source: reviews.default.svc.cluster.local |
| 97 | + sourceTags: |
| 98 | + version: v2 |
| 99 | +``` |
| 100 | +
|
| 101 | +_3. Select rule based on HTTP headers_. For example, the following rule will |
| 102 | +only apply to an incoming request if it includes a "Cookie" header that |
| 103 | +contains the substring "user=jason". |
| 104 | +
|
| 105 | +```yaml |
| 106 | +destination: reviews.default.svc.cluster.local |
| 107 | +match: |
| 108 | + httpHeaders: |
| 109 | + Cookie: |
| 110 | + regex: "^(.*?;)?(user=jason)(;.*)?$" |
| 111 | +``` |
| 112 | +
|
| 113 | +If more than one property-value pair is provided, then all of the |
| 114 | +corresponding headers must match for the rule to apply. |
| 115 | +
|
| 116 | +Multiple criteria can be set simultaneously. In such a case, AND semantics |
| 117 | +apply. For example, the following rule only applies if the source of the |
| 118 | +request is "reviews:v2" AND the "Cookie" header containing "user=jason" is |
| 119 | +present. |
| 120 | +
|
| 121 | +```yaml |
| 122 | +destination: ratings.default.svc.cluster.local |
| 123 | +match: |
| 124 | + source: reviews.default.svc.cluster.local |
| 125 | + sourceTags: |
| 126 | + version: v2 |
| 127 | + httpHeaders: |
| 128 | + Cookie: |
| 129 | + regex: "^(.*?;)?(user=jason)(;.*)?$" |
| 130 | +``` |
| 131 | +
|
| 132 | +### Split traffic between service versions |
| 133 | +
|
| 134 | +Each *route rule* identifies one or more weighted backends to call when the rule is activated. |
| 135 | +Each backend corresponds to a specific version of the destination service, |
| 136 | +where versions can be expressed using _tags_. |
| 137 | +
|
| 138 | +If there are multiple registered instances with the specified tag(s), |
| 139 | +they will be routed to based on the [load balancing policy](#loadBalancing) configured for the service, |
| 140 | +or round-robin by default. |
| 141 | +
|
| 142 | +For example, the following rule will route 25% of traffic for the "reviews" service to instances with |
| 143 | +the "v2" tag and the remaining traffic (i.e., 75%) to "v1". |
| 144 | +
|
| 145 | +```yaml |
| 146 | +destination: reviews.default.svc.cluster.local |
| 147 | +route: |
| 148 | +- tags: |
| 149 | + version: v2 |
| 150 | + weight: 25 |
| 151 | +- tags: |
| 152 | + version: v1 |
| 153 | + weight: 75 |
| 154 | +``` |
| 155 | +
|
| 156 | +### Rules have precedence |
| 157 | +
|
| 158 | +Multiple route rules could be applied to the same destination. The order of |
| 159 | +evaluation of rules corresponding to a given destination, when there is |
| 160 | +more than one, can be specified by setting the *precedence* field of the |
| 161 | +rule. |
| 162 | +
|
| 163 | +```yaml |
| 164 | +destination: reviews.default.svc.cluster.local |
| 165 | +precedence: 1 |
| 166 | +``` |
| 167 | +
|
| 168 | +The precedence field is an optional integer value, 0 by default. Rules |
| 169 | +with higher precedence values are evaluated first. _If there is more than |
| 170 | +one rule with the same precedence value the order of evaluation is |
| 171 | +undefined._ |
| 172 | +
|
| 173 | +**When is precedence useful?** Whenever the routing story for a particular |
| 174 | +microservice is purely weight based, it can be specified in a single rule, |
| 175 | +as shown in the earlier example. When, on the other hand, other crieria |
| 176 | +(e.g., requests from a specific user) are being used to route traffic, more |
| 177 | +than one rule will be needed to specify the routing. This is where the |
| 178 | +rule *precedence* field must be set to make sure that the rules are |
| 179 | +evaluated in the right order. |
| 180 | +
|
| 181 | +A common pattern for generalized route specification is to provide one or |
| 182 | +more higher priority rules that qualify rules by source/headers to specific |
| 183 | +destinations, and then provide a single weight-based rule with no match |
| 184 | +criteria at the lowest priority to provide the weighted distribution of |
| 185 | +traffic for all other cases. |
| 186 | +
|
| 187 | +For example, the following 2 rules, together, specify that all requests for |
| 188 | +the "reviews" service that includes a header named "Foo" with the value |
| 189 | +"bar" will be sent to the "v2" instances. All remaining requests will be |
| 190 | +sent to "v1". |
| 191 | +
|
| 192 | +```yaml |
| 193 | +destination: reviews.default.svc.cluster.local |
| 194 | +precedence: 2 |
| 195 | +match: |
| 196 | + httpHeaders: |
| 197 | + Foo: |
| 198 | + exact: bar |
| 199 | +route: |
| 200 | +- tags: |
| 201 | + version: v2 |
| 202 | +--- |
| 203 | +destination: reviews.default.svc.cluster.local |
| 204 | +precedence: 1 |
| 205 | +route: |
| 206 | +- tags: |
| 207 | + version: v1 |
| 208 | + weight: 100 |
| 209 | +``` |
| 210 | +
|
| 211 | +Notice that the header-based rule has the higher precedence (2 vs. 1). If |
| 212 | +it was lower, these rules wouldn't work as expected since the weight-based |
| 213 | +rule, with no specific match criteria, would be evaluated first which would |
| 214 | +then simply route all traffic to "v1", even requests that include the |
| 215 | +matching "Foo" header. Once a rule is found that applies to the incoming |
| 216 | +request, it will be executed and the rule-evaluation process will |
| 217 | +terminate. That's why it's very important to carefully consider the |
| 218 | +priorities of each rule when there is more than one. |
| 219 | +
|
| 220 | +## Destination Policies |
| 221 | +
|
| 222 | +Destination policies describe various routing related policies associated |
| 223 | +with a particular service version, such as the load balancing algorithm, |
| 224 | +the configuration of circuit breakers, health checks, etc. Unlike route |
| 225 | +rules, destination policies cannot be qualified based on attributes of a |
| 226 | +request such as the calling service or HTTP request headers. |
| 227 | +
|
| 228 | +However, the policies can be restricted to apply to requests that are |
| 229 | +routed to backends with specific tags. For example, the following load |
| 230 | +balancing policy will only apply to requests targetting the "v1" version of |
| 231 | +the "reviews" microserivice. |
| 232 | +
|
| 233 | +```yaml |
| 234 | +destination: reviews.default.svc.cluster.local |
| 235 | +tags: |
| 236 | + version: v1 |
| 237 | +loadBalancing: RANDOM |
| 238 | +``` |
| 239 | +
|
| 240 | +### Destination Policy evaluation |
| 241 | +
|
| 242 | +Similar to route rules, destination policies are associated with a |
| 243 | +particular *destination* however if they also include *tags* their |
| 244 | +activation depends on route rule evaluation results. |
| 245 | +
|
| 246 | +The first step in the rule evaluation process evaluates the route rules for |
| 247 | +a *destination*, if any are defined, to determine the tags (i.e., specific |
| 248 | +version) of the destination service that the current request will be routed |
| 249 | +to. Next, the set of destination policies, if any, are evaluated to |
| 250 | +determine if they apply. |
| 251 | +
|
| 252 | +**NOTE:** One subtlety of the algorithm to keep in mind is that policies |
| 253 | +that are defined for specific tagged destinations will only be applied if |
| 254 | +the corresponding tagged instances are explicity routed to. For example, |
| 255 | +consider the following rule, as the one and only rule defined for the |
| 256 | +"reviews" microservice. |
| 257 | +
|
| 258 | +```yaml |
| 259 | +destination: reviews.default.svc.cluster.local |
| 260 | +tags: |
| 261 | + version: v1 |
| 262 | +circuitBreaker: |
| 263 | + simpleCb: |
| 264 | + maxConnections: 100 |
| 265 | +``` |
| 266 | +
|
| 267 | +Since there is no specific route rule defined for the "reviews" |
| 268 | +microservice, default round-robin routing behavior will apply, which will |
| 269 | +persumably call "v1" instances on occasion, maybe even always if "v1" is |
| 270 | +the only running version. Nevertheless, the above policy will never be |
| 271 | +invoked since the default routing is done at a lower level. The rule |
| 272 | +evaluation engine will be unaware of the final destination and therefore |
| 273 | +unable to match the destination policy to the request. |
| 274 | +
|
| 275 | +You can fix the above example in one of two ways. You can either remove the |
| 276 | +`tags:` from the rule, if "v1" is the only instance anyway, or, better yet, |
| 277 | +define proper route rules for the service. For example, you can add a |
| 278 | +simple route rule for "reviews:v1". |
| 279 | + |
| 280 | +```yaml |
| 281 | +destination: reviews.default.svc.cluster.local |
| 282 | +route: |
| 283 | +- tags: |
| 284 | + version: v1 |
| 285 | +``` |
| 286 | + |
| 287 | +Although the default Istio behavior conveniently sends traffic from all |
| 288 | +versions of a source service to all versions of a destination service |
| 289 | +without any rules being set, as soon as version discrimination is desired |
| 290 | +rules are going to be needed. |
| 291 | + |
| 292 | +Therefore, setting a default rule for every microservice, right from the |
| 293 | +start, is generally considered a best practice in Istio. |
| 294 | + |
| 295 | +{% endcapture %} |
| 296 | + |
| 297 | +{% include templates/concept.md %} |
0 commit comments