基于MSE Ingress的全鏈路灰度
通過(guò)MSE Ingress網(wǎng)關(guān)提供的全鏈路灰度能力,您可以在不需要修改任何業(yè)務(wù)代碼的情況下,實(shí)現(xiàn)全鏈路流量控制。本文介紹如何通過(guò)MSE Ingress網(wǎng)關(guān)實(shí)現(xiàn)全鏈路灰度功能。
前提條件
已創(chuàng)建Kubernetes集群。具體操作,請(qǐng)參見(jiàn)創(chuàng)建ACK托管集群。
已開(kāi)通MSE微服務(wù)治理專業(yè)版。具體操作,請(qǐng)參見(jiàn)開(kāi)通MSE微服務(wù)治理。
安裝MSE Ingress Controller組件并授予相關(guān)權(quán)限。具體操作,請(qǐng)參見(jiàn)安裝組件,為MSE Ingress Controller授權(quán)。
使用限制
由于全鏈路灰度功能整合了標(biāo)簽路由功能,因此不推薦已經(jīng)加入全鏈路流量控制的應(yīng)用配置金絲雀發(fā)布和標(biāo)簽路由規(guī)則。
全鏈路灰度能力支持的Java版本及框架詳見(jiàn)微服務(wù)治理支持的Java框架。
背景信息
在微服務(wù)場(chǎng)景中,當(dāng)您部署的Spring Cloud應(yīng)用或Dubbo應(yīng)用存在升級(jí)版本時(shí),由于應(yīng)用之間的調(diào)用是隨機(jī)的,會(huì)導(dǎo)致無(wú)法將具有一定特征的流量路由到應(yīng)用的目標(biāo)版本。全鏈路流量控制功能將應(yīng)用的相關(guān)版本隔離成一個(gè)獨(dú)立的運(yùn)行環(huán)境(即泳道),通過(guò)設(shè)置Ingress路由規(guī)則,將滿足規(guī)則的請(qǐng)求流量路由到目標(biāo)版本應(yīng)用。
全鏈路灰度場(chǎng)景
本文以電商架構(gòu)中的下單場(chǎng)景為例,介紹從MSE Ingress網(wǎng)關(guān)到微服務(wù)的全鏈路流控功能。假設(shè)應(yīng)用的架構(gòu)由MSE Ingress網(wǎng)關(guān)以及后端的微服務(wù)架構(gòu)(Spring Cloud)組成,后端調(diào)用鏈路有3個(gè):交易中心(A)、商品中心(B)和庫(kù)存中心(C),可以通過(guò)客戶端或者是HTML來(lái)訪問(wèn)后端服務(wù),這些服務(wù)之間通過(guò)Nacos注冊(cè)中心實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)。
客戶下單后流量從MSE Ingress網(wǎng)關(guān)進(jìn)入,先調(diào)用交易中心(A),然后交易中心(A)再調(diào)用商品中心(B),最后商品中心(B)再調(diào)用下游的庫(kù)存中心(C)。調(diào)用鏈路從左到右依次為:客戶->MSE Ingress->A->B->C。
隨著業(yè)務(wù)不斷迭代,功能也不斷更新。在新版本正式上線之前,需要同時(shí)對(duì)應(yīng)用A和應(yīng)用C進(jìn)行灰度驗(yàn)證,確認(rèn)無(wú)誤后方可正式上線。新功能上線過(guò)程中,涉及到應(yīng)用A和應(yīng)用C同時(shí)發(fā)布新版本。通過(guò)MSE Ingress網(wǎng)關(guān)和MSE微服務(wù)治理提供的全鏈路灰度能力,您可以端到端的構(gòu)建從網(wǎng)關(guān)到多個(gè)后端服務(wù)的全鏈路灰度,控制具有一定特征的灰度流量始終路由到應(yīng)用對(duì)應(yīng)的灰度環(huán)境,滿足您同時(shí)灰度驗(yàn)證多個(gè)服務(wù)的訴求。此外,在應(yīng)用無(wú)目標(biāo)灰度版本時(shí),自動(dòng)容災(zāi)到正式環(huán)境中。
名詞解釋
泳道
為相同版本應(yīng)用定義的一套隔離環(huán)境。只有滿足了流控路由規(guī)則的請(qǐng)求流量才會(huì)路由到對(duì)應(yīng)泳道里的打標(biāo)應(yīng)用。一個(gè)應(yīng)用可以屬于多個(gè)泳道,一個(gè)泳道可以包含多個(gè)應(yīng)用,應(yīng)用和泳道是多對(duì)多的關(guān)系。
泳道組
泳道的集合。泳道組的作用主要是為了區(qū)分不同團(tuán)隊(duì)或不同場(chǎng)景。
MSE Ingress網(wǎng)關(guān)
MSE Ingress網(wǎng)關(guān)是在MSE云原生網(wǎng)關(guān)基礎(chǔ)上提供的Ingress流量管理方式,兼容Nginx Ingress以及超50種Nginx Ingress注解,支持多服務(wù)版本同時(shí)灰度發(fā)布。同時(shí),靈活的服務(wù)治理能力以及全方位的安全防護(hù)保障,可以滿足大規(guī)模云原生分布式應(yīng)用的流量治理訴求。更多信息,請(qǐng)參見(jiàn)MSE Ingress概覽。
準(zhǔn)備工作
開(kāi)啟MSE微服務(wù)治理
開(kāi)通微服務(wù)治理專業(yè)版。
具體操作,請(qǐng)參見(jiàn)開(kāi)通MSE微服務(wù)治理。
為應(yīng)用開(kāi)啟微服務(wù)治理。
- 登錄MSE治理中心控制臺(tái)。
- 在左側(cè)導(dǎo)航欄,選擇 。在目標(biāo)集群操作列,單擊管理。
- 在集群詳情頁(yè)面,在目標(biāo)命名空間操作列,單擊開(kāi)啟微服務(wù)治理。然后單擊確定。
部署Demo應(yīng)用程序
在控制臺(tái)左側(cè)導(dǎo)航欄,單擊集群。
在集群列表頁(yè)面,單擊目標(biāo)集群名稱或者目標(biāo)集群右側(cè)操作列下的詳情。
在集群管理頁(yè)左側(cè)導(dǎo)航欄,選擇 。
在無(wú)狀態(tài)頁(yè)面,選擇命名空間,然后單擊使用YAML創(chuàng)建資源。
對(duì)模板進(jìn)行相關(guān)配置,完成配置后單擊創(chuàng)建。
本文示例中部署一個(gè)Nacos Server應(yīng)用,用于實(shí)現(xiàn)服務(wù)發(fā)現(xiàn),部署A、B、C三個(gè)應(yīng)用。其中A和C應(yīng)用分別部署一個(gè)基線版本和一個(gè)灰度版本,B應(yīng)用部署一個(gè)基線版本。
部署Nacos Server應(yīng)用。
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 # Nacos Server Service配置 --- apiVersion: v1 kind: Service metadata: name: nacos-server spec: ports: - port: 8848 protocol: TCP targetPort: 8848 selector: app: nacos-server type: ClusterIP
部署A應(yīng)用
基線(base)版本的YAML如下。
apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-a spec: replicas: 2 selector: matchLabels: app: spring-cloud-a template: metadata: labels: app: spring-cloud-a msePilotAutoEnable: 'on' msePilotCreateAppName: 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-governance-demo/spring-cloud-a:3.0.1 imagePullPolicy: Always name: spring-cloud-a ports: - containerPort: 20001 livenessProbe: tcpSocket: port: 20001 initialDelaySeconds: 10 periodSeconds: 30
灰度(gray)版本的YAML如下。
apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-a-gray spec: replicas: 2 selector: matchLabels: app: spring-cloud-a-gray strategy: template: metadata: labels: app: spring-cloud-a-gray msePilotAutoEnable: 'on' alicloud.service.tag: gray msePilotCreateAppName: 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-governance-demo/spring-cloud-a:3.0.1 imagePullPolicy: Always name: spring-cloud-a-gray ports: - containerPort: 20001 livenessProbe: tcpSocket: port: 20001 initialDelaySeconds: 10 periodSeconds: 30
部署B(yǎng)應(yīng)用
基線(base)版本的YAML如下。
apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-b spec: replicas: 2 selector: matchLabels: app: spring-cloud-b strategy: template: metadata: labels: app: spring-cloud-b msePilotAutoEnable: 'on' msePilotCreateAppName: 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-governance-demo/spring-cloud-b:3.0.1 imagePullPolicy: Always name: spring-cloud-b ports: - containerPort: 8080 livenessProbe: tcpSocket: port: 20002 initialDelaySeconds: 10 periodSeconds: 30
部署C應(yīng)用
基線(base)版本的YAML如下。
apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-c spec: replicas: 2 selector: matchLabels: app: spring-cloud-c template: metadata: labels: app: spring-cloud-c msePilotAutoEnable: 'on' msePilotCreateAppName: 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-governance-demo/spring-cloud-c:3.0.1 imagePullPolicy: Always name: spring-cloud-c ports: - containerPort: 8080 livenessProbe: tcpSocket: port: 20003 initialDelaySeconds: 10 periodSeconds: 30
灰度(gray)版本的YAML如下。
apiVersion: apps/v1 kind: Deployment metadata: name: spring-cloud-c-gray spec: replicas: 2 selector: matchLabels: app: spring-cloud-c-gray template: metadata: labels: app: spring-cloud-c-gray msePilotAutoEnable: 'on' alicloud.service.tag: gray msePilotCreateAppName: 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-governance-demo/spring-cloud-c:3.0.1 imagePullPolicy: IfNotPresent name: spring-cloud-c-gray ports: - containerPort: 8080 livenessProbe: tcpSocket: port: 20003 initialDelaySeconds: 10 periodSeconds: 30
針對(duì)入口應(yīng)用A,配置兩個(gè)K8s Service。
- 登錄容器服務(wù)控制臺(tái)。
在集群管理頁(yè)左側(cè)導(dǎo)航欄,選擇 。
在服務(wù)頁(yè)面,選擇命名空間,然后單擊使用YAML創(chuàng)建資源,對(duì)模板進(jìn)行相關(guān)配置,完成配置后單擊創(chuàng)建。
spring-cloud-a-base對(duì)應(yīng)A的base版本。
apiVersion: v1 kind: Service metadata: name: spring-cloud-a-base spec: ports: - name: http port: 20001 protocol: TCP targetPort: 20001 selector: app: spring-cloud-a
spring-cloud-a-gray對(duì)應(yīng)A的gray版本。
apiVersion: v1 kind: Service metadata: name: spring-cloud-a-gray spec: ports: - name: http port: 20001 protocol: TCP targetPort: 20001 selector: app: spring-cloud-a-gray
步驟一:創(chuàng)建泳道組
登錄MSE治理中心控制臺(tái),并在頂部菜單欄選擇地域。
在左側(cè)導(dǎo)航欄,選擇治理中心 > 全鏈路灰度。
在全鏈路灰度頁(yè)面,單擊創(chuàng)建泳道組及泳道。如果您選擇的微服務(wù)空間內(nèi)已經(jīng)創(chuàng)建過(guò)泳道組,則單擊+創(chuàng)建泳道組。
在創(chuàng)建泳道組面板,設(shè)置泳道組相關(guān)參數(shù),然后單擊確定。
配置項(xiàng)
說(shuō)明
泳道組名稱
自定義設(shè)置泳道組的名稱。
入口類型
選擇Ingress/自建網(wǎng)關(guān)。
泳道組涉及應(yīng)用
選擇您的入口應(yīng)用或入口網(wǎng)關(guān)所涉及的所有相關(guān)服務(wù)。
泳道組創(chuàng)建完成后,請(qǐng)檢查入口應(yīng)用和所涉及的應(yīng)用是否正確。您可以在全鏈路灰度頁(yè)面的泳道組及涉及的應(yīng)用區(qū)域,查看您已創(chuàng)建的泳道組。如需變更泳道組信息,請(qǐng)單擊右側(cè)的圖標(biāo)并修改相關(guān)信息。
步驟二:創(chuàng)建泳道
在全鏈路灰度頁(yè)面頂部,選擇和泳道組相同的地域,然后在頁(yè)面底部單擊點(diǎn)擊創(chuàng)建第一個(gè)分流泳道。
如果您選擇的微服務(wù)空間內(nèi)已經(jīng)創(chuàng)建過(guò)泳道,則單擊創(chuàng)建泳道。
重要加入全鏈路流量控制的應(yīng)用,不推薦使用金絲雀發(fā)布和標(biāo)簽路由功能。
在創(chuàng)建泳道面板,設(shè)置流控泳道相關(guān)參數(shù),然后單擊確定。
重要如果您的網(wǎng)關(guān)應(yīng)用是Ingress網(wǎng)關(guān),需要在容器服務(wù)管理控制臺(tái)配置Ingress路由規(guī)則。
配置項(xiàng)
說(shuō)明
配置節(jié)點(diǎn)標(biāo)簽
配置方式:在容器ACK控制臺(tái)中,在應(yīng)用YAML的
spec.template.metadata.labels
下增加alicloud.service.tag: ${tag}
。設(shè)置標(biāo)簽名:并為
spec.template.metadata.labels
增加如下兩個(gè)key-value鍵值對(duì)。msePilotCreateAppName:${AppName}
alicloud.service.tag:{tag}
泳道名稱
自定義設(shè)置流控泳道的名稱。
泳道標(biāo)簽
完成配置節(jié)點(diǎn)標(biāo)簽后,下拉框中會(huì)出現(xiàn)相應(yīng)的標(biāo)簽列表,選擇對(duì)應(yīng)的標(biāo)簽,則會(huì)自動(dòng)添加相應(yīng)的應(yīng)用。
完成泳道創(chuàng)建后,在全鏈路灰度的流量分配區(qū)域,可以查看或配置泳道信息。
單擊圖標(biāo),查看該泳道的流量比例。
單擊圖標(biāo),可在泳道列表的操作列,設(shè)置該泳道應(yīng)用的狀態(tài)。
開(kāi)啟泳道:?jiǎn)螕?b data-tag="uicontrol" id="uicontrol-jgo-s77-qiw" class="uicontrol">開(kāi)啟,創(chuàng)建的泳道將會(huì)生效,即流量會(huì)按照泳道方式進(jìn)行流轉(zhuǎn),滿足規(guī)則的流量會(huì)優(yōu)先流向標(biāo)記有當(dāng)前泳道對(duì)應(yīng)標(biāo)簽的應(yīng)用版本,如果沒(méi)有對(duì)應(yīng)標(biāo)簽的應(yīng)用版本則流向未打標(biāo)的應(yīng)用版本。
關(guān)閉泳道:?jiǎn)螕?b data-tag="uicontrol" id="uicontrol-fs2-i1k-0la" class="uicontrol">關(guān)閉,關(guān)閉創(chuàng)建的泳道,即該應(yīng)用往后的流量會(huì)流向未打標(biāo)的應(yīng)用版本。
修改泳道:?jiǎn)螕?b data-tag="uicontrol" id="uicontrol-wbp-438-if4" class="uicontrol">編輯,修改當(dāng)前泳道的配置信息。
刪除泳道:?jiǎn)螕?b data-tag="uicontrol" id="uicontrol-z5o-4rq-xkt" class="uicontrol">刪除,刪除目標(biāo)泳道。
步驟三:配置基線環(huán)境的Ingress規(guī)則
如果業(yè)務(wù)域名為example.com
,訪問(wèn)example.com
的請(qǐng)求流量只通過(guò)基線環(huán)境(線上環(huán)境),可以通過(guò)如下代碼配置基線環(huán)境的Ingress規(guī)則。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-cloud-a
namespace: default
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: spring-cloud-a-base
port:
number: 20001
path: /
pathType: Prefix
使用curl命令訪問(wèn)example.com
路由到基線環(huán)境。
curl -H "host: example.com" http://47.98.xxx.xx/a
返回結(jié)果如下:
A[192.168.0.98][config=base] -> B[192.168.0.157] -> C[192.168.0.161]
步驟四:配置灰度環(huán)境的Ingress規(guī)則
如果基于Header策略來(lái)區(qū)分線上正式流量和灰度流量,希望帶有HTTP Header為x-user-id: 100
的請(qǐng)求流量訪問(wèn)example.com
路由到灰度環(huán)境中,流量會(huì)優(yōu)先訪問(wèn)鏈路中各個(gè)應(yīng)用對(duì)應(yīng)的灰度版本,若無(wú)灰度版本,則會(huì)容災(zāi)到基線版本。通過(guò)如下代碼配置灰度環(huán)境的Ingress規(guī)則。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: x-user-id
nginx.ingress.kubernetes.io/canary-by-header-value: '100'
mse.ingress.kubernetes.io/request-header-control-update: x-mse-tag gray
name: spring-cloud-a-gray
namespace: default
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: spring-cloud-a-gray
port:
number: 20001
path: /
pathType: Prefix
上述代碼使用注解實(shí)現(xiàn)路由灰度發(fā)布、Header配置以及Header控制能力。關(guān)于注解的更多用法,請(qǐng)參見(jiàn)MSE Ingress高級(jí)用法。
使用curl命令訪問(wèn)example.com
路由到灰度環(huán)境,其中帶有HTTP Header為x-user-id: 100
的請(qǐng)求流量。
curl -H "host: example.com" -H "x-user-id: 100" http://47.98.xxx.xx/a
返回結(jié)果如下。灰度流量?jī)?yōu)先訪問(wèn)了A和C的灰度版本,由于B沒(méi)有灰度版本,所以訪問(wèn)了B的基線版本。
Agray[192.168.0.128][config=base] -> B[192.168.0.152] -> Cgray[192.168.0.151]
控制臺(tái)查看應(yīng)用的流量監(jiān)控圖
查看單個(gè)應(yīng)用的監(jiān)控圖
在全鏈路灰度頁(yè)面,單擊目標(biāo)泳道組頁(yè)簽。
在泳道組及涉及的應(yīng)用區(qū)域,單擊目標(biāo)應(yīng)用名稱,在右側(cè)會(huì)出現(xiàn)對(duì)應(yīng)的QPS數(shù)據(jù)
查看泳道組內(nèi)所有應(yīng)用的監(jiān)控圖。
在全鏈路灰度頁(yè)面,單擊目標(biāo)泳道組頁(yè)簽。
在應(yīng)用 QPS 監(jiān)控右側(cè),單擊查看流量詳情,可以查看該泳道所有應(yīng)用的流量監(jiān)控圖。