當您需要在多個服務間實現全鏈路的灰度發布時,可以通過配置TrafficLabel來識別流量特征,將網關入口流量分為正常流量和灰度流量。灰度流量特征會在請求調用鏈經過的各個服務間進行傳遞,從而實現全鏈路灰度發布。本文介紹如何通過TrafficLabel實現微服務的全鏈路灰度發布。
前提條件
已添加集群到ASM實例。具體操作,請參見添加集群到ASM實例。
已創建ASM網關。具體操作,請參見創建入口網關。
功能介紹
灰度發布有多種實現方式,例如基于ASM完成藍綠和灰度發布。該灰度方式偏重于單個服務的發布,通過使用Istio原生提供的VirtualService標簽路由和權重分流進行實現。某些場景下,僅限于兩個服務間的灰度不能滿足需求。
ASM基于流量打標和標簽路由功能,提供全鏈路灰度功能,幫助您解決多個服務同時發布灰度版本的問題。當業務進行功能灰度驗證時,將入口流量分為正常流量和灰度流量,對請求流量進行流量特征識別。若請求流量為灰度流量,則將請求灰度的應用服務。該場景不再是簡單的按流量比例灰度分發到后端不同的版本,而且灰度流量特征會在請求調用鏈經過的各個服務間進行傳遞。更多信息,請參見流量標簽TrafficLabel說明。
配置說明
您可以單擊配置文件,直接下載部署示例及相關配置文件。示例中應用服務調用鏈路如下:
本示例服務中的應用A在調用B時,已包含傳播HTTP標頭my-trace-id的代碼實現邏輯。更多信息,請參見配置文件中的src/mock-abc/go/main.go。
如果您使用其他的應用示例,請確保在調用中包含傳播HTTP標頭的邏輯,后續的功能依賴于這個傳播的HTTP標頭。
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-base
labels:
app: mocka
version: base
spec:
replicas: 1
selector:
matchLabels:
app: mocka
version: base
template:
metadata:
labels:
app: mocka
version: base
spec:
containers:
- name: default
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
imagePullPolicy: Always
env:
- name: version
value: base
- 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-base
labels:
app: mockb
version: base
spec:
replicas: 1
selector:
matchLabels:
app: mockb
version: base
template:
metadata:
labels:
app: mockb
version: base
spec:
containers:
- name: default
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
imagePullPolicy: Always
env:
- name: version
value: base
- name: app
value: mockb
ports:
- containerPort: 8000
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-canary
labels:
app: mocka
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: mocka
version: canary
template:
metadata:
labels:
app: mocka
version: canary
spec:
containers:
- name: default
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
imagePullPolicy: Always
env:
- name: version
value: canary
- 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-canary
labels:
app: mockb
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: mockb
version: canary
template:
metadata:
labels:
app: mockb
version: canary
spec:
containers:
- name: default
image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
imagePullPolicy: Always
env:
- name: version
value: canary
- name: app
value: mockb
ports:
- containerPort: 8000
步驟一:在ACK集群下部署示例應用
步驟二:初始化路由規則配置
使用以下內容,創建routing.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: simple-gateway spec: selector: istio: ingressgateway servers: - hosts: - "*" port: name: http number: 80 protocol: HTTP --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: dr-mocka spec: host: mocka trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - labels: version: base name: version-base - labels: version: canary name: version-canary --- apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: dr-mockb spec: host: mockb trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - labels: version: base name: version-base - labels: version: canary name: version-canary --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-gateway-mocka spec: gateways: - simple-gateway hosts: - "*" http: - route: - destination: host: mocka --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-mockb spec: hosts: - mockb http: - route: - destination: host: mockb
使用ASM實例的KubeConfig,執行以下命令,配置路由。
kubectl apply -n default -f routing.yaml
驗證服務訪問是否可以連通。
執行以下命令,設置環境變量。
xxxx
為上一步獲取的IP。export ASM_GATEWAY_IP=xxxx
執行以下命令,驗證服務訪問是否可以連通。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-base' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
預期輸出表明從ASM入口網關到應用服務A,以及從應用A調用B的過程,負載均衡是隨機的路由策略。 通過
curl
命令指定的my-asm-prefer-tag
或者其他請求頭都不會改變隨機路由的策略。
步驟三:為示例應用設置流量標簽
ASM支持通過TrafficLabel CRD設置流量標簽,然后根據流量標簽將流量路由到不同的工作負載。更多信息,請參見流量標簽TrafficLabel說明。
使用以下內容,創建trafficlabel.yaml文件。
apiVersion: istio.alibabacloud.com/v1 kind: TrafficLabel metadata: name: trafficlabel-ns namespace: default spec: rules: - labels: - name: asm-labels-sample valueFrom: - $getExternalInboundRequestHeader(my-asm-prefer-tag, my-trace-id) --- apiVersion: istio.alibabacloud.com/v1 kind: TrafficLabel metadata: name: ingressgateway namespace: istio-system spec: rules: - labels: - name: asm-labels-sample valueFrom: - $getInboundRequestHeader(my-asm-prefer-tag) workloadSelector: labels: istio: ingressgateway
配置說明如下:
TrafficLabel
trafficlabel-ns
配置針對命名空間default下所有的應用服務生效,即示例中部署的mocka和mockb服務;TrafficLabelingressgateway
針對網關ingressgateway生效。用于區分版本的請求頭為
my-asm-prefer-tag
,因此getExternalInboundRequestHeader
中的第一個參數對應設置為my-asm-prefer-tag
。請您根據實際情況進行修改。傳播的HTTP標頭為
my-trace-id
,因此getExternalInboundRequestHeader
中的第二個參數對應設置為my-trace-id
。請您根據實際情況進行修改。
使用ASM實例的KubeConfig,執行以下命令,部署TrafficLabel。
kubectl apply -f trafficlabel.yaml
步驟四:配置標簽路由規則
您可以通過配置標簽路由規則,控制流量的走向。
一、驗證服務提供側的灰度
驗證應用A→B的調用是否符合預期,其中包括流向A的灰度流量打到灰度版本,以及Base流量打到Base版本。
配置應用B的基于流量標簽的路由規則后,流量示意圖如下。
使用以下內容,創建vs-tf-mockb.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-mockb spec: hosts: - mockb http: - route: - destination: host: mockb subset: $asm-labels-sample
執行以下命令,在A服務側生效路由規則。
kubectl apply -n default -f vs-tf-mockb.yaml
執行以下命令,驗證流向A的灰度流量打到灰度版本。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-canary' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54)
執行以下命令,驗證流向A的Base流量打到Base版本。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-base' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70) -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
預期輸出表明入口流量訪問A服務未流向指定版本。您需要配置A服務的基于流量標簽的路由規則。具體操作,請參見下一步。
二、驗證全鏈路灰度
配置A服務的TrafficLabel路由vs-tf-mocka.yaml,在ASM網關側生效。預期結果為入口請求灰度流量打到A的灰度版本,Base流量打到A的Base版本,并傳遞到B服務。
配置應用A的基于流量標簽的路由規則后,流量示意圖如下。
使用以下示例,創建文件vs-tf-mocka.yaml。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-gateway-mocka spec: gateways: - simple-gateway hosts: - "*" http: - route: - destination: host: mocka subset: $asm-labels-sample
執行以下命令,在ASM網關側生效路由規則。
kubectl apply -n default -f vs-tf-mocka.yaml
執行以下命令,驗證入口請求灰度流量打到A的灰度版本。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-canary' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
執行以下命令,驗證Base流量打到A的Base版本,并傳遞到B服務。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-base' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
三、驗證路由權重
當在應用A上配置基于權重與基于流量標簽的路由規則后,流量示意圖如下。
使用以下內容,創建vs-tf-mocka-90-10.yaml文件。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: vs-gateway-mocka spec: gateways: - simple-gateway hosts: - "*" http: - route: - destination: host: mocka subset: version-base weight: 90 - destination: host: mocka subset: $asm-labels-sample weight: 10
執行以下命令,在ASM網關側生效路由規則。
kubectl apply -n default -f vs-tf-mocka-90-10.yaml
執行以下命令,驗證入口請求灰度流量打到應用A的版本。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-canary' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130) -> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
由預期輸出得到,入口請求灰度流量約90%左右流向應用A的Base版本,10%左右流向到Canary版本。在上述生效的路由規則中,90%的請求進入應用A的Base版本,剩下的10%請求按照指定的請求頭
my-asm-prefer-tag
的值來決定去向,而請求命令中指定version-canary
為請求頭my-asm-prefer-tag
的值,即這10%的請求將流向Canary版本。執行以下命令,驗證入口請求的Base版本流量全部轉到應用A的Base版本。
for i in {1..200}; do curl -H'my-asm-prefer-tag: version-base' -H'my-trace-id: x000'$i http://${ASM_GATEWAY_IP}/; echo; sleep 1; done;
預期輸出:
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93) -> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
上述生效的路由規則中,90%的請求進入Base版本,剩下的10%請求按照指定的請求頭
my-asm-prefer-tag
的值來決定去向,而請求命令中指定version-base
為請求頭my-asm-prefer-tag
的值,即這10%的請求將流向Base版本。