Skip to content

Commit

Permalink
Add AnalysisTemplate & update logic for canary rollout strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
yyhp committed Apr 26, 2024
1 parent 58d72b6 commit 175a67c
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 50 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ jobs:
kubectl apply -f https://raw.githubusercontent.com/opsgy/loki-rule-operator/main/chart/crds/logging.opsgy.com_lokirules.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/manifests/charts/base/crds/crd-all.gen.yaml
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/manifests/crds/rollout-crd.yaml
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/manifests/crds/analysis-template-crd.yaml
- name: Install charts
run: ct install --all
14 changes: 14 additions & 0 deletions charts/generic-service/ci/argo-bluegreen-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Argo Rollout controller BlueGreen test

image:
repository: jwilder/whoami
tag: latest

ingress:
enabled: true
port: 8000

rollout:
controller: ArgoRollout
strategy: BlueGreen
autoPromotion: true
45 changes: 45 additions & 0 deletions charts/generic-service/ci/argo-canary-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Argo Rollout controller Canary test

image:
repository: jwilder/whoami
tag: latest

ingress:
enabled: true
port: 8000

replicas: 2

rollout:
controller: ArgoRollout
strategy: Canary
notifications:
on-rollout-completed:
- "your-slack-channel"
steps:
- setWeight: 20
- analysis:
templates:
- templateName: success-rate
args:
- name: service-name
value: canary-demo
- pause:
duration: 1h
- setWeight: 40
analysisTemplates:
- name: success-rate
args:
- name: service-name
metrics:
- name: success-rate
interval: 5m
count: 10
successCondition: "result[0] >= 0.95"
query: |
sum(irate(
istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
)) /
sum(irate(
istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
))
52 changes: 52 additions & 0 deletions charts/generic-service/templates/analysis-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{{- if eq .Values.rollout.controller "ArgoRollout" }}
{{- range .Values.rollout.analysisTemplates }}
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: {{ include "generic-service.fullname" $ }}-{{ .name }}
spec:
{{- if .args }}
args:
{{- toYaml .args | nindent 4 }}
{{- end }}
{{- if .dryRun }}
dryRun:
{{- toYaml .dryRun | nindent 4 }}
{{- end }}
{{- if .measurementRetention }}
measurementRetention:
{{- toYaml .measurementRetention | nindent 4 }}
{{- end }}
metrics:
{{- range .metrics }}
- name: {{ .name }}
{{- if .consecutiveErrorLimit }}
consecutiveErrorLimit: {{ .consecutiveErrorLimit }}
{{- end }}
{{- if .count }}
count: {{ .count }}
{{- end }}
{{- if .failureCondition }}
failureCondition: {{ .failureCondition }}
{{- end }}
{{- if .failureLimit }}
failureLimit: {{ .failureLimit }}
{{- end }}
{{- if .inconclusiveLimit }}
inconclusiveLimit: {{ .inconclusiveLimit }}
{{- end }}
{{- if .initialDelay }}
initialDelay: {{ .initialDelay }}
{{- end }}
{{- if .interval }}
interval: {{ .interval }}
{{- end }}
provider:
prometheus:
address: {{ .prometheusAddress | default "http://prometheus-prometheus.monitoring:9090" }}
query: |
{{ .query | nindent 12 }}
{{- end }}
{{- end }}
{{- end }}
104 changes: 57 additions & 47 deletions charts/generic-service/templates/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ metadata:
{{- if .Values.annotations }}
{{- .Values.annotations | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.rollout.notifications }}
{{- range $event, $channels := . }}
{{- range $channel := $channels }}
notifications.argoproj.io/subscribe.{{ $event }}.slack: {{ join ";" $channels | quote }}
{{- end }}
{{- end }}
{{- end }}

spec:
{{- if and (not .Values.autoscaling.enabled) (ne .Values.rollout.controller "DaemonSet") }}
Expand All @@ -32,6 +39,13 @@ spec:
selector:
matchLabels: {{- include "generic-service.selector-labels" . | nindent 6 }}

progressDeadlineSeconds: {{ .Values.rollout.progressDeadlineSeconds| int }}
minReadySeconds: {{ .Values.rollout.minReadySeconds | int }}

{{- if and .Values.rollout.progressDeadlineAbort (eq .Values.rollout.controller "ArgoRollout") }}
progressDeadlineAbort: {{ .Values.rollout.progressDeadlineAbort }}
{{- end }}

