文章目录
前言
在实施金丝雀发布的过程中,我们通过 Argo Rollout 的金丝雀策略将发布过程分成了 3 个阶段,每个阶段金丝雀的流量比例都不同,经过一段时间之后,金丝雀环境变成了新的生产环境。实际上,这也是一种渐进式的交付方式,它通过延长发布时间来保护生产环境,降低了发生生产事故的概率。
不过,这种渐进式的交付方式存在一个明显的缺点:无法自动判断金丝雀环境是否出错?
这可能会导致一种情况,当金丝雀环境在接收生产流量之后,它产生了大量的请求错误,在缺少人工介入的情况下,发布仍然按照计划进行,最终导致生产环境故障。
为了解决这个问题,我们希望
渐进式交付
变得更加智能,一个好的工程实践方式是: 通过指标分析来自动判断金丝雀发布的质量,如果符合预期,就继续金丝雀步骤;如果不符合预期,则进行回滚。 这样,也就能够避免将金丝雀环境的故障带到生产环境中了,这种分析方法也称之为金丝雀分析
。
自动渐进式交付概述
相比较金丝雀发布,自动渐进式交付增加了
Prometheus、Analysis Template 和 AnalysisRun 对象
。其中,Analysis Template 定义用于分析的模板,AnalysisRun 是分析模板的实例化,Prometheus 是用来存储指标的数据库。
自动渐进式交付流程图:
自动渐进式交付开始时,首先会先将金丝雀环境的流量比例设置为
20%
并持续两分钟,然后将金丝雀环境的流量比例设置为40%
并持续两分钟,然后再以此类推到60%、80%
,直到将金丝雀环境提升为生产环境为止。
从第二个阶段开始,自动金丝雀分析开始运行,在持续运行的过程中,如果金丝雀分析失败,那么金丝雀环境将进行自动回滚
。这样就达到了自动渐进式交付的目的。
自动渐进式交付准备
创建生产环境
创建用于模拟生产环境的 Rollout 对象、Service 和 Ingress.
yaml
cat rollout-with-analysis.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: canary-demo
spec:
replicas: 1
selector:
matchLabels:
app: canary-demo
strategy:
canary:
analysis:
templates:
- templateName: success-rate
startingStep: 2
args:
- name: traefik
value: traefik-service
#- name: ingress
# value: canary-demo
canaryService: canary-demo-canary
stableService: canary-demo
trafficRouting:
traefik:
weightedTraefikServiceName: traefik-service
#nginx:
# stableIngress: canary-demo
steps:
- setWeight: 20
- pause:
duration: 2m
- setWeight: 40
- pause:
duration: 2m
- setWeight: 60
- pause:
duration: 2m
- setWeight: 80
- pause:
duration: 2m
template:
metadata:
labels:
app: canary-demo
spec:
containers:
- image: argoproj/rollouts-demo:blue
imagePullPolicy: Always
name: canary-demo
ports:
- containerPort: 8080
name: http
protocol: TCP
resources:
requests:
cpu: 5m
memory: 32Mi
对比金丝雀发布的 Rollout 对象并没有太大差异,只是在 canary 字段下面增加了
analysis
字段,它的作用是指定金丝雀分析的模板,模板内容需单独创建。另外,这里同样使用了argoproj/rollouts-demo:blue
镜像来模拟生产环境。
yaml
#创建生产环境和金丝雀环境所需要用到的 Service
cat canary-demo-service-v2.yaml
apiVersion: v1
kind: Service
metadata:
name: canary-demo
labels:
app: canary-demo
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: canary-demo
---
apiVersion: v1
kind: Service
metadata:
name: canary-demo-canary
labels:
app: canary-demo
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: canary-demo
$ kubectl apply -f canary-demo-service-v2.yaml
#创建ingress
cat canary-demo-ingress-v2.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: canary-demo
labels:
app: canary-demo
spec:
entryPoints:
- web
routes:
- match: Host(`progressive.auto`) && PathPrefix(`/`)
kind: Rule
services:
- name: canary-demo
port: http
创建 AnalysisTemplate
yaml
$ cat analysis-success.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: traefik
metrics:
- name: success-rate
interval: 10s
failureLimit: 3
successCondition: result[0] > 0.90
provider:
prometheus:
address: http://prometheus-kube-prometheus-prometheus.prometheus:9090
query: >+
sum(
rate(traefik_service_requests_total{traefik="{{args.traefik}}",status!~"[4-5].*"}[60s]))
/
sum(rate(traefik_service_requests_total{traefik="{{args.traefik}}"}[60s])
)
介绍一下 AnalysisTemplate 对象字段的含义:
首先
spec.args
字段定义了参数,该参数会在后续的 query 语句中使用,它的值是从 Rollout 对象的canary.analysis.args
字段传递进来的。
spec.metrics
字段定义了自动分析的相关配置。其中,interval 字段为频率,每 10 秒钟执行一次分析。failureLimit 字段代表"连续 3 次失败则金丝雀分析失败",此时要执行回滚动作。successCondition
字段代表判断条件,这里的 result[0] 是一个表达式,代表的含义是当查询语句的返回值大于 0.90 时,说明本次金丝雀分析成功了。
spec.metrics.provider
字段定义了分析数据来源于 Prometheus,还定义了 Prometheus Server 的连接地址
query
字段是金丝雀分析的查询语句。这条查询语句的含义简单理解为:在 60 秒内 HTTP 状态码不为 4xx 和 5xx 的请求占所有请求的比例。换句话说,当 HTTP 请求成功的比例大于 0.90 时,代表一次金丝雀分析成功。
访问生产环境
安装Prometheus
由于金丝雀分析需要用到 Prometheus 来查询指标,可以通过helm安装或者用自己本地环境的Prometheus也可以。
yaml
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm upgrade prometheus prometheus-community/kube-prometheus-stack \
--namespace prometheus --create-namespace --install \
--set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
Release "prometheus" does not exist. Installing it now.
......
STATUS: deployed
--set 对安装参数进行了配置,这是为了让它后续能够顺利获取到 Ingress-Nginx 的监控指标
配置 Ingress-Nginx 和 ServiceMonitor
为了让 Prometheus 能够顺利地获取到 HTTP 请求指标,我们需要打开 Ingress-Nginx Metric 指标端口。
bash
$ kubectl patch deployment ingress-nginx-controller -n ingress-nginx --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/ports/-", "value": {"name": "prometheus","containerPort":10254}}]'
deployment.apps/ingress-nginx-controller patched
然后,为 Ingrss-Nginx Service 添加指标端口。
$ kubectl patch service ingress-nginx-controller -n ingress-nginx --type='json' -p='[{"op": "add", "path": "/spec/ports/-", "value": {"name": "prometheus","port":10254,"targetPort":"prometheus"}}]'
service/ingress-nginx-controller patched
用Traefik的话开启metrics即可
- containerPort: 9101
hostPort: 9101
name: metrics
创建 ServiceMonitor 对象,它可以为 Prometheus 配置指标获取的策略
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nginx-ingress-controller-metrics
namespace: prometheus
labels:
app: nginx-ingress
release: prometheus-operator
spec:
endpoints:
- interval: 10s
port: prometheus
selector:
matchLabels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
namespaceSelector:
matchNames:
- ingress-nginx
如果你使用的是Traefik,可以用以下配置:
cat servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: traefik-ingress-controller
namespace: kubesphere-monitoring-system
labels:
app: traefik
spec:
endpoints:
- interval: 10s
port: metrics
selector:
matchLabels:
app: traefik
namespaceSelector:
matchNames:
- traefik
验证 Ingress-Nginx 指标
测试Prometheus 是否已经成功获取到了 Ingress-Nginx 指标,这将决定自动金丝雀分析是否能成功获取到数据,博主此处用的是
Traefik
自动渐进式交付实战
此次实战过程中,会按照这张流程图分别进行两个实验。
- 自动渐进式交付成功(图中①号链路)
- 自动渐进式交付失败(图中②号链路)
自动渐进式交付成功
验证的话只要更新 Rollout 对象的镜像版本即可。两种方式,第一直接编辑 Rollout 对象并通过 kubectl apply 的方法来更新镜像版本。第二种通过
Argo Rollout kubectl
插件来更新镜像。
sql
kubectl argo rollouts set image canary-demo canary-demo=argoproj/rollouts-demo:green
rollout "canary-demo" image updated
过一会儿看到绿色方块开始出现,流量占比约为 20%,如下图所示:
也可以打开Argo Rollout 控制台观察自动渐进式交付过程。可以看到目前处在 20% 金丝雀流量的下一阶段,也就是暂停 2 分钟的阶段。
2 分钟后,将进入到 40% 金丝雀流量阶段,从这个阶段开始,自动金丝雀分析开始工作,直到最后金丝雀发布完成,金丝雀环境提升为了生产环境,这时自动分析也完成了.
自动渐进式交付失败
上述演示中,由于应用返回的 HTTP 状态码都是 200 ,所以金丝雀分析自然是会成功的。
接下来,我们来尝试进行自动渐进式交付失败的实验。
经过了自动渐进式交付成功的实验之后,当前生产环境中的镜像为
argoproj/rollouts-demo:green
,我们继续使用Argo Rollout kubectl
插件来更新镜像,并将镜像版本修改为yellow
版本。
sql
kubectl argo rollouts set image canary-demo canary-demo=argoproj/rollouts-demo:yellow
rollout "canary-demo" image updated
接下来,我们让应用返回错误的 HTTP 状态码。你可以滑动界面上的 ERROR 滑动块,将错误率设置为 50%
现在,你会在黄色方块中看到带有红色描边的方块,这代表本次请求返回的 HTTP 状态码不等于 200,说明 我们成功控制了一部分请求返回错误。
2 分钟后,金丝雀发布会进入到 40% 流量的阶段,此时自动分析将开始进行。可以通过 Argo Rollout 控制台实时观察。
等待一段时间后,金丝雀分析将失败,是预期内的!
此时,Argo Rollout 将执行自动回滚操作,这时候重新返回http://progressive.auto
打开应用,你会看到黄色方块的流量消失,所有请求被绿色方块取代,说明已经完成回滚了,如下图所示:
到这里,一次完整的渐进式交付失败实验就完成了。
结语
跟之前金丝雀发布不同的是:渐进式交付在金丝雀发布的过程中加入了自动金丝雀分析,它可以验证新版本在生产环境中的表现,而这是单纯的金丝雀发布所无法实现的。借助渐进式交付,我们可以在发布过程通过指标实时分析金丝雀环境,兼顾发布的安全性和效率。
值得注意的是,为了能够查询到示例应用的 HTTP 指标,开启了Ingress-Nginx/Traefik-controller
的指标开关,这样所有经过 Ingress-Nginx 的流量都会被记录下来,结合Prometheus ServiceMonitor
实现了 HTTP 请求指标的采集。
此外,为了让 ArgoCD 在渐进式交付时顺利运行金丝雀分析,我们还需要创建AnalysisTemplate
对象,它实际上是 PromQL 编写的查询语句,ArgoCD 在交付过程中会用这条语句去 Prometheus 查询,并将返回的结果和预定义的阈值进行对比,以此控制渐进式交付应该继续进行还是回滚。
在实际的业务场景中,如果希望验证多个维度的指标,你可以创建多个AnalysisTemplate
并将它配置到 Rollout 对象中,进一步提高分析的可靠性。另外,还可以在金丝雀发布的steps
阶段里配置"内联"的分析步骤,比如在金丝雀环境 20% 和 40% 流量阶段的下一阶段分别运行不同的金丝雀分析,具体参考 https://argoproj.github.io/argo-rollouts/features/analysis/