github.com/projectcontour/contour@v1.28.2/site/content/docs/1.27/config/request-routing.md (about) 1 # Request Routing 2 3 A HTTPProxy object must have at least one route or include defined. 4 In this example, any requests to `multi-path.bar.com/blog` or `multi-path.bar.com/blog/*` will be routed to the Service `s2` using the prefix conditions. Requests to `multi-path.bar.com/feed` will be routed to Service `s2` using exact match condition. 5 All other requests to the host `multi-path.bar.com` will be routed to the Service `s1`. 6 7 ```yaml 8 # httpproxy-multiple-paths.yaml 9 apiVersion: projectcontour.io/v1 10 kind: HTTPProxy 11 metadata: 12 name: multiple-paths 13 namespace: default 14 spec: 15 virtualhost: 16 fqdn: multi-path.bar.com 17 routes: 18 - conditions: 19 - prefix: / # matches everything else 20 services: 21 - name: s1 22 port: 80 23 - conditions: 24 - prefix: /blog # matches `multi-path.bar.com/blog` or `multi-path.bar.com/blog/*` 25 services: 26 - name: s2 27 port: 80 28 - conditions: 29 - exact: /feed # matches `multi-path.bar.com/feed` only 30 services: 31 - name: s2 32 port: 80 33 ``` 34 35 In the following example, we match on headers and query parameters and send to different services, with a default route if those do not match. 36 37 ```yaml 38 # httpproxy-multiple-headers.yaml 39 apiVersion: projectcontour.io/v1 40 kind: HTTPProxy 41 metadata: 42 name: multiple-paths 43 namespace: default 44 spec: 45 virtualhost: 46 fqdn: multi-path.bar.com 47 routes: 48 - conditions: 49 - header: 50 name: x-os 51 contains: ios 52 services: 53 - name: s1 54 port: 80 55 - conditions: 56 - header: 57 name: x-os 58 contains: android 59 services: 60 - name: s2 61 port: 80 62 - conditions: 63 - queryParameter: 64 name: os 65 exact: other 66 ignoreCase: true 67 services: 68 - name: s3 69 port: 80 70 - services: 71 - name: s4 72 port: 80 73 ``` 74 75 ## Conditions 76 77 Each Route entry in a HTTPProxy **may** contain one or more conditions. 78 These conditions are combined with an AND operator on the route passed to Envoy. 79 Conditions can be either a `prefix`, `exact`, `regex`, `header` or a `queryParameter` condition. At most one of `prefix`, `exact` or `regex` can be used in one condition block. 80 81 #### Prefix conditions 82 83 Paths defined are matched using prefix conditions. 84 Up to one prefix condition may be present in any condition block. 85 86 Prefix conditions **must** start with a `/` if they are present. 87 88 #### Exact conditions 89 90 Paths defined are matched using exact conditions. 91 Up to one exact condition may be present in any condition block. Any condition block can 92 either have a regex condition, exact condition or prefix condition, but not multiple together. Exact conditions are 93 only allowed in route match conditions and not in include match conditions. 94 95 Exact conditions **must** start with a `/` if they are present. 96 97 #### Regex conditions 98 99 Paths defined are matched using regex expressions. 100 Up to one regex condition may be present in any condition block. Any condition block can 101 either have a regex condition, exact condition or prefix condition, but not multiple together. Regex conditions are 102 only allowed in route match conditions and not in include match conditions. 103 104 Regex conditions **must** start with a `/` if they are present. 105 106 #### Header conditions 107 108 For `header` conditions there is the following structure: 109 110 1. one required field, `name` 111 2. six operator fields: `present`, `notpresent`, `contains`, `notcontains`, `exact`, and `notexact` 112 3. two optional modifiers: `ignoreCase` and `treatMissingAsEmpty` 113 114 Operators: 115 - `present` is a boolean and checks that the header is present. The value will not be checked. 116 117 - `notpresent` similarly checks that the header is *not* present. 118 119 - `contains` is a string, and checks that the header contains the string. `notcontains` similarly checks that the header does *not* contain the string. 120 121 - `exact` is a string, and checks that the header exactly matches the whole string. `notexact` checks that the header does *not* exactly match the whole string. 122 123 - `regex` is a string representing a regular expression, and checks that the header value matches against the given regular expression. 124 125 Modifiers: 126 - `ignoreCase`: IgnoreCase specifies that string matching should be case insensitive. It has no effect on the `Regex` parameter. 127 - `treatMissingAsEmpty`: specifies if the header match rule specified header does not exist, this header value will be treated as empty. Defaults to false. Unlike the underlying Envoy implementation this is **only** supported for negative matches (e.g. NotContains, NotExact). 128 129 #### Query parameter conditions 130 131 Similar to the `header` conditions, `queryParameter` conditions also require the 132 `name` field to be specified, which represents the name of the query parameter 133 e.g. `search` when the query string looks like `/?search=term` and `term` 134 representing the value. 135 136 There are six operator fields: `exact`, `prefix`, `suffix`, `regex`, `contains` 137 and `present` and a modifier `ignoreCase` which can be used together with all of 138 the operator fields except `regex` and `present`. 139 140 - `exact` is a string, and checks that the query parameter value exactly matches 141 the whole string. 142 143 - `prefix` is a string, and checks that the query parameter value is prefixed by 144 the given value. 145 146 - `suffix` is a string, and checks that the query parameter value is suffixed by 147 the given value. 148 149 - `regex` is a string representing a regular expression, and checks that the 150 query parameter value matches against the given regular expression. 151 152 - `contains` is a string, and checks that the query parameter value contains 153 the given string. 154 155 - `present` is a boolean, and checks that the query parameter is present. The 156 value will not be checked. 157 158 - `ignoreCase` is a boolean, and if set to `true` it will enable case 159 insensitive matching for any of the string operator matching methods. 160 161 ## Request Redirection 162 163 HTTP redirects can be implemented in HTTPProxy using `requestRedirectPolicy` on a route. 164 In the following basic example, requests to `example.com` are redirected to `www.example.com`. 165 We configure a root HTTPProxy for `example.com` that contains redirect configuration. 166 We also configure a root HTTPProxy for `www.example.com` that represents the destination of the redirect. 167 168 ```yaml 169 apiVersion: projectcontour.io/v1 170 kind: HTTPProxy 171 metadata: 172 name: example-com 173 spec: 174 virtualhost: 175 fqdn: example.com 176 routes: 177 - conditions: 178 - prefix: / 179 requestRedirectPolicy: 180 hostname: www.example.com 181 ``` 182 183 ```yaml 184 apiVersion: projectcontour.io/v1 185 kind: HTTPProxy 186 metadata: 187 name: www-example-com 188 spec: 189 virtualhost: 190 fqdn: www.example.com 191 routes: 192 - conditions: 193 - prefix: / 194 services: 195 - name: s1 196 port: 80 197 ``` 198 199 In addition to specifying the hostname to set in the `location` header, the scheme, port, and returned status code of the redirect response can be configured. 200 Configuration of the path or a path prefix replacement to modify the path of the returned `location` can be included as well. 201 See [the API specification][3] for more detail. 202 203 ## Multiple Upstreams 204 205 One of the key HTTPProxy features is the ability to support multiple services for a given path: 206 207 ```yaml 208 # httpproxy-multiple-upstreams.yaml 209 apiVersion: projectcontour.io/v1 210 kind: HTTPProxy 211 metadata: 212 name: multiple-upstreams 213 namespace: default 214 spec: 215 virtualhost: 216 fqdn: multi.bar.com 217 routes: 218 - services: 219 - name: s1 220 port: 80 221 - name: s2 222 port: 80 223 ``` 224 225 In this example, requests for `multi.bar.com/` will be load balanced across two Kubernetes Services, `s1`, and `s2`. 226 This is helpful when you need to split traffic for a given URL across two different versions of an application. 227 228 ### Upstream Weighting 229 230 Building on multiple upstreams is the ability to define relative weights for upstream Services. 231 This is commonly used for canary testing of new versions of an application when you want to send a small fraction of traffic to a specific Service. 232 233 ```yaml 234 # httpproxy-weight-shifting.yaml 235 apiVersion: projectcontour.io/v1 236 kind: HTTPProxy 237 metadata: 238 name: weight-shifting 239 namespace: default 240 spec: 241 virtualhost: 242 fqdn: weights.bar.com 243 routes: 244 - services: 245 - name: s1 246 port: 80 247 weight: 10 248 - name: s2 249 port: 80 250 weight: 90 251 ``` 252 253 In this example, we are sending 10% of the traffic to Service `s1`, while Service `s2` receives the remaining 90% of traffic. 254 255 HTTPProxy weighting follows some specific rules: 256 257 - If no weights are specified for a given route, it's assumed even distribution across the Services. 258 - Weights are relative and do not need to add up to 100. If all weights for a route are specified, then the "total" weight is the sum of those specified. As an example, if weights are 20, 30, 20 for three upstreams, the total weight would be 70. In this example, a weight of 30 would receive approximately 42.9% of traffic (30/70 = .4285). 259 - If some weights are specified but others are not, then it's assumed that upstreams without weights have an implicit weight of zero, and thus will not receive traffic. 260 261 ### Traffic mirroring 262 263 Per route, a service can be nominated as a mirror. 264 The mirror service will receive a copy of the read traffic sent to any non mirror service. 265 The mirror traffic is considered _read only_, any response by the mirror will be discarded. 266 267 This service can be useful for recording traffic for later replay or for smoke testing new deployments. 268 269 `weight` can be optionally set (in the space of integers 1-100) to mirror the corresponding percent of traffic (ie. `weight: 5` mirrors 5% of traffic). Omitting the `weight` field results in 100% traffic mirroring. There is unexpected behavior if `weight` is explicitly set to 0, 100% traffic will be mirrored. This occurs because we cannot distinguish undefined variables from explicitly setting them to default values, and omission of a `weight` must mirror full traffic. 270 ```yaml 271 apiVersion: projectcontour.io/v1 272 kind: HTTPProxy 273 metadata: 274 name: traffic-mirror 275 namespace: default 276 spec: 277 virtualhost: 278 fqdn: www.example.com 279 routes: 280 - conditions: 281 - prefix: / 282 services: 283 - name: www 284 port: 80 285 - name: www-mirror 286 port: 80 287 mirror: true 288 ``` 289 290 ## Response Timeouts 291 292 Each Route can be configured to have a timeout policy and a retry policy as shown: 293 294 ```yaml 295 # httpproxy-response-timeout.yaml 296 apiVersion: projectcontour.io/v1 297 kind: HTTPProxy 298 metadata: 299 name: response-timeout 300 namespace: default 301 spec: 302 virtualhost: 303 fqdn: timeout.bar.com 304 routes: 305 - timeoutPolicy: 306 response: 1s 307 idle: 10s 308 idleConnection: 60s 309 retryPolicy: 310 count: 3 311 perTryTimeout: 150ms 312 services: 313 - name: s1 314 port: 80 315 ``` 316 317 In this example, requests to `timeout.bar.com/` will have a response timeout policy of 1s. 318 This refers to the time that spans between the point at which complete client request has been processed by the proxy, and when the response from the server has been completely processed. 319 320 - `timeoutPolicy.response` Timeout for receiving a response from the server after processing a request from client. 321 If not supplied, Envoy's default value of 15s applies. 322 More information can be found in [Envoy's documentation][4]. 323 - `timeoutPolicy.idle` Timeout for how long the proxy should wait while there is no activity during single request/response (for HTTP/1.1) or stream (for HTTP/2). 324 Timeout will not trigger while HTTP/1.1 connection is idle between two consecutive requests. 325 If not specified, there is no per-route idle timeout, though a connection manager-wide stream idle timeout default of 5m still applies. 326 More information can be found in [Envoy's documentation][6]. 327 - `timeoutPolicy.idleConnection` Timeout for how long connection from the proxy to the upstream service is kept when there are no active requests. 328 If not supplied, Envoy’s default value of 1h applies. 329 More information can be found in [Envoy's documentation][8]. 330 331 TimeoutPolicy durations are expressed in the Go [Duration format][5]. 332 Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". 333 The string "infinity" is also a valid input and specifies no timeout. 334 A value of "0s" will be treated as if the field were not set, i.e. by using Envoy's default behavior. 335 Example input values: "300ms", "5s", "1m". 336 337 - `retryPolicy`: A retry will be attempted if the server returns an error code in the 5xx range, or if the server takes more than `retryPolicy.perTryTimeout` to process a request. 338 339 - `retryPolicy.count` specifies the maximum number of retries allowed. This parameter is optional and defaults to 1. Set to -1 to disable. If set to 0, the Envoy default of 1 is used. 340 341 - `retryPolicy.perTryTimeout` specifies the timeout per retry. If this field is greater than the request timeout, it is ignored. This parameter is optional. 342 If left unspecified, `timeoutPolicy.request` will be used. 343 344 ## Load Balancing Strategy 345 346 Each route can have a load balancing strategy applied to determine which of its Endpoints is selected for the request. 347 The following list are the options available to choose from: 348 349 - `RoundRobin`: Each healthy upstream Endpoint is selected in round-robin order (Default strategy if none selected). 350 - `WeightedLeastRequest`: The least request load balancer uses different algorithms depending on whether hosts have the same or different weights in an attempt to route traffic based upon the number of active requests or the load at the time of selection. 351 - `Random`: The random strategy selects a random healthy Endpoints. 352 - `RequestHash`: The request hashing strategy allows for load balancing based on request attributes. An upstream Endpoint is selected based on the hash of an element of a request. For example, requests that contain a consistent value in an HTTP request header will be routed to the same upstream Endpoint. Currently, only hashing of HTTP request headers, query parameters and the source IP of a request is supported. 353 - `Cookie`: The cookie load balancing strategy is similar to the request hash strategy and is a convenience feature to implement session affinity, as described below. 354 355 More information on the load balancing strategy can be found in [Envoy's documentation][7]. 356 357 The following example defines the strategy for the route `/` as `WeightedLeastRequest`. 358 359 ```yaml 360 # httpproxy-lb-strategy.yaml 361 apiVersion: projectcontour.io/v1 362 kind: HTTPProxy 363 metadata: 364 name: lb-strategy 365 namespace: default 366 spec: 367 virtualhost: 368 fqdn: strategy.bar.com 369 routes: 370 - conditions: 371 - prefix: / 372 services: 373 - name: s1-strategy 374 port: 80 375 - name: s2-strategy 376 port: 80 377 loadBalancerPolicy: 378 strategy: WeightedLeastRequest 379 ``` 380 381 The below example demonstrates how request hash load balancing policies can be configured: 382 383 Request hash headers 384 ```yaml 385 # httpproxy-lb-request-hash.yaml 386 apiVersion: projectcontour.io/v1 387 kind: HTTPProxy 388 metadata: 389 name: lb-request-hash 390 namespace: default 391 spec: 392 virtualhost: 393 fqdn: request-hash.bar.com 394 routes: 395 - conditions: 396 - prefix: / 397 services: 398 - name: httpbin 399 port: 8080 400 loadBalancerPolicy: 401 strategy: RequestHash 402 requestHashPolicies: 403 - headerHashOptions: 404 headerName: X-Some-Header 405 terminal: true 406 - headerHashOptions: 407 headerName: User-Agent 408 - hashSourceIP: true 409 ``` 410 In this example, if a client request contains the `X-Some-Header` header, the value of the header will be hashed and used to route to an upstream Endpoint. This could be used to implement a similar workflow to cookie-based session affinity by passing a consistent value for this header. If it is present, because it is set as a `terminal` hash option, Envoy will not continue on to process to `User-Agent` header or source IP to calculate a hash. If `X-Some-Header` is not present, Envoy will use the `User-Agent` header value to make a routing decision along with the source IP of the client making the request. These policies can be used alone or as shown for an advanced routing decision. 411 412 413 Request hash source ip 414 ```yaml 415 # httpproxy-lb-request-hash-ip.yaml 416 apiVersion: projectcontour.io/v1 417 kind: HTTPProxy 418 metadata: 419 name: lb-request-hash 420 namespace: default 421 spec: 422 virtualhost: 423 fqdn: request-hash.bar.com 424 routes: 425 - conditions: 426 - prefix: / 427 services: 428 - name: httpbin 429 port: 8080 430 loadBalancerPolicy: 431 strategy: RequestHash 432 requestHashPolicies: 433 - hashSourceIP: true 434 ``` 435 436 Request hash query parameters 437 ```yaml 438 # httpproxy-lb-request-hash.yaml 439 apiVersion: projectcontour.io/v1 440 kind: HTTPProxy 441 metadata: 442 name: lb-request-hash 443 namespace: default 444 spec: 445 virtualhost: 446 fqdn: request-hash.bar.com 447 routes: 448 - conditions: 449 - prefix: / 450 services: 451 - name: httpbin 452 port: 8080 453 loadBalancerPolicy: 454 strategy: RequestHash 455 requestHashPolicies: 456 - queryParameterHashOptions: 457 prameterName: param1 458 terminal: true 459 - queryParameterHashOptions: 460 parameterName: param2 461 ``` 462 463 ## Session Affinity 464 465 Session affinity, also known as _sticky sessions_, is a load balancing strategy whereby a sequence of requests from a single client are consistently routed to the same application backend. 466 Contour supports session affinity on a per-route basis with `loadBalancerPolicy` `strategy: Cookie`. 467 468 ```yaml 469 # httpproxy-sticky-sessions.yaml 470 apiVersion: projectcontour.io/v1 471 kind: HTTPProxy 472 metadata: 473 name: httpbin 474 namespace: default 475 spec: 476 virtualhost: 477 fqdn: httpbin.davecheney.com 478 routes: 479 - services: 480 - name: httpbin 481 port: 8080 482 loadBalancerPolicy: 483 strategy: Cookie 484 ``` 485 486 Session affinity is based on the premise that the backend servers are robust, do not change ordering, or grow and shrink according to load. 487 None of these properties are guaranteed by a Kubernetes cluster and will be visible to applications that rely heavily on session affinity. 488 489 Any perturbation in the set of pods backing a service risks redistributing backends around the hash ring. 490 491 ## Internal Redirects 492 493 HTTPProxy supports handling 3xx redirects internally, that is capturing a configurable 3xx redirect response, synthesizing a new request, sending it to the upstream specified by the new route match, and returning the redirected response as the response to the original request. 494 495 Internal redirects can be enabled in HTTPProxy by defining an `internalRedirectPolicy` on a route. 496 497 ```yaml 498 apiVersion: projectcontour.io/v1 499 kind: HTTPProxy 500 metadata: 501 name: myservice 502 namespace: prod 503 spec: 504 virtualhost: 505 fqdn: foo.com 506 routes: 507 - conditions: 508 - prefix: /download 509 services: 510 - name: foo 511 port: 8080 512 internalRedirectPolicy: 513 maxInternalRedirects: 5 514 redirectResponseCodes: [ 302 ] 515 allowCrossSchemeRedirect: SafeOnly 516 denyRepeatedRouteRedirect: true 517 ``` 518 519 In this example, a sample redirect flow might look like this: 520 521 1. Client sends a `GET` request for http://foo.com/download. 522 2. Upstream `foo` returns a `302` response with `location: http://foo.com/myfile`. 523 3. Envoy lookups a route for http://foo.com/myfile and sends a new `GET` request to the corresponding upstream with the additional request header `x-envoy-original-url: http://foo.com/download`. 524 4. Envoy proxies the response data for http://foo.com/myfile to the client as the response to the original request. 525 526 See [the API specification][9] and [Envoy's documentation][10] for more detail. 527 528 [3]: /docs/{{< param version >}}/config/api/#projectcontour.io/v1.HTTPRequestRedirectPolicy 529 [4]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-timeout 530 [5]: https://godoc.org/time#ParseDuration 531 [6]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-idle-timeout 532 [7]: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/overview 533 [8]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-field-config-core-v3-httpprotocoloptions-idle-timeout 534 [9] /docs/{{< param version >}}/config/api/#projectcontour.io/v1.HTTPInternalRedirectPolicy 535 [10] https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_connection_management.html#internal-redirects