strategy:
{{- if eq .Values.rollout.strategy "RollingUpdate" }}
{{- if eq .Values.rollout.controller "ArgoRollout" }}
Expand All @@ -51,59 +65,56 @@ spec:
{{- end }}
type: OnDelete
{{- else if eq .Values.rollout.strategy "Canary" }}
{{- if not .Values.ingress.enabled }}
{{ fail "ingress.enabled must be true if rollout.strategy is Canary" }}
{{- end }}
{{- if not .Values.ingress.domains }}
{{ fail "ingress.domains must not be empty if rollout.strategy is Canary" }}
{{- end }}
{{- if eq .Values.rollout.controller "ArgoRollout" }}
canary:
stableService: {{ include "generic-service.fullname" . }}
stableMetadata:
labels:
role: stable
canaryService: {{ include "generic-service.fullname" . }}-preview
canaryMetadata:
labels:
role: preview
analysis: {{- .Values.rollout.analysis | required "rollout.analysis is required if rollout.strategy is Canary" | toYaml | nindent 8 }}
trafficRouting:
{{- if .Values.ingress.istio.enabled }}
istio:
virtualService:
name: {{ include "generic-service.fullname" . }}
{{- else if eq .Values.ingress.class "nginx" }}
nginx:
stableIngress: {{ include "generic-service.fullname" . }}
{{- else }}
{{ fail "Ingress must use Istio or nginx if rollout.strategy is Canary" }}
{{- with .Values.rollout.analysis -}}
analysis: {{- . | toYaml | nindent 8 }}
{{- end }}
{{- if .Values.rollout.useTrafficRouting -}}
{{- if not eq .Values.rollout.strategy "Canary" }}
{{ fail "Traffic routing is only available if rollout.strategy is Canary" }}
{{- end }}
stableService: {{ include "generic-service.fullname" . }}
stableMetadata:
labels:
role: stable
canaryService: {{ include "generic-service.fullname" . }}-preview
canaryMetadata:
labels:
role: preview
trafficRouting:
{{- if .Values.ingress.istio.enabled }}
istio:
virtualService:
name: {{ include "generic-service.fullname" . }}
{{- else if eq .Values.ingress.class "nginx" }}
nginx:
stableIngress: {{ include "generic-service.fullname" . }}
{{- else }}
{{ fail "Ingress must use Istio or nginx if rollout.strategy is Canary" }}
{{- end }}
{{- end }}
{{- with .Values.rollout.steps }}
steps: {{- . | toYaml | nindent 8 }}
{{- end }}
{{- else if not .Values.rollout.flagger }}
{{ fail "rollout.flagger must be true or rollout.controller must be ArgoRollout if rollout.strategy is Canary" }}
{{- end }}
{{- else if eq .Values.rollout.strategy "BlueGreen" }}
{{- if not .Values.ingress.enabled }}
{{ fail "ingress.enabled must be true if rollout.strategy is BlueGreen" }}
{{- end }}
{{- if eq .Values.rollout.controller "ArgoRollout" }}
blueGreen:
activeService: {{ include "generic-service.fullname" . }}
activeMetadata:
labels:
role: stable
previewService: {{ include "generic-service.fullname" . }}-preview
previewMetadata:
labels:
role: preview
autoPromotionEnabled: {{ .Values.rollout.autoPromotion }}
{{- if .Values.rollout.analysis }}
prePromotionAnalysis: {{- .Values.rollout.analysis | toYaml | nindent 8 }}
{{- end }}
{{- else if not .Values.rollout.flagger }}
{{ fail "rollout.flagger must be true or rollout.controller must be ArgoRollout if rollout.strategy is BlueGreen" }}
blueGreen:
activeService: {{ include "generic-service.fullname" . }}
activeMetadata:
labels:
role: stable
previewService: {{ include "generic-service.fullname" . }}-preview
previewMetadata:
labels:
role: preview
autoPromotionEnabled: {{ .Values.rollout.autoPromotion }}
{{- if .Values.rollout.analysis }}
prePromotionAnalysis: {{- .Values.rollout.analysis | toYaml | nindent 8 }}
{{- end }}
{{- end }}
{{ else }}
{{- else }}
{{ fail "Unknown rollout.strategy" }}
{{- end }}

Expand Down Expand Up @@ -463,4 +474,3 @@ spec:
{{- end }}
{{- end }}
{{- end }}

2 changes: 1 addition & 1 deletion charts/generic-service/templates/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ spec:
{{- end }}
{{- end }}

{{- if eq .Values.rollout.controller "ArgoRollout" }}
{{- if and (eq .Values.rollout.controller "ArgoRollout") (or (eq .Values.rollout.strategy "BlueGreen") (eq .Values.rollout.useTrafficRouting true)) }}
---
apiVersion: v1
kind: Service
Expand Down
40 changes: 39 additions & 1 deletion charts/generic-service/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,49 @@
"description": "Use Flagger to control rollouts (rollout.controller must be Deployment or StatefulSet)"
},
"analysis": {
"description": "Flagger or Argo Rollouts analysis for automatic Canary or BlueGreen promotion"
"type": "object",
"description": "Flagger or Argo Rollouts analysis for automatic Canary promotion"
},
"steps": {
"type": "array",
"description": "Argo Rollouts list of steps to perform during a canary rollout"
},
"analysisTemplates": {
"type": "array",
"description": "List of analysis templates to create (only applicable if rollout.controller is ArgoRollout)"
},
"useTrafficRouting": {
"type": "boolean",
"default": false,
"description": "Whether to use Argo Rollouts traffig routing feature"
},
"revisionHistoryLimit": {
"type": ["integer", "null"],
"description": "Number of old ReplicaSets to retain (rollout.controller must be Deployment or ArgoRollout)"
},
"progressDeadlineSeconds": {
"type": ["integer"],
"description": "The maximum time in seconds for a deployment to make progress before it is considered to be failed"
},
"minReadySeconds": {
"type": ["integer"],
"description": "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available"
},
"progressDeadlineAbort": {
"type": ["boolean"],
"description": "Whether to abort the update when ProgressDeadlineSeconds is exceeded (rollout.controller must be ArgoRollout and rollout.strategy Canary)"
},
"notifications": {
"type": "object",
"patternProperties": {
"^(on-analysis-run-error|on-analysis-run-failed|on-analysis-run-running|on-rollout-aborted|on-rollout-completed|on-rollout-paused|on-rollout-step-completed|on-rollout-updated|on-scaling-replica-set)$": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
Expand Down
9 changes: 8 additions & 1 deletion charts/generic-service/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,17 @@ resources:
rollout:
controller: Deployment
strategy: RollingUpdate
useTrafficRouting: false
autoPromotion: true
flagger: false
analysis: null
analysis: {}
steps: []
analysisTemplates: []
revisionHistoryLimit: null
progressDeadlineSeconds: 600
minReadySeconds: 0
progressDeadlineAbort: false
notifications: {}

replicas: 1

Expand Down

0 comments on commit 175a67c

Please sign in to comment.