本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 Istio 服務網格進行請求路由和策略管理
編者註:今天的文章是關於 Istio 的三部分系列文章中的第二篇。
在之前的文章中,我們查看了一個由四個獨立微服務組成的簡單應用程式 (Bookinfo)。文章展示了如何在不更改任何應用程式程式碼的情況下,使用 Kubernetes 和啟用 Istio 的叢集部署應用程式。文章還概述了如何查看 Istio 提供的關於運行中服務的 L7 指標。
本文繼續深入探討使用 Bookinfo 的 Istio。具體來說,我們將查看 Istio 的另外兩個功能:請求路由和策略管理。
運行 Bookinfo 應用程式
和之前一樣,我們運行 Bookinfo 應用程式的 v1 版本。在我們的叢集中安裝 Istio之後,我們使用以下命令啟動在 bookinfo-v1.yaml 中定義的應用程式
kubectl apply -f \<(istioctl kube-inject -f bookinfo-v1.yaml)
我們為應用程式創建了一個 Ingress 資源
cat \<\<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: bookinfo
annotations:
kubernetes.io/ingress.class: "istio"
spec:
rules:
- http:
paths:
- path: /productpage
backend:
serviceName: productpage
servicePort: 9080
- path: /login
backend:
serviceName: productpage
servicePort: 9080
- path: /logout
backend:
serviceName: productpage
servicePort: 9080
EOF
然後我們檢索了 Istio Ingress 控制器的 NodePort 位址
export BOOKINFO\_URL=$(kubectl get po -n istio-system -l istio=ingress -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc -n istio-system istio-ingress -o jsonpath={.spec.ports[0].nodePort})
最後,我們將瀏覽器指向 http://$BOOKINFO_URL/productpage,以查看正在運行的 v1 應用程式
HTTP 請求路由
現有的容器編排平台(如 Kubernetes、Mesos 和其他微服務框架)允許運營商控制特定的一組 pod/VM 何時應接收流量(例如,透過添加/刪除特定標籤)。與現有技術不同,Istio 將流量流與基礎架構擴展解耦。這使得 Istio 能夠提供各種駐留在應用程式程式碼之外的流量管理功能,包括用於 A/B 測試、金絲雀發布、漸進式推出的動態 HTTP 請求路由、使用超時、重試、斷路器進行 故障恢復,以及使用 故障注入 來測試跨服務的故障恢復策略的相容性。
為了示範,我們將部署 reviews 服務的 v2 版本,並使用 Istio 使其僅對特定測試使用者可見。我們可以透過 這個 YAML 檔案創建 Kubernetes 部署 reviews-v2
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: reviews-v2
spec:
replicas: 1
template:
metadata:
labels:
app: reviews
version: v2
spec:
containers:
- name: reviews
image: istio/examples-bookinfo-reviews-v2:0.2.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
從 Kubernetes 的角度來看,v2 部署增加了額外的 pod,reviews 服務選擇器將這些 pod 包含在循環負載平衡演算法中。這也是 Istio 的預設行為。
在我們啟動 reviews:v2 之前,我們將啟動 Bookinfo 四個服務中的最後一個服務 ratings,v2 版本使用它來提供與每個評論對應的評級星級
kubectl apply -f \<(istioctl kube-inject -f bookinfo-ratings.yaml)
如果我們現在啟動 reviews:v2,我們將看到瀏覽器回應在 v1(沒有相應評級的評論)和 v2(帶有黑色評級星級的評論)之間交替。但是,這不會發生,因為我們將使用 Istio 的流量管理功能來控制流量。
使用 Istio,新版本不需要根據正在運行的 pod 數量變得可見。版本可見性改為由指定確切條件的規則控制。為了示範,我們首先使用 Istio 指定我們要將 100% 的 reviews 流量僅發送到 v1 pod。
立即為網格中的每個服務設定預設規則是 Istio 的最佳實踐。這樣做可以避免意外顯示較新、可能不穩定的版本。但是,為了本次示範的目的,我們只對 reviews 服務執行此操作
cat \<\<EOF | istioctl create -f -
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v1
weight: 100
EOF
此命令指示服務網格將 reviews 服務的 100% 流量發送到標籤為「version: v1」的 pod。有了這個規則,我們可以安全地部署 v2 版本而不會公開它。
kubectl apply -f \<(istioctl kube-inject -f bookinfo-reviews-v2.yaml)
刷新 Bookinfo 網頁確認沒有任何變化。
此時,我們有多種選擇可以決定如何公開 reviews:v2。例如,如果我們想進行簡單的金絲雀測試,我們可以透過類似這樣的規則將 10% 的流量發送到 v2
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v2
weight: 10
- labels:
version: v1
weight: 90
早期測試服務版本的更好方法是更具體地限制對它的訪問。為了示範,我們將設定一個規則,僅使 reviews:v2 對特定測試使用者可見。我們透過設定第二個更高優先級的規則來做到這一點,該規則僅在請求符合特定條件時應用
cat \<\<EOF | istioctl create -f -
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-test-v2
spec:
destination:
name: reviews
precedence: 2
match:
request:
headers:
cookie:
regex: "^(.\*?;)?(user=jason)(;.\*)?$"
route:
- labels:
version: v2
weight: 100
EOF
在這裡,我們指定請求標頭需要包含一個值為「tester」的使用者 Cookie 作為條件。如果未滿足此規則,我們將回退到 v1 的預設路由規則。
如果我們使用使用者名稱「tester」(無需密碼)登入 Bookinfo UI,我們現在將看到應用程式的 v2 版本(每個評論都包含 1-5 個黑色評級星級)。每個其他使用者都不受此變更的影響。
一旦 v2 版本經過徹底測試,我們可以使用 Istio 繼續進行金絲雀測試,使用先前顯示的規則,或者我們可以簡單地將所有流量從 v1 遷移到 v2,可選擇以漸進方式透過使用權重小於 100 的規則序列(例如:10、20、30、... 100)。此流量控制與實現每個版本的 pod 數量無關。例如,如果我們有自動擴展並且流量很大,我們可能會看到 v2 的相應擴展和 v1 pod 的縮減同時獨立發生。有關使用自動擴展進行版本路由的更多資訊,請查看 「使用 Istio 進行金絲雀部署」。
在我們的例子中,我們將使用一個命令將所有流量發送到 v2
cat \<\<EOF | istioctl replace -f -
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default
spec:
destination:
name: reviews
route:
- labels:
version: v2
weight: 100
EOF
我們也應該刪除我們為測試人員創建的特殊規則,以免它覆蓋我們決定執行的任何未來推出
istioctl delete routerule reviews-test-v2
在 Bookinfo UI 中,我們將看到我們現在正在向所有使用者公開 reviews 的 v2 版本。
策略執行
Istio 提供策略執行功能,例如配額、先決條件檢查和訪問控制。我們可以透過一個範例示範 Istio 開放且可擴展的策略框架:速率限制。
讓我們假設 Bookinfo ratings 服務是一項外部付費服務——例如 Rotten Tomatoes®——免費配額為每秒 1 個請求 (req/sec)。為了確保應用程式不超過此限制,我們將指定一個 Istio 策略,一旦達到限制就切斷請求。我們將為此目的使用 Istio 的內建策略之一。
要設定 1 req/sec 配額,我們首先配置一個具有速率限制的 memquota 處理程序
cat \<\<EOF | istioctl create -f -
apiVersion: "config.istio.io/v1alpha2"
kind: memquota
metadata:
name: handler
namespace: default
spec:
quotas:
- name: requestcount.quota.default
maxAmount: 5000
validDuration: 1s
overrides:
- dimensions:
destination: ratings
maxAmount: 1
validDuration: 1s
EOF
然後我們創建一個 quota 實例,將傳入屬性映射到配額維度,並創建一個 rule,將其與 memquota 處理程序一起使用
cat \<\<EOF | istioctl create -f -
apiVersion: "config.istio.io/v1alpha2"
kind: quota
metadata:
name: requestcount
namespace: default
spec:
dimensions:
source: source.labels["app"] | source.service | "unknown"
sourceVersion: source.labels["version"] | "unknown"
destination: destination.labels["app"] | destination.service | "unknown"
destinationVersion: destination.labels["version"] | "unknown"
---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: quota
namespace: default
spec:
actions:
- handler: handler.memquota
instances:
- requestcount.quota
EOF
為了查看速率限制的實際效果,我們將在應用程式上產生一些負載
wrk -t1 -c1 -d20s http://$BOOKINFO\_URL/productpage
在網頁瀏覽器中,我們會注意到,當負載產生器正在運行時(即,產生超過 1 req/sec),瀏覽器流量被切斷。頁面現在顯示一條消息,指示評級目前不可用,而不是每個評論旁邊的黑色星級。
停止負載產生器意味著不會再超過限制:當我們刷新頁面時,黑色星級會返回。
總結
我們向您展示了如何在不重新啟動任何服務的情況下,將 HTTP 請求路由和策略注入等進階功能引入使用 Istio 配置的服務網格中。這使您可以進行開發和部署,而無需擔心服務網格的持續管理;服務範圍的策略始終可以在以後添加。
在本系列的下一篇也是最後一篇中,我們將重點介紹 Istio 的安全性和身份驗證功能。我們將討論如何保護網格中的所有服務間通信,即使是針對可以訪問網路的內部人員,而無需對應用程式程式碼或部署進行任何更改。