Skip to content

Commit 5f0f8b4

Browse files
authored
feat: TrafficRouting support with AWS App Mesh (argoproj#1401) (argoproj#1606)
Signed-off-by: Kiran Meduri <[email protected]>
1 parent e79296a commit 5f0f8b4

34 files changed

+4516
-636
lines changed

cmd/rollouts-controller/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func newCommand() *cobra.Command {
5959
trafficSplitVersion string
6060
ambassadorVersion string
6161
ingressVersion string
62+
appmeshCRDVersion string
6263
albIngressClasses []string
6364
nginxIngressClasses []string
6465
awsVerifyTargetGroup bool
@@ -89,6 +90,7 @@ func newCommand() *cobra.Command {
8990
defaults.SetIstioAPIVersion(istioVersion)
9091
defaults.SetAmbassadorAPIVersion(ambassadorVersion)
9192
defaults.SetSMIAPIVersion(trafficSplitVersion)
93+
defaults.SetAppMeshCRDVersion(appmeshCRDVersion)
9294

9395
config, err := clientConfig.ClientConfig()
9496
checkError(err)
@@ -228,6 +230,7 @@ func newCommand() *cobra.Command {
228230
command.Flags().StringVar(&ambassadorVersion, "ambassador-api-version", defaults.DefaultAmbassadorVersion, "Set the Ambassador apiVersion that controller should look when manipulating Ambassador Mappings.")
229231
command.Flags().StringVar(&trafficSplitVersion, "traffic-split-api-version", defaults.DefaultSMITrafficSplitVersion, "Set the default TrafficSplit apiVersion that controller uses when creating TrafficSplits.")
230232
command.Flags().StringVar(&ingressVersion, "ingress-api-version", "", "Set the Ingress apiVersion that the controller should use.")
233+
command.Flags().StringVar(&appmeshCRDVersion, "appmesh-crd-version", defaults.DefaultAppMeshCRDVersion, "Set the default AppMesh CRD Version that controller uses when manipulating resources.")
231234
command.Flags().StringArrayVar(&albIngressClasses, "alb-ingress-classes", defaultALBIngressClass, "Defines all the ingress class annotations that the alb ingress controller operates on. Defaults to alb")
232235
command.Flags().StringArrayVar(&nginxIngressClasses, "nginx-ingress-classes", defaultNGINXIngressClass, "Defines all the ingress class annotations that the nginx ingress controller operates on. Defaults to nginx")
233236
command.Flags().BoolVar(&awsVerifyTargetGroup, "alb-verify-weight", false, "Verify ALB target group weights before progressing through steps (requires AWS privileges)")

controller/metrics/rollout_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,17 @@ func TestGetStrategyAndTrafficRouter(t *testing.T) {
271271
expectedStrategy: "canary",
272272
expectedTrafficRouter: "Nginx",
273273
},
274+
{
275+
strategy: v1alpha1.RolloutStrategy{
276+
Canary: &v1alpha1.CanaryStrategy{
277+
TrafficRouting: &v1alpha1.RolloutTrafficRouting{
278+
AppMesh: &v1alpha1.AppMeshTrafficRouting{},
279+
},
280+
},
281+
},
282+
expectedStrategy: "canary",
283+
expectedTrafficRouter: "AppMesh",
284+
},
274285
}
275286

276287
for _, test := range tests {

controller/metrics/rollouts.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ func getStrategyAndTrafficRouter(rollout *v1alpha1.Rollout) (string, string) {
111111
if rollout.Spec.Strategy.Canary.TrafficRouting.SMI != nil {
112112
trafficRouter = "SMI"
113113
}
114+
if rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh != nil {
115+
trafficRouter = "AppMesh"
116+
}
114117
}
115118
}
116119
return strategy, trafficRouter

docs/getting-started/appmesh/index.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Getting Started - App Mesh
2+
3+
This guide covers how Argo Rollouts integrates with service-meshes managed by [AWS App Mesh](https://docs.aws.amazon.com/app-mesh/latest/userguide/what-is-app-mesh.html). This guide builds upon the concepts of the [basic getting started guide](../../getting-started.md).
4+
5+
## Requirements
6+
- Kubernetes cluster with AWS App Mesh Controller for K8s installed
7+
8+
!!! tip
9+
10+
See the [App Mesh Controler Installation instructions](https://docs.aws.amazon.com/app-mesh/latest/userguide/getting-started-kubernetes.html) on how to get started using App Mesh with Kubernetes.
11+
12+
## 1. Deploy the Rollout, Services, App Mesh CRD
13+
14+
When App Mesh is used as the traffic router, the Rollout canary strategy must define the following mandatory fields:
15+
16+
```yaml
17+
apiVersion: argoproj.io/v1alpha1
18+
kind: Rollout
19+
metadata:
20+
name: my-rollout
21+
spec:
22+
strategy:
23+
canary:
24+
# canaryService and stableService are references to Services which the Rollout will modify
25+
# to target the canary ReplicaSet and stable ReplicaSet respectively (required).
26+
canaryService: my-svc-canary
27+
stableService: my-svc-stable
28+
trafficRouting:
29+
appMesh:
30+
# The referenced virtual-service will be used to determine the virtual-router that is
31+
# manipulated to update canary weights.
32+
virtualService:
33+
# name of the virtual-service App Mesh CR
34+
name: my-svc
35+
# Optional set of routes to update. If empty, all routes associated with the virtual-service are updated.
36+
routes:
37+
- http-primary
38+
# virtualNodeGroup is a structure to refer App Mesh virtual-node CR corresponding to Canary and Stable versions
39+
virtualNodeGroup:
40+
# canaryVirtualNodeRef refers to virtual-node corresponding to canary version. Rollouts controller will
41+
# update the podSelector of this virtual-node to latest canary pod-hash generated by controller.
42+
canaryVirtualNodeRef:
43+
name: my-vn-canary
44+
# stableVirtualNodeRef refers to virtual-node corresponding to stable version. Rollouts controller will
45+
# update the podSelector of this virtual-node to latest stable pod-hash generated by controller.
46+
stableVirtualNodeRef:
47+
name: my-vn-stable
48+
steps:
49+
- setWeight: 25
50+
- pause: {}
51+
...
52+
```
53+
54+
In this guide, the two services are: `my-svc-canary` and `my-svc-stable` respectively. There are two
55+
virtual-node CRs corresponding to these services named `my-vn-canary` and `my-vn-stable`
56+
respectively. In addition, there is a virtual-service named `rollout-demo-vsvc` that is provided by a
57+
virtual-router CR named `rollout-demo-vrouter`. This virtual-router need have at least one route with action to forward
58+
traffic to the canary and stable virtual-nodes. Initially weight for canary is set to 0% while for stable it is 100%.
59+
During rollout, controller will modify the weights on route(s) based on the configuraiton defined in
60+
`steps[N].setWeight`.
61+
62+
To summarize, run the following commands to deploy a service:
63+
64+
* Two services (stable and canary)
65+
* One service (for VIP and DNS lookup)
66+
* Two App Mesh virtual-nodes (stable and canary)
67+
* One App Mesh virtual-router with routes to virtual-nodes
68+
* One App Mesh virtual-service corresponding to VIP service
69+
* A rollout
70+
71+
```shell
72+
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/appmesh/canary-service.yaml
73+
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/appmesh/canary-rollout.yaml
74+
```
75+
## 2. Verify service
76+
77+
First make sure that rollout is stable.
78+
79+
```shell
80+
kubectl argo rollouts get rollout my-rollout -n argo-examples -w
81+
```
82+
83+
Then make sure the service is functional.
84+
85+
```shell
86+
kubectl -n argo-examples port-forward svc/my-svc 8181:80
87+
```
88+
89+
## 3. Rollout new version
90+
91+
Now its time to deploy new version. Update the rollout with new image.
92+
93+
```shell
94+
kubectl argo rollouts set image my-rollout demo=argoproj/rollouts-demo:green -n argo-examples
95+
```
96+
97+
Rollout should deploy a new canary revision and update the weights under virtual-router.
98+
99+
```shell
100+
kubectl get -n argo-examples virtualrouter my-vrouter -o json | jq ".spec.routes[0].httpRoute.action.weightedTargets"
101+
[
102+
{
103+
"virtualNodeRef": {
104+
"name": "my-vn-canary"
105+
},
106+
"weight": 25
107+
},
108+
{
109+
"virtualNodeRef": {
110+
"name": "my-vn-stable"
111+
},
112+
"weight": 75
113+
}
114+
]
115+
```
116+
117+
Now manually approve the rollout that is paused indefinitely, and continue watching the routes get updated
118+
119+
```shell
120+
kubectl argo rollouts promote my-rollout -n argo-examples
121+
122+
watch -d 'kubectl get -n argo-examples virtualrouter my-vrouter -o json | jq ".spec.routes[0].httpRoute.action.weightedTargets"'
123+
```

examples/appmesh/canary-rollout.yaml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
apiVersion: argoproj.io/v1alpha1
2+
kind: AnalysisTemplate
3+
metadata:
4+
name: success-rate
5+
namespace: argo-examples
6+
spec:
7+
args:
8+
- name: envoy_cluster_name
9+
metrics:
10+
- name: success-rate
11+
interval: 5m
12+
successCondition: result[0] >= 0.99
13+
failureLimit: 3
14+
provider:
15+
prometheus:
16+
address: http://appmesh-prometheus.appmesh-system:9090
17+
query: |
18+
sum(irate(envoy_cluster_upstream_rq_xx{app="wrk-tester",envoy_cluster_name="{{args.envoy_cluster_name}}",envoy_response_code_class!~"5.*"}[5m])) /
19+
sum(irate(envoy_cluster_upstream_rq_xx{app="wrk-tester",envoy_cluster_name="{{args.envoy_cluster_name}}"}[5m]))
20+
21+
---
22+
apiVersion: argoproj.io/v1alpha1
23+
kind: Rollout
24+
metadata:
25+
name: my-rollout
26+
namespace: argo-examples
27+
spec:
28+
replicas: 4
29+
selector:
30+
matchLabels:
31+
app: my-app
32+
template:
33+
metadata:
34+
labels:
35+
app: my-app
36+
spec:
37+
containers:
38+
- name: demo
39+
image: argoproj/rollouts-demo:blue
40+
imagePullPolicy: Always
41+
ports:
42+
- name: http
43+
containerPort: 8080
44+
strategy:
45+
canary:
46+
canaryService: my-svc-canary
47+
stableService: my-svc-stable
48+
trafficRouting:
49+
appMesh:
50+
virtualService:
51+
name: my-svc
52+
virtualNodeGroup:
53+
canaryVirtualNodeRef:
54+
name: my-vn-canary
55+
stableVirtualNodeRef:
56+
name: my-vn-stable
57+
steps:
58+
- setWeight: 25
59+
- pause: {}
60+
- setWeight: 50
61+
- pause: {duration: 10m}
62+
- setWeight: 75
63+
- pause: {duration: 10m}
64+
# Uncomment below to enable analysis
65+
# analysis:
66+
# templates:
67+
# - templateName: success-rate
68+
# startingStep: 2
69+
# args:
70+
# - name: envoy_cluster_name
71+
# value: cds_egress_argo-examples_my-vn-canary_argo-examples_http_80

0 commit comments

Comments
 (0)