Skip to content

Commit

Permalink
feat: Adds support for Istio traffic mirroring (#2074)
Browse files Browse the repository at this point in the history
* feat: Add support for istio traffic mirroring steps

Signed-off-by: zachaller <[email protected]>

* bump e2e timeout

Signed-off-by: zachaller <[email protected]>

* Remove unintended change

Signed-off-by: zachaller <[email protected]>

* Cleaner events

Signed-off-by: zachaller <[email protected]>

* Add docs for mirror and fix up header routing

Signed-off-by: zachaller <[email protected]>

* small doc changes

Signed-off-by: zachaller <[email protected]>

* Add example

Signed-off-by: zachaller <[email protected]>

* Fix types and change example

Signed-off-by: zachaller <[email protected]>

* Remove unused type

Signed-off-by: zachaller <[email protected]>

* Docs change

Signed-off-by: zachaller <[email protected]>

* Fix PR comments

Signed-off-by: zachaller <[email protected]>

* Check for >=

Signed-off-by: zachaller <[email protected]>

* Remove unused function

Signed-off-by: zachaller <[email protected]>

* codegen

Signed-off-by: zachaller <[email protected]>

* Add better error logging

Signed-off-by: zachaller <[email protected]>

* a few more error msgs

Signed-off-by: zachaller <[email protected]>

* fix comments

Signed-off-by: zachaller <[email protected]>

* typo

Signed-off-by: zachaller <[email protected]>

* fix logic error

Signed-off-by: zachaller <[email protected]>

* redo header logic

Signed-off-by: zachaller <[email protected]>

* cleanup

Signed-off-by: zachaller <[email protected]>

* Fix issue with keeping route weight updated when no routes
are defined in spec.strategy.canary.trafficRouting.istio.virtualService.routes
requiring only a single route

Signed-off-by: zachaller <[email protected]>

* cleanup routes when promiting with last step being a pause

Signed-off-by: zachaller <[email protected]>

* fix bug with promote and last step is a pause

Signed-off-by: zachaller <[email protected]>

* Fix tests

Signed-off-by: zachaller <[email protected]>

* fix typo

Signed-off-by: zachaller <[email protected]>
  • Loading branch information
zachaller authored Jun 29, 2022
1 parent e3c33d8 commit 40c356c
Show file tree
Hide file tree
Showing 47 changed files with 4,600 additions and 941 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ DEV_IMAGE=false
E2E_INSTANCE_ID ?= argo-rollouts-e2e
E2E_TEST_OPTIONS ?=
E2E_PARALLEL ?= 4
E2E_WAIT_TIMEOUT ?= 90
E2E_WAIT_TIMEOUT ?= 120

override LDFLAGS += \
-X ${PACKAGE}/utils/version.version=${VERSION} \
Expand Down
58 changes: 49 additions & 9 deletions docs/features/specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,19 +268,52 @@ spec:
# Setting header based route will send all 100 traffic to the canary for the requests
# O with a specified header, in this case request header "version":"2"
# (supported only with trafficRouting, for Istio only at the moment)
- setHeaderRouting:
- setHeaderRoute:
# Name of the route that will be created by argo rollouts this must also be configured
# in spec.strategy.canary.trafficRouting.managedRoutes
name: "header-route-1"
# The matching rules for the header route, if this is missing it acts as a removal of the route.
match:
# headerName The name of the header to apply the match rules to.
- headerName: "version"
# headerValue must contain exactly one field of exact, regex, or prefix. Not all traffic routers support
# all types
headerValue:
# Exact will only match if the header value is exactly the same
exact: "2"

# Sets header based route with specified header values using regex as a value
# Could be used 'headerValue' or 'headerRegex' one of that values
- setHeaderRouting:
match:
- headerName: "version"
headerValue:
# Will match the rule if the regular expression matches
regex: "2.0.(.*)"
# prefix will be a prefix match of the header value
prefix: "2.0"

# Sets up a mirror/shadow based route with the specified match rules
# The traffic will be mirrored at the configured percentage to the canary service
# during the rollout
# (supported only with trafficRouting, for Istio only at the moment)
- setMirrorRoute:
# Name of the route that will be created by argo rollouts this must also be configured
# in spec.strategy.canary.trafficRouting.managedRoutes
name: "header-route-1"
# The percentage of the matched traffic to mirror to the canary
percentage: 100
# The matching rules for the header route, if this is missing it acts as a removal of the route.
# All conditions inside a single match block have AND semantics, while the list of match blocks have OR semantics.
# Each type within a match (method, path, headers) must have one and only one match type (exact, regex, prefix)
# Not all match types (exact, regex, prefix) will be supported by all traffic routers.
match:
- method: # What HTTP method to match
exact: "GET"
regex: "P.*"
prefix: "POST"
path: # What HTTP url paths to match.
exact: "/test"
regex: ""/test/.*"
prefix: ""/"
headers:
agent-1b: # What HTTP header name to use in the match.
exact: "firefox"
regex: "firefox2(.*)"
prefix: "firefox"

# an inline analysis step
- analysis:
Expand Down Expand Up @@ -311,7 +344,14 @@ spec:
# will achieve traffic split via a weighted replica counts between
# the canary and stable ReplicaSet.
trafficRouting:

# This is a list of routes that Argo Rollouts has the rights to manage it is currently only required for
# setMirrorRoute and setHeaderRoute. The order of managedRoutes array also sets the precedence of the route
# in the traffic router. Argo Rollouts will place these routes in the order specified above any routes already
# defined in the used traffic router if something exists. The names here must match the names from the
# setHeaderRoute and setMirrorRoute steps.
managedRoutes:
- name: set-header
- name: mirror-route
# Istio traffic routing configuration
istio:
# Either virtualService or virtualServices can be configured.
Expand Down
107 changes: 100 additions & 7 deletions docs/features/traffic-management/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,53 @@ Since the traffic is controlled independently by the Service Mesh resources, the
[^1]: The Rollout has to assume that the application can handle 100% of traffic if it is fully scaled up. It should outsource to the HPA to detect if the Rollout needs to more replicas if 100% isn't enough.
## Traffic routing with managed routes and route precedence
##### Traffic router support: (Istio)
When traffic routing is enabled, you have the ability to also let argo rollouts add and manage other routes besides just
controlling the traffic weight to the canary. Two such routing rules are header and mirror based routes. When using these
routes we also have to set a route precedence with the upstream traffic router. We do this using the `spec.strategy.canary.trafficRouting.managedRoutes`
field which is an array the order of the items in the array determine the precedence. This set of routes will also be placed
in the order specified on top of any other routes defined manually.

#### WARNING: All routes listed in managed routes will be removed at the end of a rollout or on an abort. Do not put any manually created routes in the list.


Here is an example:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
...
strategy:
canary:
...
trafficRouting:
managedRoutes:
- name: priority-route-1
- name: priority-route-2
- name: priority-route-3
```


## Traffic routing based on a header values for Canary
##### Traffic router support: (Istio)

Argo Rollouts has ability to send all traffic to the canary-service based on a http request header value.
The step for the header based traffic routing is `setHeaderRoute` and has a list of matchers for the header.

Argo Rollouts has ability to send all traffic to the canary-service based on a http request header value. Right now it's implemented for the Istio only.
The step for the header based traffic routing `setHeaderRouting` has a list of matchers for the header.
Should be specified the `headerName` - name of the header and a value.
The value could be one of 3 `exact` - specify the exact header value, `regex` - value in a regex format, `prefix` - the prefix of the value could be provided.
`name` - name of the header route.

To disable header based traffic routing just need to specify empty `setHeaderRouting`.
`match` - header matching rules is an array of `headerName, headerValue` pairs.

`headerName` - name of the header to match.

`headerValue`- contains exactly one of `exact` - specify the exact header value,
`regex` - value in a regex format, `prefix` - the prefix of the value could be provided. Not all traffic routers will support
all match types.

To disable header based traffic routing just need to specify empty `setHeaderRoute` with only the name of the route.

Example:

Expand All @@ -70,12 +109,15 @@ spec:
canaryService: canary-service
stableService: stable-service
trafficRouting:
managedRoutes:
- name: set-header-1
istio:
virtualService:
name: rollouts-demo-vsvc
steps:
- setWeight: 20
- setHeaderRouting: # enable header based traffic routing where
- setHeaderRoute: # enable header based traffic routing where
name: "set-header-1"
match:
- headerName: Custom-Header1 # Custom-Header1=Mozilla
headerValue:
Expand All @@ -87,5 +129,56 @@ spec:
headerValue:
regex: Mozilla(.*)
- pause: {}
- setHeaderRouting: {} # disable header based traffic routing
- setHeaderRoute:
name: "set-header-1" # disable header based traffic routing
```

## Traffic routing mirroring traffic to canary
##### Traffic router support: (Istio)

Argo Rollouts has ability to mirror traffic to the canary-service based on a various matching rules.
The step for the mirror based traffic routing is `setMirrorRoute` and has a list of matchers for the header.

`name` - name of the mirror route.

`percentage` - what percentage of the matched traffic to mirror

`match` - The matching rules for the header route, if this is missing it acts as a removal of the route.
All conditions inside a single match block have AND semantics, while the list of match blocks have OR semantics.
Each type within a match (method, path, headers) must have one and only one match type (exact, regex, prefix)
Not all match types (exact, regex, prefix) will be supported by all traffic routers.

To disable mirror based traffic route you just need to specify a `setMirrorRoute` with only the name of the route.

This example will mirror 35% of HTTP traffic that matches a `GET` requests and with the url prefix of `/`
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
...
strategy:
canary:
canaryService: canary-service
stableService: stable-service
trafficRouting:
managedRoutes:
- name: mirror-route
istio:
virtualService:
name: rollouts-demo-vsvc
steps:
- setCanaryScale:
weight: 25
- setMirrorRoute:
name: mirror-route
percentage: 35
match:
- method:
exact: GET
path:
prefix: /
- pause:
duration: 10m
- setMirrorRoute:
name: "mirror-route" # removes mirror based traffic route
```
117 changes: 117 additions & 0 deletions examples/traffic-routing/istio-mirror.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
## This examples sets up istio mirroring if running locally using docker for destkop you can add
## istio-host-split.com to your /etc/hosts and point it to 127.0.0.1 to view demo.
apiVersion: v1
kind: Service
metadata:
name: istio-host-split-canary
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: istio-host-split

---
apiVersion: v1
kind: Service
metadata:
name: istio-host-split-stable
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: istio-host-split

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: istio-host-split-vsvc
spec:
hosts:
- istio-host-split.com
gateways:
- istio-host-split-gateway
http:
- name: primary
route:
- destination:
host: istio-host-split-stable
weight: 100
- destination:
host: istio-host-split-canary
weight: 0

---
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: istio-host-split
spec:
replicas: 4
strategy:
canary:
canaryService: istio-host-split-canary
stableService: istio-host-split-stable
trafficRouting:
managedRoutes:
- name: mirror-route
istio:
virtualService:
name: istio-host-split-vsvc
routes:
- primary
steps:
- setCanaryScale:
weight: 50
- setMirrorRoute:
name: mirror-route
percentage: 50
match:
- method:
exact: POST
path:
prefix: /color
- pause: {}
selector:
matchLabels:
app: istio-host-split
template:
metadata:
labels:
app: istio-host-split
spec:
containers:
- name: istio-host-split
image: argoproj/rollouts-demo:green
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 16Mi
cpu: 5m

---

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: istio-host-split-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "istio-host-split.com"

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.13.1
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0
github.com/aws/smithy-go v1.10.0
github.com/blang/semver v3.5.1+incompatible
github.com/evanphx/json-patch/v5 v5.6.0
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
Expand Down Expand Up @@ -77,6 +76,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect
github.com/aws/smithy-go v1.10.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
Expand Down
Loading

0 comments on commit 40c356c

Please sign in to comment.