前言
上一小節,istio成功的安裝,並且還解決了常見的426的問題,本節內容主要探討一下istio關於流量轉發的問題
按比例分發
配置
需要創建一個backend-v1,它與backend的selector都是app: backend,backend-v1部署完成之後,它會立即分走50%的流量,為了測試istio流控,我們需要在不改變任何配置的情況下實現9:1分流,也就是90%進入原backend,10%進入新的backend-v1

-
標記2個deployment,追加標籤,backend為
version: v0,backend-v1為version: v1kubectl patch deployment backend -p '{"spec":{"template":{"metadata":{"labels":{"version":"v0"}}}}}' kubectl patch deployment backend-v1 -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}' -
創建istio資源:DestinationRule,該資源主要用來標記istio要往哪個地方轉發
apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: backend-dr namespace: default spec: host: backend-service subsets: - labels: version: v0 name: v0 - labels: version: v1 name: v1 -
創建istio資源:VirtualService,該資源用來確定轉發的權重
apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: backend-vs namespace: default spec: hosts: - backend-service http: - route: - destination: host: backend-service subset: v0 weight: 90 - destination: host: backend-service subset: v1 weight: 10
調試
-
測試命令:
for i in {1..10}; do curl -s 10.22.12.178:30785/test > /dev/null ; done -
登錄到k8s的istio-proxy控制枱查看:
kubectl logs -f -l app=backend -c istio-proxy[2026-01-28T08:24:55.670Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default [2026-01-28T08:24:55.687Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default [2026-01-28T08:24:55.706Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default [2026-01-28T08:24:55.741Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default [2026-01-28T08:24:55.751Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default [2026-01-28T08:24:55.759Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default [2026-01-28T08:24:55.696Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default [2026-01-28T08:24:55.716Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default [2026-01-28T08:24:55.725Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default [2026-01-28T08:24:55.734Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default▶ kubectl get pod -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES backend-86b958bdc-5zjgn 2/2 Running 0 21m 10.244.0.53 wilson <none> <none> backend-v1-75ccff86dc-sl6bt 2/2 Running 0 119s 10.244.0.55 wilson <none> <none> nginx-test-7d87875694-8vsrp 2/2 Running 0 30m 10.244.0.61 wilson <none> <none> -
明顯不對,10.244.0.55與10.244.0.53的比例並沒有呈現9:1,轉發到backend要backend-v1還是5:5
修復
可以直接修改nginx的配置
server {
listen 80;
listen [::]:80;
server_name localhost;
location /test {
proxy_http_version 1.1;
# proxy_set_header Host $host; # 原配置
proxy_set_header Host backend-service.default.svc.cluster.local; # 新配置
proxy_pass http://backend-service:10000;
}
}
重啓之後再次測試:
[2026-01-28T08:30:59.968Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:30:59.988Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default
[2026-01-28T08:31:00.027Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default
[2026-01-28T08:31:00.037Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:31:00.048Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:31:00.056Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:31:00.008Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
[2026-01-28T08:31:00.066Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:31:00.074Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
[2026-01-28T08:31:00.083Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
已經生效了,這次只有1次10.244.0.55:10000
疑問
有位大哥説了,如果這樣配置的,明顯影響了業務:
- nginx的配置被修改了
- 所有的host被寫死了,都成了:backend-service.default.svc.cluster.local,而後端業務是需要把客户端的host帶入過去的,改了之後後端業務收到嚴重影響
確實,固定host屬於粗暴簡單的寫法,還有更加驚喜的解決方法,調整VirtualService,添加hosts
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com # 新增
http:
- route:
- destination:
host: backend-service
subset: v0
weight: 90
- destination:
host: backend-service
subset: v1
weight: 10
客户端訪問的時候必須帶上該域名: for i in {1..10}; do curl -s -H 'host: api.wilsontest.com' 10.22.12.178:30785/test > /dev/null ; done
這樣也可以解決問題,不過坑點也來了,年久失修,從無數前人繼承的祖傳代碼,就需要好好的梳理到底有哪些host來訪問,否則漏掉host的話,就會出現配置問題。-_-!
再次凸顯了istio之中,host是非常非常重要的,Istio 的路由決策、Service 的匹配完全依賴 Host 頭
- Istio 的 VirtualService 本質上是一個“增強版”的路由器。如果發現請求的 Host 是 backend-service,就按 90:10 分配。
- 之前的配置是$host,由於客户端沒有傳輸host,當請求經過 Nginx 的 Sidecar時,它會檢查Host,發現為空。由於路由表裏沒有對應的記錄 ,sidecar並不認識,按普通 K8s 流量處理
按header分發
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com
http:
- match:
- headers:
hellotest:
exact: "true"
route:
- destination:
host: backend-service
subset: v1
- route:
- destination:
host: backend-service
subset: v0
curl -s -H 'host: api.wilsontest.com' -H 'hellotest: true' 10.22.12.178:30785/test。只有header裏面匹配了hellotest: true才會去v1,否則全部去v0
按前綴分發
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com
http:
- match:
- uri:
prefix: /test/v1
route:
- destination:
host: backend-service
subset: v1
- route:
- destination:
host: backend-service
subset: v0
帶有/test/v1前綴的都會去新版本v1,滿足不了條件都會走默認的版本v0
url改寫
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: backend-vs
namespace: default
spec:
hosts:
- backend-service
- api.wilsontest.com
http:
- match:
- uri:
prefix: /test/v1
route:
- destination:
host: backend-service
subset: v1
- match:
- uri:
prefix: /test/v2
rewrite:
uri: /test
route:
- destination:
host: backend-service
subset: v0
- route:
- destination:
host: backend-service
subset: v0
如果是/test/v1,就訪問v1版本,/test/v2重寫成/test並且訪問v0版本,其餘的默認都會走v0版本
藍綠、金絲雀、灰度、A/B測試
關於流量分流的各種操作,大部分都集中在以下場景:
- 藍綠:實現瞬間切換與零宕機回滾,消除發佈期間的中間狀態
- 金絲雀:像礦工用金絲雀探測毒氣一樣,先讓一小部分用户(如1%~5%)訪問新版本,觀察系統指標(如錯誤率、延遲),若無問題再逐步擴大範圍
- 灰度:將用户羣體按比例或特定規則(如地域、設備)逐步切換到新版本(例如10%→30%→100%),持續觀察反饋
- A/B:同時向隨機分組的用户展示不同版本(A組用舊版,B組用新版),通過統計指標(如點擊率、轉化率)判斷哪個版本更優
| 藍綠髮布 | 金絲雀發佈 | 灰度發佈 | A/B測試 | |
|---|---|---|---|---|
| 主要目標 | 零停機、瞬時回滾 | 用真實流量快速發現技術風險 | 平穩、可控地逐步替換所有用户 | 驗證不同版本的業務效果 |
| 流量路由 | 全量切換(100%→0%) | 極小比例引流(如1%-5%) | 按比例分階段擴大(10%→50%→100%) | 按規則/隨機分配(如50%/50%) |
| 關注重點 | 系統可用性與回滾速度 | 系統穩定性指標(錯誤率、延遲) | 發佈過程平穩性與綜合反饋 | 業務指標(轉化率、留存率) |
| 所需資源 | 兩套完整環境,成本高 | 一套環境,新版本實例較少 | 一套環境,新舊版本實例共存 | 一套或多套環境,並行運行多個版本 |
| 用户選擇 | 全體用户同時切換 | 小部分用户隨機或按基礎設施選擇 | 用户按比例或屬性逐步遷移 | 用户隨機分組或按屬性定向分配 |
| 持續時間 | 極短(切換在幾分鐘內) | 短(幾小時到一天) | 中長(幾天到數週) | 長(數週到數月) |
| 典型場景 | 關鍵業務大版本升級、基礎設施更換 | 後端服務、中間件、數據庫變更 | 前端功能、用户界面更新 | UI設計、文案、算法策略、定價優化 |
聯繫我
- 聯繫我,做深入的交流

至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...