本文介绍如何通过微服务引擎和 Ingress 入口网关实现全链路流量灰度。
外部带有 x_version_tag:gray
请求头的请求:作为灰度流量,请求的路径为 service1 v1 -> service2 v2 -> service3 v2 -> service4 v2 -> service5 v2 -> end。
其他的请求:路由至基础泳道,请求路径为 service1 v1 -> service2 v1 -> service3 v1 -> service4 v1 -> service5 v1 -> end。
x_version_tag:gray
。mse-lane-demo.zip
。启动 K8s Deployment 时,需要增加部分 Labels 和 Annotations,对应的示例和说明如下。
说明
以下部分信息支持通过服务接入向导获取,操作详情参见 接入 Java 应用。
spec: template: metadata: annotations: sidecar.mesh.io/prestop-timeout: "5000" labels: sidecar.mesh.io/data-plane-mode: "java_proxyless" sidecar.mesh.io/lane: "lane-a" sidecar.mesh.io/mse-namespace: "nacos-test-public-default-group"
类型 | 参数 | 说明 | 示例值 |
---|---|---|---|
annotations | sidecar.mesh.io/prestop-timeout | 可选,开启无损下线后支持。实例延迟下线的时长,单位为毫秒,支持根据实际业务情况调整时长。 | sidecar.mesh.io/prestop-timeout: "5000" |
labels | sidecar.mesh.io/data-plane-mode | 微服务引擎数据面组件。 | sidecar.mesh.io/data-plane-mode: "java_proxy" |
sidecar.mesh.io/lane | 服务所处泳道名称。 | sidecar.mesh.io/lane: "lane-a" | |
sidecar.mesh.io/mse-namespace | 服务所处 Nacos 命名空间的名称。 | sidecar.mesh.io/mse-namespace: "nacos-test-public-default-group" |
在已创建的业务集群创建 Nacos 应用,并支持 K8s 服务访问,示例代码如下。
apiVersion: apps/v1 kind: Deployment metadata: annotations: name: nacostest spec: replicas: 1 selector: matchLabels: app: nacostest template: metadata: labels: app: nacostest spec: containers: - env: - name: MODE value: standalone image: mse-cn-beijing.cr.volces.com/mse/nacos-server:v2.1.0 imagePullPolicy: IfNotPresent name: nacos ports: - containerPort: 8848 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: nacostest spec: ports: - name: http port: 8848 protocol: TCP targetPort: 8848 - name: grpc port: 9848 protocol: TCP targetPort: 9848 selector: app: nacostest type: NodePort
创建 App1 ~ App5,5 个 Java 应用, App2 ~ App5 存在灰度版本 v2。
说明
mse-lane-demo.zip
。App1 的基线版本。
说明
apiVersion: apps/v1 kind: Deployment metadata: name: service1 namespace: istio-app spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: service1 strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: sidecar.mesh.io/prestop-timeout: "5000" labels: app: service1 service.istio.io/canonical-name: "service1" sidecar.mesh.io/data-plane-mode: "java_proxyless" sidecar.mesh.io/mse-namespace: "nacos-test-public-default-group" spec: containers: - args: - -c - /jdk/bin/java -jar lenforry.jar command: - /bin/sh env: - name: CurServiceName value: service1 - name: CurServiceVersion value: v1 - name: NextServiceName value: service2 - name: VERSION valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name image: monica-cn-beijing.cr.volces.com/monica/topology:v1 imagePullPolicy: IfNotPresent name: c0 ports: - containerPort: 80 name: http protocol: TCP resources: limits: cpu: 510m memory: 1Gi requests: cpu: 500m memory: 1Gi
App3 的基线版本。
App3 请求 App4 时,由于归属不同业务域无法直连访问。可通过集群内的 Ingress 进行代理转发。将 App3 的 NextServiceName 设置为 Ingress 暴漏的 VIP 地址,通过 Ingress 路由规则匹配 App4 对应服务版本。
apiVersion: apps/v1 kind: Deployment metadata: name: service3 namespace: istio-app spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: service3 strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: sidecar.mesh.io/prestop-timeout: "5000" labels: app: service1 service.istio.io/canonical-name: "service3" sidecar.mesh.io/data-plane-mode: "java_proxyless" sidecar.mesh.io/mse-namespace: "nacos-test-public-default-group" spec: containers: - args: - -c - /jdk/bin/java -jar lenforry.jar command: - /bin/sh env: - name: CurServiceName value: service3 - name: CurServiceVersion value: v1 - name: NextServiceName value: 180.***.***.56 - name: VERSION valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name image: monica-cn-beijing.cr.volces.com/monica/topology:v1 imagePullPolicy: IfNotPresent name: c0 ports: - containerPort: 80 name: http protocol: TCP resources: limits: cpu: 510m memory: 1Gi requests: cpu: 500m memory: 1Gi
对 App4 创建 2 个 K8s svc 指向 App4 的基线和灰度版本。Ingress 根据 App3 请求流量中的染色标识 baggage 路由至 App4 对应泳道版本。
service4-base-svc
:用于映射 Ingress 规则路由至 App4 的基线版本。service4-gray-svc
:用于映射 Ingress 规则路由至 App4 的灰度版本。svc4-ingress-lane-demo
:用于获取 App3 带有灰度染色标识进行流量透传并路由到灰度版本。svc4-ingress
:用于将 App3 流量中未带有流量染色标识路由到基线版本。创建 App1 的 k8s service service1-base-svc
,关联 App1 Deployment,以支持外部流量通过 Ingress + K8s 的服务发现方式访问 App1 服务。
在 Ingress 设置染色规则。svc1-ingress
示例代码如下。
说明
x_version_tag:gray
流量进行染色service1-base-svc
服务。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/configuration-snippet: | # 如果有header x_version_tag=gray,则是灰度流量, # 添加x-mse-tag=gray,透传流量标签 set $mseTag "prod"; if ($http_x_version_tag = "gray") { set $mseTag "meshEnv=g81bix7ftty9wzlvv1hq****-demo-lane"; } proxy_set_header baggage $mseTag; vke.volcengine.com/description: "" creationTimestamp: "2023-08-22T08:32:32Z" generation: 5 name: svc1-ingress namespace: istio-app resourceVersion: "1817755" uid: b6df5a51-347d-4abb-89ba-1265f376**** spec: ingressClassName: nginx rules: - host: service1 http: paths: - backend: service: name: service1-base-svc port: number: 80 path: /getnext pathType: Prefix status: loadBalancer: ingress: - ip: 180.***.***.56
结果验证
登录业务集群中的任意 Pod 执行以下命令即可查看流量的请求路径。
for i in $(seq 1 100); do curl -s -o /dev/null curl -X GET 180.***.***.56/getnext -H "Host: service1" -H "x_version_tag:100" -w"\n";done
for i in $(seq 1 100); do curl -s -o /dev/null curl -X GET 180.***.***.56/getnext -H "Host: service1" -H "x_version_tag:101" -w"\n";done
说明
180.***.***.56
为 Ingress 的 VIP 地址。
经验证可知:
x_version_tag:gray
时路由至灰度版本已设置灰度版本相对未设置灰度版本需要新增以下资源。
service1-v2
。apiVersion: apps/v1 kind: Deployment metadata: name: service1-v2 namespace: istio-app spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: service1-v2 strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: sidecar.mesh.io/prestop-timeout: "5000" labels: app: service1 service.istio.io/canonical-name: "service1" sidecar.mesh.io/data-plane-mode: "java_proxyless" sidecar.mesh.io/mse-namespace: "nacos-test-public-default-group" sidecar.mesh.io/lane: "demo-lane" spec: containers: - args: - -c - /jdk/bin/java -jar lenforry.jar command: - /bin/sh env: - name: CurServiceName value: service1 - name: CurServiceVersion value: v2 - name: NextServiceName value: service2 - name: VERSION valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name image: monica-cn-beijing.cr.volces.com/monica/topology:v1 imagePullPolicy: IfNotPresent name: c0 ports: - containerPort: 80 name: http protocol: TCP resources: limits: cpu: 510m memory: 1Gi requests: cpu: 500m memory: 1Gi
service1-gray-svc
。apiVersion: v1 kind: Service metadata: name: service1-gray-svc namespace: istio-app spec: ports: - name: http port: 80 protocol: TCP targetPort: 80 selector: app: service1-v2 sessionAffinity: None type: ClusterIP
svc1-ingress-lane-demo
。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: x_version_tag nginx.ingress.kubernetes.io/canary-by-header-value: "gray" nginx.ingress.kubernetes.io/canary-weight: "0" vke.volcengine.com/description: "" creationTimestamp: "2023-08-22T12:17:33Z" generation: 3 name: svc1-ingress-lane-demo namespace: istio-app resourceVersion: "1820324" uid: 9e514e6c-f39e-420c-846a-728ed5d7**** spec: ingressClassName: nginx rules: - host: service1 http: paths: - backend: service: name: service1-gray-svc port: number: 80 path: /getnext pathType: Prefix status: loadBalancer: ingress: - ip: 180.***.***.56
结果验证
登录业务集群中的任意 Pod 执行以下命令即可查看流量的请求路径。
for i in $(seq 1 100); do curl -s -o /dev/null curl -X GET 180.***.***.56/getnext -H "Host: service1" -H "x_version_tag:100" -w"\n";done
for i in $(seq 1 100); do curl -s -o /dev/null curl -X GET 180.***.***.56/getnext -H "Host: service1" -H "x_version_tag:101" -w"\n";done
说明
180.***.***.56
为 Ingress 的 VIP 地址。
经验证可知:
x_version_tag:gray
时路由至灰度版本