全链路灰度介绍
在微服务架构场景下,传统的灰度发布模式往往不能满足交付的复杂需求,全链路灰度发布的场景也就应运而生,此时每个微服务都会有灰度环境或分组来接受灰度流量。开发者希望进入上游灰度环境的流量也能进入下游灰度环境中,确保一个请求始终在灰度环境中传递,从而形成流量泳道。在泳道内的流量链路中,即使这个调用链路上有一些微服务应用不存在灰度环境,那么这些微服务应用在请求下游的时候依然能够重新回到灰度环境中。此时可以根据服务的实际情况,控制多个服务同时进行发布变更,从而保证整个系统的稳定性,效果如下图所示:

Kruise Rollouts介绍
Kruise Rollouts是OpenKruise社区开源的渐进式交付框架。Kruise Rollouts支持配合流量和实例灰度的灰度发布、蓝绿发布和A/B Testing发布。基于Prometheus Metrics指标,Kruise Rollouts还可以实现发布过程的自动化分批与暂停,并提供旁路的无感对接,兼容已有的多种工作负载(Deployment、CloneSet、StatefulSet),更多信息,请参见Kruise Rollouts。
Kruise Rollouts是一种旁路式的工作机制。您只需配置一份Rollouts资源并将其下发到K8s集群中,后续的业务发布和升级均无需额外操作,并且可以与Helm和PaaS平台低成本无缝对接。使用Kruise Rollouts实现灰度发布架构图如下:
步骤二:部署Demo应用
部署业务应用(Deployment、Service和Ingress)。
使用如下内容,创建mse-demo.yaml文件。
apiVersion: v1
kind: Service
metadata:
name: spring-cloud-a
spec:
ports:
- name: http
port: 20001
protocol: TCP
targetPort: 20001
selector:
app: spring-cloud-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-a
spec:
replicas: 2
selector:
matchLabels:
app: spring-cloud-a
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-a
labels:
app: spring-cloud-a
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/spring-cloud-a:mse-2.0.0
imagePullPolicy: Always
name: spring-cloud-a
ports:
- containerPort: 20001
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-b
spec:
replicas: 2
selector:
matchLabels:
app: spring-cloud-b
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-b
labels:
app: spring-cloud-b
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/spring-cloud-b:mse-2.0.0
imagePullPolicy: Always
name: spring-cloud-b
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-c
spec:
replicas: 2
selector:
matchLabels:
app: spring-cloud-c
template:
metadata:
annotations:
msePilotCreateAppName: spring-cloud-c
labels:
app: spring-cloud-c
spec:
containers:
- env:
- name: JAVA_HOME
value: /usr/lib/jvm/java-1.8-openjdk/jre
image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/spring-cloud-c:mse-2.0.0
imagePullPolicy: Always
name: spring-cloud-c
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos-server
spec:
replicas: 1
selector:
matchLabels:
app: nacos-server
template:
metadata:
labels:
app: nacos-server
spec:
containers:
- env:
- name: MODE
value: standalone
image: registry.cn-hangzhou.aliyuncs.com/mse-governance-demo/nacos-server:v2.1.2
imagePullPolicy: Always
name: nacos-server
dnsPolicy: ClusterFirst
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: nacos-server
spec:
type: ClusterIP
ports:
- name: nacos-server-8848-8848
port: 8848
protocol: TCP
targetPort: 8848
- name: nacos-server-9848-9848
port: 9848
protocol: TCP
targetPort: 9848
selector:
app: nacos-server
---
apiVersion: v1
kind: Service
metadata:
labels:
app: demo-mysql
name: demo-mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: demo-mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-mysql
spec:
selector:
matchLabels:
app: demo-mysql
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: demo-mysql
spec:
containers:
- args:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
env:
- name: MYSQL_ROOT_PASSWORD
value: root
image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo-mysql:3.0.1
name: demo-mysql
ports:
- containerPort: 3306
执行如下命令,部署业务应用。
kubectl apply -f mse-demo.yaml
使用如下内容,创建mse-ingress.yaml文件。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/service-subset: ""
name: spring-cloud-a
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: spring-cloud-a
port:
number: 20001
path: /
pathType: Prefix
执行如下命令,创建Ingress规则。
kubectl apply -f mse-ingress.yaml
执行如下命令,获取外部IP。
预期输出如下所示:
NAME CLASS HOSTS ADDRESS PORTS AGE
spring-cloud-a <none> * EXTERNAL_IP 80 12m
执行如下命令,查看路由访问情况。替换以下<EXTERNAL_IP>为您上一步获取的外部IP。
curl http://<EXTERNAL_IP>/a
预期输出如下所示:
A[192.168.0.26][config=base] -> B[192.168.100.45] -> C[192.168.0.34]
步骤三:通过Kruise Rollouts实现自动化的全链路灰度发布
定义Kruise Rollouts的灰度发布规则。
说明
以下Rollout资源将定义灰度发布规则,发布分为三批:
A/B Testing发布,具有header[User-Agent]=xiaoming的流量将导入到新版本,其它则为老版本。
按照流量比例进行灰度,此批次将灰度50%的实例及流量。
将灰度完成所有的实例。
使用如下内容,创建rollout.yaml文件。
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-a
annotations:
rollouts.kruise.io/trafficrouting: mse-traffic
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: spring-cloud-a
strategy:
canary:
steps:
- pause: {}
replicas: 1
patchPodTemplateMetadata:
labels:
alicloud.service.tag: gray
opensergo.io/canary-gray: gray
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-b
annotations:
rollouts.kruise.io/trafficrouting: mse-traffic
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: spring-cloud-b
strategy:
canary:
steps:
- pause: {}
replicas: 1
patchPodTemplateMetadata:
labels:
alicloud.service.tag: gray
opensergo.io/canary-gray: gray
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-c
annotations:
rollouts.kruise.io/trafficrouting: mse-traffic
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: spring-cloud-c
strategy:
canary:
steps:
- pause: {}
replicas: 1
patchPodTemplateMetadata:
labels:
alicloud.service.tag: gray
opensergo.io/canary-gray: gray
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: mse-traffic
spec:
objectRef:
- service: spring-cloud-a
ingress:
classType: mse
name: spring-cloud-a
strategy:
matches:
- headers:
- type: Exact
name: User-Agent
value: xiaoming
requestHeaderModifier:
set:
- name: x-mse-tag
value: gray
执行如下命令,将该Rollout资源下发到K8s集群。
kubectl apply -f rollout.yaml
执行如下命令,查看Rollout资源的状态。
预期输出STATUS=Healthy,表明Rollout资源正常工作。
升级应用版本。
Kruise Rollouts是一个常态化的配置,将其下发到集群后,后续业务版本发布只需调整Deployment配置,无需再对Kruise Rollouts进行额外操作。例如,业务将spring-cloud-a服务跟spring-cloud-c镜像版本升级到mse-2.0.1,然后通过执行kubectl apply -f mse-demo.yaml
命令将Deployment部署到集群。将Deployment配置下发到K8s集群时,除kubectl方式外,也可以使用Helm或Vela等方式。
确认灰度发布的新版本发布正常后,继续后续发布。
前面的步骤仅发布部分实例以及部分的金丝雀流量灰度,通过一些业务日志或监控确认新版本发布正常后,可通过rollout.rollouts.kruise.io/<rollouts-demo> approved
命令继续后续发布,其中<rollouts-demo>表示Rollout资源的名称。
(可选)若新版本服务异常,可进行业务回滚。
如果在Rollout过程中,发现新版本服务异常,可以通过Deployment配置恢复到之前版本。然后通过kubectl apply -f mse-demo.yaml
命令进行部署,无需对Rollout资源做任何改动。
在微服务治理架构中,全链路灰度功能提供流量分流,极大地方便了测试和发布时的快速验证,结合Kruise Rollouts能够大幅度帮助DevOps提升线上稳定性。