本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 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 服務選擇器將其包含在迴圈負載平衡演算法中。這也是 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% 的評論流量僅傳送到 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 Pod 相應地向上伸縮,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 評級服務是一個外部付費服務——例如,爛番茄®——提供每秒 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 例項,將傳入屬性對映到配額維度,並建立一個使用 memquota 處理程式的 rule

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 個請求),瀏覽器流量會被切斷。頁面現在顯示一條訊息,指示評級當前不可用,而不是每個評論旁邊的黑色星級。

停止負載生成器意味著不再超出限制:當我們重新整理頁面時,黑色星級會返回。

總結

我們已經向您展示瞭如何在配置了 Istio 的服務網格中引入 HTTP 請求路由和策略注入等高階功能,而無需重新啟動任何服務。這使您可以在開發和部署時無需擔心服務網格的持續管理;服務範圍的策略可以隨時新增。

在本系列的下一篇也是最後一篇文章中,我們將重點介紹 Istio 的安全和認證功能。我們將討論如何在網格中保護所有服務間通訊,即使是網路內部人員的訪問,而無需更改應用程式程式碼或部署。