灰度发布是一种常用的软件发布策略,通过渐进式地向用户推送新版本的服务,来保证生产环境中服务迭代升级时系统的稳定性。ALB Ingress支持使用canary注解实现基于Header、Cookie、Weight的灰度发布。本文介绍如何通过ALB Ingress的canary注解实现服务的灰度发布。
前提条件
已创建ACS集群。具体操作,请参见创建ACS集群。
已为ACS集群安装ALB Ingress Controller组件。具体操作,请参见管理ALB Ingress Controller组件。
已创建AlbConfig和IngressClass。具体操作,请参见创建AlbConfig和创建IngressClass。
连接集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群或在CloudShell上通过kubectl管理Kubernetes集群。
注意事项
通过canary注解实现的三种灰度策略的优先级为Header>Cookie>Weight,同时配置三种策略时,优先级高的策略将优先进行灰度发布。关于canary注解的详细信息,请参见ALB Ingress灰度发布注解。
canary灰度发布不支持在同一条Ingress上同时配置基于Header/Cookie的灰度策略与基于权重Weight的灰度策略,这种场景下需要通过拆分为两条Ingress或通过自定义转发动作实现。自定义转发动作可以实现基于更丰富的转发条件的灰度发布策略。关于自定义转发规则,请参见自定义ALB Ingress的转发规则。
通过canary注解实现灰度发布时,ALB Ingress转发规则生效顺序依赖
Ingress namespace/name
字典序。为保证灰度规则生效顺序,可以使用alb.ingress.kubernetes.io/order
标识Ingress之间的生效顺序。alb.ingress.kubernetes.io/order
的取值范围为1~1000,默认标识为数字10,值越小表示优先级越高。例如,如果您想提高Ingress的优先级,可以将目标Ingress的alb.ingress.kubernetes.io/order
数值调小。
步骤一:部署服务
部署服务tea。
使用以下内容,创建tea-deploy.yaml。
apiVersion: apps/v1 kind: Deployment metadata: name: tea spec: replicas: 1 selector: matchLabels: app: tea template: metadata: labels: app: tea spec: containers: - name: tea image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx:latest ports: - containerPort: 80
执行以下命令,部署服务tea。
kubectl apply -f tea-deploy.yaml
部署名为tea-svc的Service。
使用以下内容,创建tea-svc.yaml。
apiVersion: v1 kind: Service metadata: name: tea-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: tea type: ClusterIP
执行以下命令,部署Service。
kubectl apply -f tea-svc.yaml
部署名为tea-ingress的Ingress。
使用以下内容,创建tea-ingress.yaml。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tea-ingress spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # 请替换成您自己的域名,并确保它已正确解析到Ingress控制器所在的负载均衡器的IP地址。 http: paths: - path: / pathType: Prefix backend: service: name: tea-svc port: number: 80
执行以下命令,部署Ingress。
kubectl apply -f tea-ingress.yaml
验证部署成功。
执行以下命令,请求访问服务。
curl -H Host:demo.domain.ingress.top http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
预期输出:
old
步骤二:灰度发布新版本服务
部署新版本服务和Ingress,使得当请求Header为location: hz
时将路由到新版本服务canary,其他请求Header以及不携带请求Header将有50%的流量路由到新版本服务canary。
部署新版本服务canary。
使用以下内容,创建canary-deploy.yaml。
apiVersion: apps/v1 kind: Deployment metadata: name: canary spec: replicas: 1 selector: matchLabels: app: canary template: metadata: labels: app: canary spec: containers: - name: canary image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx:latest ports: - containerPort: 80
执行以下命令,部署canary。
kubectl apply -f canary-deploy.yaml
部署名为canary-svc的Service。
使用以下内容,创建canary-svc.yaml。
apiVersion: v1 kind: Service metadata: name: canary-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: canary type: ClusterIP
执行以下命令,部署Service。
kubectl apply -f canary-svc.yaml
部署基于Header分配流量的Ingress。
使用以下内容,创建canary-header-ingress.yaml。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/canary: "true" alb.ingress.kubernetes.io/canary-by-header: "location" alb.ingress.kubernetes.io/canary-by-header-value: "hz" name: canary-header-ingress namespace: default spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # 请替换成您自己的域名,并确保它已正确解析到Ingress控制器所在的负载均衡器的IP地址。 http: paths: - backend: service: name: canary-svc port: number: 80 path: / pathType: Prefix
alb.ingress.kubernetes.io/canary:设置为true,表示启用canary注解功能。
alb.ingress.kubernetes.io/canary-by-header与alb.ingress.kubernetes.io/canary-by-header-value:设置请求Header的键值对。本文设置为
location: hz
,表示请求Header为location: hz
,请求流量会被分配到新版本服务;对于其他Header,将会被忽略,并通过灰度优先级将请求流量分配到其他规则设置的服务。
执行以下命令,部署基于Header分配流量的Ingress。
kubectl apply -f canary-header-ingress.yaml
部署基于权重分配流量的Ingress。
使用以下内容,创建canary-weight-ingress.yaml。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/canary: "true" alb.ingress.kubernetes.io/canary-weight: "50" name: canary-weight-ingress namespace: default spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # 请替换成您自己的域名,并确保它已正确解析到Ingress控制器所在的负载均衡器的IP地址。 http: paths: - backend: service: name: canary-svc port: number: 80 path: / pathType: Prefix
alb.ingress.kubernetes.io/canary-weight:设置路由到新版本服务的流量百分比。本文设置为50,表示50%的流量将路由到新版本服务。
执行以下命令,部署基于权重分配流量的Ingress。
kubectl apply -f canary-weight-ingress.yaml
验证灰度发布新版本服务是否成功。
执行以下命令,获取ALB实例的访问地址。
kubectl get ingress
预期输出:
NAME CLASS HOSTS ADDRESS PORTS AGE canary-header-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 8m23s canary-weight-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 8m16s tea-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 7m5s
执行以下命令,多次使用携带
location: hz
请求头的请求访问服务。curl -H Host:demo.domain.ingress.top -H "location:hz" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
预期输出:
new
多次使用携带
location: hz
请求头的请求访问服务,都返回new
的结果,说明使用携带location: hz
请求头的请求访问服务时,请求都路由到新版本服务。多次执行以下命令,发送不携带请求头的请求访问服务。
curl -H Host:demo.domain.ingress.top http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
多次不携带请求头的请求访问服务,约50%概率返回
new
的结果,约50%概率返回old
的结果,说明不携带请求头的请求访问服务时,请求按照50%权重路由到新版本服务。多次执行以下命令,使携带
location: bj
请求头的请求访问服务。curl -H Host:demo.domain.ingress.top -H "location:bj" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
多次携带
location: bj
请求头的请求访问服务,约50%的概率返回new
的结果,约50%的概率返回old
的结果,说明携带location: bj
请求头的请求访问服务时,请求按照50%的权重路由到新版本服务。
根据以上结果,可以看到当请求Header为
location: hz
时将路由到新版本服务canary,不携带请求Header以及其他请求Header有50%的流量路由到新版本服务canary,说明灰度发布canary服务成功。
步骤三:下线老版本服务
系统运行一段时间后,当新版本服务已经稳定并且符合预期时,需要下线旧版本的服务,仅保留新版本服务在线上运行。为了达到该目标,需要将原服务的Ingress中的Service修改为新版本服务的Service,使得流量都路由到新版本服务,然后删除灰度Ingress。
执行以下命令,修改tea-ingress.yaml文件。
vim tea-ingress.yaml
将tea-ingress.yaml文件中的Service由tea-svc修改为canary-svc。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tea-ingress spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # 请替换成您自己的域名,并确保它已正确解析到Ingress控制器所在的负载均衡器的IP地址。 http: paths: - path: / pathType: Prefix backend: service: name: canary-svc # 将tea-svc替换为canary-svc。 port: number: 80
执行以下命令,使修改后的Ingress生效。
kubectl apply -f tea-ingress.yaml
验证下线老版本服务是否成功。
执行以下命令,多次使用携带
location: hz
请求头的请求访问服务。curl -H Host:demo.domain.ingress.top -H "location:hz" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
预期输出:
new
多次使用携带
location: hz
请求头的请求访问服务,都返回new
的结果,说明使用携带location: hz
请求头的请求访问服务时,请求都路由到新版本服务。执行以下命令,多次使用不携带请求头的请求访问服务。
curl -H Host:demo.domain.ingress.top http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
预期输出:
new
多次使用不携带请求头的请求访问服务,都返回
new
的结果,说明使用不携带请求头的请求访问服务时,请求都路由到新版本服务。执行以下命令,使多次携带
location: bj
请求头的请求访问服务。curl -H Host:demo.domain.ingress.top -H "location:bj" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com
预期输出:
new
多次使用携带
location: bj
请求头的请求访问服务,都返回new
的结果,说明使用携带location: bj
请求头的请求访问服务时,请求都路由到新版本服务。
根据以上结果,可以看到携带
location: hz
请求头,携带其他请求头,或者不携带请求头的请求都路由到新版本服务,说明下线老版本服务成功。执行以下命令,删除名为canary-weight-ingress和canary-header-ingress的灰度Ingress,完成灰度发布流程。
kubectl delete ingress canary-weight-ingress canary-header-ingress