場(chǎng)景三:在鏈路中透?jìng)鰾aggage請(qǐng)求頭
您可以使用寬松模式的流量泳道實(shí)現(xiàn)應(yīng)用版本隔離,基于Baggage請(qǐng)求頭透?jìng)饕髡?qǐng)求頭,并將流量路由到不同泳道。泳道中服務(wù)相互調(diào)用時(shí),若目標(biāo)服務(wù)不存在當(dāng)前泳道則轉(zhuǎn)發(fā)至基線泳道,保障鏈路完整性,簡(jiǎn)化流量管理。
開(kāi)始閱讀前,請(qǐng)確保您已經(jīng)閱讀并理解了使用寬松模式流量泳道實(shí)現(xiàn)全鏈路流量管理及其相關(guān)的內(nèi)容。
場(chǎng)景概述
本示例使用三個(gè)服務(wù)(mocka、mockb、mockc)創(chuàng)建三條泳道(s1、s2、s3)模擬調(diào)用鏈路。基線泳道s1包含全部服務(wù),s2僅包含mocka和mockc,s3只有mockb。首先利用OpenTelemetry自動(dòng)插裝為服務(wù)啟用Baggage能力,再創(chuàng)建三條寬松模式泳道,通過(guò)流量權(quán)重策略進(jìn)行流量引導(dǎo)。
步驟一:部署示例服務(wù)
為default命名空間啟用Sidecar網(wǎng)格代理自動(dòng)注入。具體操作,請(qǐng)參見(jiàn)管理全局命名空間。
說(shuō)明關(guān)于自動(dòng)注入的更多信息,請(qǐng)參見(jiàn)配置Sidecar注入策略。
使用以下內(nèi)容,創(chuàng)建mock.yaml文件。
apiVersion: v1 kind: Service metadata: name: mocka labels: app: mocka service: mocka spec: ports: - port: 8000 name: http selector: app: mocka --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v1 labels: app: mocka version: v1 spec: replicas: 1 selector: matchLabels: app: mocka version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mocka version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: name: mockb labels: app: mockb service: mockb spec: ports: - port: 8000 name: http selector: app: mockb --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v1 labels: app: mockb version: v1 spec: replicas: 1 selector: matchLabels: app: mockb version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mockb version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: name: mockc labels: app: mockc service: mockc spec: ports: - port: 8000 name: http selector: app: mockc --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v1 labels: app: mockc version: v1 spec: replicas: 1 selector: matchLabels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mockc ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v2 labels: app: mocka version: v2 spec: replicas: 1 selector: matchLabels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v2 labels: app: mockb version: v2 spec: replicas: 1 selector: matchLabels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v2 labels: app: mockc version: v2 spec: replicas: 1 selector: matchLabels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockc ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mocka-v3 labels: app: mocka version: v3 spec: replicas: 1 selector: matchLabels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockb-v3 labels: app: mockb version: v3 spec: replicas: 1 selector: matchLabels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000 --- apiVersion: apps/v1 kind: Deployment metadata: name: mockc-v3 labels: app: mockc version: v3 spec: replicas: 1 selector: matchLabels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockc ports: - containerPort: 8000
對(duì)于每個(gè)實(shí)例服務(wù)Pod,都加入了
instrumentation.opentelemetry.io/inject-java: "true"
和instrumentation.opentelemetry.io/container-names: "default"
兩個(gè)注解,以聲明該實(shí)例服務(wù)使用Java語(yǔ)言實(shí)現(xiàn),并要求OpenTelemetry Operator對(duì)名稱為default
的容器進(jìn)行自動(dòng)插裝。執(zhí)行以下命令,部署實(shí)例服務(wù)。
kubectl apply -f mock.yaml
基于OpenTelemetry自動(dòng)插裝機(jī)制,部署的服務(wù)Pod將自動(dòng)具有在調(diào)用鏈路中傳遞Baggage的能力。
步驟二:創(chuàng)建泳道組和對(duì)應(yīng)泳道
創(chuàng)建泳道組。
登錄ASM控制臺(tái),在左側(cè)導(dǎo)航欄,選擇 。
在網(wǎng)格管理頁(yè)面,單擊目標(biāo)實(shí)例名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在流量泳道頁(yè)面,單擊創(chuàng)建泳道組,在創(chuàng)建泳道組面板中,配置相關(guān)信息,然后單擊確定。
配置項(xiàng)
說(shuō)明
泳道組名稱
本示例配置為test。
入口網(wǎng)關(guān)
選擇ingressgateway。
泳道模式
選擇寬松模式。
調(diào)用鏈路上下文透?jìng)鞣绞?/b>
選擇透?jìng)鱞aggage。
引流請(qǐng)求頭
填寫(xiě)x-asm-prefer-tag。
泳道服務(wù)
選擇目標(biāo)Kubernetes集群和default命名空間,在下方列表中選中mocka、mockb和mockc服務(wù),單擊圖標(biāo),將目標(biāo)服務(wù)添加到已選擇區(qū)域。
創(chuàng)建s1、s2、s3泳道,并分別綁定v1、v2、v3版本。
在流量泳道頁(yè)面的流量規(guī)則定義區(qū)域,單擊創(chuàng)建泳道。
在創(chuàng)建泳道對(duì)話框,配置相關(guān)信息,然后單擊確定。
配置項(xiàng)
說(shuō)明
泳道名稱
三條泳道分別配置為s1、s2、s3。
配置服務(wù)標(biāo)簽
標(biāo)簽名稱:配置為ASM_TRAFFIC_TAG。
標(biāo)簽值:三條泳道分別配置為v1、v2和v3。
添加服務(wù)
s1泳道:選擇mocka(default)、mockb(default)、mockc(default)。
s2泳道:選擇mocka(default)、mockc(default)。
s3泳道:選擇mockb(default)。
創(chuàng)建s1泳道的示例圖如下。
三個(gè)泳道創(chuàng)建完成后,示例效果如下。
默認(rèn)情況下,您在泳道組中創(chuàng)建的第一個(gè)泳道將被設(shè)定為基線泳道。您也可以修改基線泳道,當(dāng)流量發(fā)往其它泳道中不存在的服務(wù)時(shí),通過(guò)回退機(jī)制將請(qǐng)求轉(zhuǎn)發(fā)至基線泳道。關(guān)于修改基線泳道的具體操作,請(qǐng)參見(jiàn)在寬松模式中修改基線泳道。
您可以在控制臺(tái)左側(cè)導(dǎo)航欄,選擇流量管理中心 > 目標(biāo)規(guī)則或虛擬服務(wù)查看泳道組中的每個(gè)服務(wù)的泳道規(guī)則自動(dòng)生成的目標(biāo)規(guī)則DestinationRule和虛擬服務(wù)VirtualService。例如,針對(duì)mocka服務(wù)會(huì)自動(dòng)創(chuàng)建如下DestinationRule和VirtualService。
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: labels: asm-system: 'true' provider: asm swimlane-group: test name: trafficlabel-dr-test-default-mocka namespace: istio-system spec: host: mocka.default.svc.cluster.local subsets: - labels: ASM_TRAFFIC_TAG: v1 name: s1 - labels: ASM_TRAFFIC_TAG: v2 name: s2
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: labels: asm-system: 'true' provider: asm swimlane-group: test name: trafficlabel-vs-test-default-mocka namespace: istio-system spec: hosts: - mocka.default.svc.cluster.local http: - match: - headers: x-asm-prefer-tag: exact: s1 route: - destination: host: mocka.default.svc.cluster.local subset: s1 fallback: target: host: mocka.default.svc.cluster.local subset: s1 - match: - headers: x-asm-prefer-tag: exact: s2 route: - destination: host: mocka.default.svc.cluster.local subset: s2 fallback: target: host: mocka.default.svc.cluster.local subset: s1 - match: - headers: x-asm-prefer-tag: exact: s3 route: - destination: host: mocka.default.svc.cluster.local subset: s3 fallback: target: host: mocka.default.svc.cluster.local subset: s1
創(chuàng)建基于權(quán)重的統(tǒng)一引流規(guī)則。
在流量泳道頁(yè)面的流量規(guī)則定義區(qū)域,單擊引流策略中的基于權(quán)重引流。
在設(shè)定統(tǒng)一引流規(guī)則對(duì)話框中,配置相關(guān)信息,然后單擊確定。以下以泳道服務(wù)對(duì)應(yīng)入口API為/mock為例,為三條泳道配置統(tǒng)一的引流規(guī)則。
配置項(xiàng)
說(shuō)明
域名
配置為*。
匹配請(qǐng)求的URI
配置匹配方式為前綴,匹配內(nèi)容為/。
設(shè)定統(tǒng)一引流規(guī)則的示例圖如下:
設(shè)定三條泳道的引流權(quán)重,引流權(quán)重確定了流量向每條泳道發(fā)送的比例。
在流量泳道頁(yè)面的流量規(guī)則定義區(qū)域,在每條泳道的引流權(quán)重列,單擊數(shù)字右側(cè)的按鈕,在編輯引流權(quán)重對(duì)話框,配置相關(guān)信息,然后單擊確定。
配置項(xiàng)
說(shuō)明
入口服務(wù)
三條泳道都配置為mocka.default.svc.cluster.local。
權(quán)重?cái)?shù)值
對(duì)于s1泳道,配置為60。
對(duì)于s2泳道,配置為20。
對(duì)于s3泳道,配置為20。
編輯流量權(quán)重的示例圖如下。
步驟三:驗(yàn)證全鏈路灰度功能是否生效
獲取ASM網(wǎng)關(guān)的公網(wǎng)IP。具體操作,請(qǐng)參見(jiàn)獲取ASM網(wǎng)關(guān)地址。
執(zhí)行以下命令,設(shè)置環(huán)境變量。xxx.xxx.xxx.xxx為上一步獲取的IP。
export ASM_GATEWAY_IP=xxx.xxx.xxx.xxx
驗(yàn)證全鏈路灰度功能是否生效。
執(zhí)行以下命令,查看三條泳道的訪問(wèn)效果。
for i in {1..100}; do curl http://${ASM_GATEWAY_IP}/ ; echo ''; sleep 1; done;
預(yù)期輸出:
-> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v3, ip: 192.168.0.2)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v2, ip: 192.168.0.184)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v2, ip: 192.168.0.189) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190) -> mocka(version: v1, ip: 192.168.0.193)-> mockb(version: v1, ip: 192.168.0.1)-> mockc(version: v1, ip: 192.168.0.190)
可以看到,流量以約6:2:2的比例發(fā)送到s1、s2、s3泳道,并由s1作為基線泳道,當(dāng)調(diào)用鏈路中不存在某個(gè)服務(wù)的特定版本時(shí),將會(huì)調(diào)用s1泳道中的對(duì)應(yīng)服務(wù)。