apisix + argorollout 实现蓝绿发布II-线上热切与蓝绿发布控制
本次主题主要目的是为大家讲解蓝绿发布,但是发现文档和内容太长了,对此将文档拆分成了两部分,视频拆分成了好几部分,这样大家刷起来没疲劳感。
第一部分《apisix + argorollout 实现蓝绿发布I-使用apisix发布应用》,主要内容为:
-
K8S环境说明与准备。
-
在K8S中发布一个正常的web应用。
-
使用apisix代理我们发布的应用。
第二份《apisix + argorollout 实现蓝绿发布II-线上热切与蓝绿发布控制》内容为:
-
ArgoRollrout介绍与安装
-
怎么在线上热切换为支持蓝绿版本应用。
-
正常发布流程演示。
1.ArgoRollrout介绍与安装
1.1 AR简介
Argo Rollouts 是一个 Kubernetes 控制器和一组 CRDs(自定义资源定义),它们为 Kubernetes 提供了高级部署能力,如蓝绿部署、金丝雀发布、金丝雀分析、实验以及渐进式交付功能。 主要提供以下功能:
-
蓝绿更新策略
-
金丝雀更新策略
-
细粒度、加权流量转移
-
自动回滚和升级
-
人工判断
-
可定制指标查询和业务 KPI 分析
-
入口控制器集成:NGINX、ALB
-
服务网格集成:Istio、Linkerd、SMI
-
指标提供商集成:Prometheus、Wavefront、Kayenta、Web、Kubernetes Jobs
1.2 架构信息
蓝绿发布
蓝绿部署同时部署了应用程序的新版本和旧版本。在此期间,只有旧版本的应用程序会接收生产流量。这允许 QA 和运营团队在将实时流量切换到新版本之前针对新版本运行测试。
Canary-金丝雀
金丝雀部署将一部分用户暴露给新版本的应用程序,同时将其余流量提供给旧版本。一旦新版本被验证为正确,新版本就可以逐渐取代旧版本。入口控制器和服务网格(例如 NGINX 和 Istio)为金丝雀部署提供了比原生更复杂的流量整形模式(例如实现非常细粒度的流量拆分或基于 HTTP 标头的拆分)。
Argo Rollouts 架构
Rollout 控制器
主控制器监视集群中的事件,并在 Rollout 类型的资源发生更改时做出反应。控制器将读取 Rollout 的所有详细信息,并将集群置于 Rollout 定义中描述的相同状态。
AnalysisTemplate 和 AnalysisRun
Analysis 是将 Rollout 连接到指标提供程序并为某些指标定义特定阈值的功能,这些阈值将决定更新是否成功。如果指标查询良好,Rollout 将自行进行;如果指标显示失败,则自动回滚;如果指标无法提供成功/失败答案,则暂停 Rollout。
为了执行分析,Argo Rollouts 包含两个自定义 Kubernetes 资源:AnalysisTemplate 和 AnalysisRun。
AnalysisTemplate 包含有关查询哪些指标的说明。附加到 Rollout 的实际结果是 AnalysisRun 自定义资源。
1.3 部署手册
安装argo-rollouts controller
这将创建命名空间并创建 argo-rollout 服务、部署、CRD 等。
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
在为需要运行业务的namespace添加权限:apisixroute-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:name: argo-rollouts-apisix-rolenamespace: web
rules:
- apiGroups: ["apisix.apache.org"]resources: ["apisixroutes"]verbs: ["get", "list", "create", "update", "delete"]---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: argo-rollouts-apisixroute-accessnamespace: web
subjects:- kind: ServiceAccountname: argo-rolloutsnamespace: argo-rollouts
roleRef:kind: Rolename: argo-rollouts-apisix-roleapiGroup: rbac.authorization.k8s.io
创建对应的资源
如果不加权限的话,可能会出现报错:Error encounter during ArgoRollout Canary
Error create apisix route "set-header": apisixroutes.apisix.apache.org is forbidden: User "system:serviceaccount:argo-rollouts:argo-rollouts"
cannot create resource "apisixroutes" in API group "apisix.apache.org" in the namespace "web"
The error you're seeing occurs because the Argo Rollouts service account does not have the necessary permissions to create or update ApisixRoute resources in the fpms namespace. To fix this, you'll need to give the argo-rollouts service account the appropriate Role and RoleBinding in Kubernetes so it can interact with the ApisixRoute resources.
2.业务系统蓝绿改造
2.1 Rollout Deployment
demo示例 canary-rollout-deployment.yaml,按照文档1中的信息,修改为rollout 格式。
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:name: http-web-server-canarynamespace: weblabels:app: http-web-server-canary
spec:replicas: 5selector:matchLabels:app: http-web-server-canaryrevisionHistoryLimit: 3strategy:canary:canaryService: service-http-web-server-csstableService: service-http-web-server-sstrafficRouting:managedRoutes:- name: set-header-usernameapisix:route:name: http-web-server-apisix-route-canaryrules:- http-web-server-route-canarysteps:- setCanaryScale:weight: 2setHeaderRoute:match:- headerName: usernameheaderValue:regex: "(maoshu|maoshu1|maoshu2)"name: set-header-username- pause: { }- setCanaryScale:matchTrafficWeight: true- setWeight: 10- pause: { duration: 15m }- setWeight: 50- pause: { duration: 45m }- setWeight: 80- pause: { duration: 2h }
说明:
保留的旧 ReplicaSet 数量,默认为 10。
revisionHistoryLimit:3
Canary 服务表示将更新的服务(新版本),而 Stable 服务表示当前版本。
注意:Stable 服务表示您当前的服务,但您应该创建一个新的 Stable 服务,而不是修改当前的服务。
-
strategy:canary:
-
canaryService:service-http-web-server-cs
-
stableService:service-http-web-server-ss
trafficRouting.managedRoutes 表示在 Rollout 启动时,它将创建一个名为 set-header-client-apiserver 的新 APISIX 路由。apisix.route.name 表示您当前正在使用的 APISIX 路由的名称,apisix.route.rules APISIX 路由的规则名称,可以参考此 APISIX 路由示例:
strategy.steps 是金丝雀阶段的开始。 setCanaryScale 表示金丝雀 Pod 的总副本数占比(新版本),可以包含 2 个选项:
-
replicas:为金丝雀打开的副本数
-
weight:占总服务 Pod 的百分比
setHeaderRoute 表示带有标头值的基于标头的路由。在我的例子中,我使用的是 true-client-ip,即用户的源 IP。(注意:稳定版本仅支持精确、正则表达式或前缀) setCanaryScale.matchTrafficWeight:true,表示匹配金丝雀流量权重。例如:
-
setWeight:5 表示总服务 Pod 的 5%,并将 5% 的流量释放到金丝雀。
-
setWeight:10 表示总服务 Pod 的 10%,并将 10% 的流量释放到金丝雀
-
setWeight: 30 表示总服务 pod 的 10%,并将 30% 的流量释放到金丝雀。
-
pause: { 1 h } :暂停部署一小时。支持的单位:s、m、h
-
pause: {} :无限期暂停,直到手动恢复。
2.2 service 改造
web服务 YAML 配置,理想情况下您将拥有 3 个服务。
-
service-http-web-server-cs(仅限新 Pod)
-
service-http-web-server-ss(仅限旧 Pod)
-
service-http-web-server(原始):service-http-web-server
apiVersion: v1
kind: Service
metadata:name: service-http-web-serverlabels:app: service-http-web-server
spec:ports:- port: 8080targetPort: 8080selector:app: http-web-server
---
apiVersion: v1
kind: Service
metadata:name: service-http-web-server-sslabels:app: service-http-web-server
spec:ports:- port: 8080targetPort: 8080selector:app: http-web-server-canary
---
apiVersion: v1
kind: Service
metadata:name: service-http-web-server-cslabels:app: service-http-web-server
spec:ports:- port: 8080targetPort: 8080selector:app: http-web-server-canary
2.3 APISIX Route 改造
APISIX Route 配置案例,建议刚开始的时候,建立新域名(webserver2.dsinc.com.cn)来验证,防止导致线上故障。
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:name: http-web-server-apisix-route-canarynamespace: web
spec:http:- backends:- serviceName: service-http-web-server-csservicePort: 8000weight: 0- serviceName: service-http-web-server-ssservicePort: 8000weight: 100match:hosts:- webserver2.dsinc.com.cnpaths:- /*name: http-web-server-route-canaryplugins:- enable: truename: prometheus- enable: falsename: traffic-splitwebsocket: true
以上信息执行一波,并查看各个信息是否存在
(base) maoshu@maoshu-MacBook argo % kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service-http-web-server ClusterIP 10.97.55.216 <none> 8080/TCP 179m
service-http-web-server-cs ClusterIP 10.101.114.27 <none> 8080/TCP 2m25s
service-http-web-server-ss ClusterIP 10.100.131.71 <none> 8080/TCP 2m25s(base) maoshu@maoshu-MacBook argo % kubectl get ar
Warning: short name "ar" could also match lower priority resource analysisruns.argoproj.io
NAME HOSTS URIS AGE
http-web-server-apisix-route ["webserver.dsinc.com.cn"] ["/*"] 85m
http-web-server-apisix-route-canary ["webserver2.dsinc.com.cn"] ["/*"] 2m23s(base) maoshu@maoshu-MacBook argo % kubectl get rollout
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
http-web-server 3 3 3 2 4m(base) maoshu@maoshu-MacBook argo % kubectl get pods
NAME READY STATUS RESTARTS AGE
http-web-server-6cdccbb564-dnqcr 1/1 Running 0 29m
http-web-server-6cdccbb564-fx2zl 1/1 Running 1 (69m ago) 3h9m
http-web-server-6cdccbb564-whcsw 1/1 Running 0 29m
http-web-server-85cd846dcd-6lqj8 1/1 Running 0 27s
http-web-server-85cd846dcd-97k5q 1/1 Running 0 27s
http-web-server-85cd846dcd-hbcl6 1/1 Running 0 27s
2.4 Argo Rollout Dashboard
在本地设备上使用 Argo Rollout Dashboard,链接如下:
https://argo-rollouts.readthedocs.io/en/stable/dashboard/
连接到您的k8s集群并运行 kubectl argo rollouts 仪表板,然后请求此 http://localhost:3100/rollouts
页面信息
3.线上热切换
3.1 参考
建议线上添加argo rollout操作步骤参考如下,我在qps 几万的线上环境操作过,可以直接抄答案。
-
更新apisix ,修改 plugin: []
-
创建argo rollout的role,RoleBinding
-
添加:apisix route,使用新域名
-
执行Rollout ,service
-
使用新域名验证功能
-
更新旧域名的apisix route,添加 priority: 10
-
更新新域名的apisix route,并设置priority: 5
-
降低旧域名的priority: 10 - 3
-
清理旧的deployment和apisix route
3.2 环境验证
经过以上的一波操作,我们已经进行到步骤4了,接下来我们从5开始验证。
第4步结束后,现有的资源如下
(base) maoshu@maoshu-MacBook argo % kubectl get pods
NAME READY STATUS RESTARTS AGE
http-web-server-6cdccbb564-dnqcr 1/1 Running 0 43h
http-web-server-6cdccbb564-fx2zl 1/1 Running 1 (44h ago) 46h
http-web-server-6cdccbb564-whcsw 1/1 Running 0 43h
http-web-server-7c85497497-dpbhj 1/1 Running 0 42h
http-web-server-7c85497497-lz4pp 1/1 Running 0 42h
http-web-server-7c85497497-vbzsn 1/1 Running 0 42h
http-web-server-fc69ff979-chkqf 1/1 Terminating 0 42h
http-web-server-fc69ff979-dfx7k 1/1 Running 0 12s
(base) maoshu@maoshu-MacBook argo % kubectl get ar
Warning: short name "ar" could also match lower priority resource analysisruns.argoproj.io
NAME HOSTS URIS AGE
http-web-server-apisix-route ["webserver.dsinc.com.cn"] ["/*"] 44h
http-web-server-apisix-route-canary ["webserver2.dsinc.com.cn"] ["/*"] 43h
我们使用新域名进行访问,试试好使不
#开端口映射
(base) maoshu@maoshu-MacBook argo % sudo kubectl port-forward svc/apisix-gateway -n ingress-apisix 80
Forwarding from 127.0.0.1:80 -> 9080
Forwarding from [::1]:80 -> 9080
#修改hosts配置信息
(base) maoshu@maoshu-MacBook .kube % cat /etc/hosts
127.0.0.1 webserver.dsinc.com.cn
127.0.0.1 webserver2.dsinc.com.cn
使用浏览器访问新域名,查看是否能得到信息
看到如上信息,证明我们改造完成。
3.3 环境切换
更新旧域名的apisix route:apps/apisix-route.yaml,添加 priority: 10
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:name: http-web-server-apisix-routenamespace: web
spec:http:- backends:- serviceName: service-http-web-serverservicePort: 8080match:hosts:- webserver.dsinc.com.cnpaths:- /*name: http-web-server-routepriority: 10
更新新域名的apisix route:argo/apisix-route.yaml,新域名域名修改为:webserver.dsinc.com.cn,并且调整priority: 5
match:hosts:- webserver.dsinc.com.cn
修改后内容如下:1. 确认下域名是否相同; 2.确认信息中 priority:5 的值
降低旧域名(apps/apisix-route.yaml)的priority: 10 - 3
#app/apisix-route.yaml
spec:http:
…name: http-web-server-routepriority: 3
使用浏览器查看是否切换到新环境
确认无问题后,删除老环境的各种资源。(建议,直接修改replica 为0,先不要删,留到最后才删除)
apiVersion: apps/v1
kind: Deployment
metadata:name: http-web-servernamespace: web
spec:replicas: 0selector:
删除命令
(base) maoshu@maoshu-MacBook apps % kubectl delete -f apisix-route.yaml
apisixroute.apisix.apache.org "http-web-server-apisix-route" deleted
(base) maoshu@maoshu-MacBook apps % kubectl delete -f deploy-http-webserver.yaml
deployment.apps "http-web-server" deleted
(base) maoshu@maoshu-MacBook apps % kubectl get pods
NAME READY STATUS RESTARTS AGE
http-web-server-6cdccbb564-dnqcr 1/1 Terminating 0 43h
http-web-server-6cdccbb564-fx2zl 1/1 Terminating 1 (44h ago) 46h
http-web-server-6cdccbb564-whcsw 1/1 Terminating 0 43h
http-web-server-canary-55cc86bfd5-5zxq8 1/1 Running 0 10m
http-web-server-canary-55cc86bfd5-c4fvx 1/1 Running 0 10m
http-web-server-canary-55cc86bfd5-hsmwb 1/1 Running 0 10m
以上操作,我在QPS几万的系统上做过线上热切,可以直接抄作业,不需要担心。
4.正常发版流程
发版流程在步骤中有定义
steps:- setCanaryScale:weight: 2setHeaderRoute:match:- headerName: usernameheaderValue:regex: "(maoshu|maoshu1|maoshu2)"name: set-header-username-client- pause: { }- setCanaryScale:matchTrafficWeight: true- setWeight: 10- pause: { duration: 15m }- setWeight: 50- pause: { duration: 45m }- setWeight: 80- pause: { duration: 2h }
整体流程如下:
-
刚开始部署时候,先启动一个“set-header-username-client”的信息用来验证
-
验证通过,点击下一步,切换10%流量到新pod
-
等待15分钟后,切换50%流量
-
等待45分钟后,切换80%流量
-
等待2h后,切换100%流量 具体发布细节如下:
4.1 触发发版
修改deployment相关的内容:镜像版本,软件信息,env信息等都可以,我们修改一个小小的env参数测试。
resources:limits:cpu: "512m"memory: "256Mi"requests:cpu: "300m"memory: "128Mi"
env:- name: SOFTWARE_VERSIONvalue: "v4.0"
执行安装更新
kubectl apply -f api-monitor-deployment.yaml
可以点击argo的页面查看
你会发现已经触发了发版本流程,创建了一个用于验证的pod了。
4.2 验证新环境是否正常
对应的pod信息,以下标红的就是用来验证的新版本信息。到这个阶段,找研发和测试组进行介入,验证新版本功能是否OK。
查看argo rollout信息,多了一个set-header-client-apiserver的服务,并且查看服务,你会发现,就是上面写的内容,满足此条件的流量,就会通过新的pod信息。
查看正式的ar信息,流量比为0:100
使用postman进行模拟访问,你会发现,属于(maoshu、maoshu1、maoshu2)都是访问到的v4.0 版本。其他情况,都是访问的v3.0版本。
其他用情况,访问的是v3.0 版本。
4.3 流量切换
经过各种验证后,点击下一步。
此处,会删除刚才用于验证的ar信息,并启动10%左右的pod,来释放流量;
查看pod与ar的变化;
pod:新建了一个;
ar:用于验证的已经删除,并且正式的流量修改为10:90。
自己测试几次,看看是不是多数访问的v3.0,少数访问的v4.0,自己点点看即可。 剩下的步骤,交给时间,同步查看下流量比例
-
等待15分钟,或者手动点击下一步(50:50)
-
等待45分钟,比例 20:80
-
最后:100%
对应的pod信息与ar信息,流量已经切换为100%了。
到此,整个发版本完成。太秀了,恭喜大家技能树又多点亮了几个,不用谢。