Skip to content

Commit 11375b6

Browse files
committed
Support OSM progressive traffic shifting
Signed-off-by: Johnson Shi <[email protected]>
1 parent e2b08eb commit 11375b6

File tree

22 files changed

+720
-2
lines changed

22 files changed

+720
-2
lines changed

.github/workflows/e2e.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
- traefik
2323
- gloo
2424
- skipper
25+
- osm
2526
- kubernetes
2627
steps:
2728
- name: Checkout
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
apiVersion: flagger.app/v1beta1
2+
kind: Canary
3+
metadata:
4+
name: podinfo
5+
namespace: test
6+
spec:
7+
provider: osm
8+
targetRef:
9+
apiVersion: apps/v1
10+
kind: Deployment
11+
name: podinfo
12+
progressDeadlineSeconds: 600
13+
service:
14+
port: 9898
15+
targetPort: 9898
16+
analysis:
17+
interval: 15s
18+
threshold: 10
19+
stepWeights: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
20+
metrics:
21+
- name: request-success-rate
22+
thresholdRange:
23+
min: 99
24+
interval: 1m
25+
- name: request-duration
26+
thresholdRange:
27+
max: 500
28+
interval: 30s
29+
webhooks:
30+
- name: acceptance-test
31+
type: pre-rollout
32+
url: http://flagger-loadtester.test/
33+
timeout: 15s
34+
metadata:
35+
type: bash
36+
cmd: "curl -sd 'test' http://podinfo-canary.test:9898/token | grep token"
37+
- name: load-test
38+
type: rollout
39+
url: http://flagger-loadtester.test/
40+
timeout: 5s
41+
metadata:
42+
cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"

artifacts/examples/osm-canary.yaml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
apiVersion: flagger.app/v1beta1
2+
kind: Canary
3+
metadata:
4+
name: podinfo
5+
namespace: test
6+
spec:
7+
provider: osm
8+
targetRef:
9+
apiVersion: apps/v1
10+
kind: Deployment
11+
name: podinfo
12+
progressDeadlineSeconds: 600
13+
service:
14+
port: 9898
15+
targetPort: 9898
16+
analysis:
17+
interval: 15s
18+
threshold: 10
19+
maxWeight: 50
20+
stepWeight: 5
21+
metrics:
22+
- name: request-success-rate
23+
thresholdRange:
24+
min: 99
25+
interval: 1m
26+
- name: request-duration
27+
thresholdRange:
28+
max: 500
29+
interval: 30s
30+
webhooks:
31+
- name: acceptance-test
32+
type: pre-rollout
33+
url: http://flagger-loadtester.test/
34+
timeout: 15s
35+
metadata:
36+
type: bash
37+
cmd: "curl -sd 'test' http://podinfo-canary.test:9898/token | grep token"
38+
- name: load-test
39+
type: rollout
40+
url: http://flagger-loadtester.test/
41+
timeout: 5s
42+
metadata:
43+
cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"

charts/flagger/Chart.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@ keywords:
2222
- contour
2323
- nginx
2424
- traefik
25+
- osm
26+
- smi
2527
- gitops
2628
- canary

charts/flagger/values.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ podPriorityClassName: ""
1919

2020
metricsServer: "http://prometheus:9090"
2121

22-
# accepted values are kubernetes, istio, linkerd, appmesh, contour, nginx, gloo, skipper, traefik
22+
# accepted values are kubernetes, istio, linkerd, appmesh, contour, nginx, gloo, skipper, traefik, osm
2323
meshProvider: ""
2424

2525
# single namespace restriction

charts/loadtester/Chart.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ keywords:
1919
- appmesh
2020
- linkerd
2121
- gloo
22+
- osm
23+
- smi
2224
- gitops
2325
- load testing

charts/loadtester/templates/deployment.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ spec:
1919
app.kubernetes.io/name: {{ include "loadtester.name" . }}
2020
annotations:
2121
appmesh.k8s.aws/ports: "444"
22+
openservicemesh.io/inbound-port-exclusion-list: "80, 8080"
2223
{{- if .Values.podAnnotations }}
2324
{{ toYaml .Values.podAnnotations | indent 8 }}
2425
{{- end }}

charts/podinfo/templates/tests/jwt.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ metadata:
1212
sidecar.istio.io/inject: "false"
1313
linkerd.io/inject: disabled
1414
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
15+
openservicemesh.io/sidecar-injection: disabled
1516
spec:
1617
containers:
1718
- name: tools

