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

使用 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 的安全性和身份驗證功能。我們將討論如何保護網格中的所有服務間通信,即使是針對可以訪問網路的內部人員,而無需對應用程式程式碼或部署進行任何更改。