cmd/flagger/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func init() {
106106
flag.BoolVar(&zapReplaceGlobals, "zap-replace-globals", false, "Whether to change the logging level of the global zap logger.")
107107
flag.StringVar(&zapEncoding, "zap-encoding", "json", "Zap logger encoding.")
108108
flag.StringVar(&namespace, "namespace", "", "Namespace that flagger would watch canary object.")
109-
flag.StringVar(&meshProvider, "mesh-provider", "istio", "Service mesh provider, can be istio, linkerd, appmesh, contour, gloo, nginx, skipper or traefik.")
109+
flag.StringVar(&meshProvider, "mesh-provider", "istio", "Service mesh provider, can be istio, linkerd, appmesh, contour, gloo, nginx, skipper, traefik or osm.")
110110
flag.StringVar(&selectorLabels, "selector-labels", "app,name,app.kubernetes.io/name", "List of pod labels that Flagger uses to create pod selectors.")
111111
flag.StringVar(&ingressAnnotationsPrefix, "ingress-annotations-prefix", "nginx.ingress.kubernetes.io", "Annotations prefix for NGINX ingresses.")
112112
flag.StringVar(&ingressClass, "ingress-class", "", "Ingress class used for annotating HTTPProxy objects.")

kustomize/osm/kustomization.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace: osm-system
2+
bases:
3+
- ../base/flagger/
4+
patchesStrategicMerge:
5+
- patch.yaml

kustomize/osm/patch.yaml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: flagger
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: flagger
10+
args:
11+
- -log-level=info
12+
- -include-label-prefix=app.kubernetes.io
13+
- -mesh-provider=osm
14+
- -metrics-server=http://osm-prometheus.osm-system.svc:7070
15+
---
16+
apiVersion: rbac.authorization.k8s.io/v1
17+
kind: ClusterRoleBinding
18+
metadata:
19+
name: flagger
20+
roleRef:
21+
apiGroup: rbac.authorization.k8s.io
22+
kind: ClusterRole
23+
name: flagger
24+
subjects:
25+
- kind: ServiceAccount
26+
name: flagger
27+
namespace: osm-system

kustomize/tester/deployment.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ spec:
1515
annotations:
1616
prometheus.io/scrape: "true"
1717
prometheus.io/port: "8080"
18+
openservicemesh.io/inbound-port-exclusion-list: "80, 8080"
1819
spec:
1920
containers:
2021
- name: loadtester

pkg/apis/flagger/v1beta1/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ const (
1111
KubernetesProvider string = "kubernetes"
1212
SkipperProvider string = "skipper"
1313
TraefikProvider string = "traefik"
14+
OsmProvider string = "osm"
1415
)

pkg/metrics/observers/factory.go

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ func (factory Factory) Observer(provider string) Interface {
8080
return &TraefikObserver{
8181
client: factory.Client,
8282
}
83+
case provider == flaggerv1.OsmProvider:
84+
return &OsmObserver{
85+
client: factory.Client,
86+
}
8387
default:
8488
return &IstioObserver{
8589
client: factory.Client,

pkg/metrics/observers/osm.go

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
Copyright 2021 The Flux authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package observers
18+
19+
import (
20+
"fmt"
21+
"time"
22+
23+
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
24+
"github.com/fluxcd/flagger/pkg/metrics/providers"
25+
)
26+
27+
var osmQueries = map[string]string{
28+
"request-success-rate": `
29+
sum(
30+
rate(
31+
osm_request_total{
32+
destination_namespace="{{ namespace }}",
33+
destination_kind="Deployment",
34+
destination_name="{{ target }}",
35+
response_code!~"5.*"
36+
}[{{ interval }}]
37+
)
38+
)
39+
/
40+
sum(
41+
rate(
42+
osm_request_total{
43+
destination_namespace="{{ namespace }}",
44+
destination_kind="Deployment",
45+
destination_name="{{ target }}"
46+
}[{{ interval }}]
47+
)
48+
)
49+
* 100`,
50+
"request-duration": `
51+
histogram_quantile(
52+
0.99,
53+
sum(
54+
rate(
55+
osm_request_duration_ms_bucket{
56+
destination_namespace="{{ namespace }}",
57+
destination_kind="Deployment",
58+
destination_name="{{ target }}"
59+
}[{{ interval }}]
60+
)
61+
) by (le)
62+
)`,
63+
}
64+
65+
type OsmObserver struct {
66+
client providers.Interface
67+
}
68+
69+
func (ob *OsmObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) {
70+
query, err := RenderQuery(osmQueries["request-success-rate"], model)
71+
if err != nil {
72+
return 0, fmt.Errorf("rendering query failed: %w", err)
73+
}
74+
75+
value, err := ob.client.RunQuery(query)
76+
if err != nil {
77+
return 0, fmt.Errorf("running query failed: %w", err)
78+
}
79+
80+
return value, nil
81+
}
82+
83+
func (ob *OsmObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) {
84+
query, err := RenderQuery(osmQueries["request-duration"], model)
85+
if err != nil {
86+
return 0, fmt.Errorf("rendering query failed: %w", err)
87+
}
88+
89+
value, err := ob.client.RunQuery(query)
90+
if err != nil {
91+
return 0, fmt.Errorf("running query failed: %w", err)
92+
}
93+
94+
ms := time.Duration(int64(value)) * time.Millisecond
95+
return ms, nil
96+
}

0 commit comments

Comments
 (0)