Istio 服務網格 Lab 環境¶
ServiceMesh 用來描述組成應用程序的微服務網絡以及它們之間的交互。隨著服務網格的規模和復雜性不斷的增長,它將會變得越來越難以理解和管理。管理微服務的非功能性需求包括服務發現、負載均衡、故障恢復、度量和監控等等。服務網格通常還有更複雜的運維需求,比如 A/B 測試、金絲雀發布、速率限制、訪問控制和端到端認證。
Istio 提供了對整個服務網格的行為洞察和操作控制的能力,以及一個完整的滿足微服務應用各種需求的解決方案。請跟隨本教程安裝、配置並深入評估 Istio 網格系統的生態系統元件。
步驟 01 - 環境安裝¶
Kubernetes¶
創建實驗 Kubernetes 集群:
k3d cluster create --servers 1 --agents 1 --api-port 6443 \
--k3s-arg "--disable=traefik@server:0" \
--port 8080:80@loadbalancer --port 8443:443@loadbalancer \
--agents-memory=8G
--disable=traefik@server:0
禁用 Traefik 負載均衡器--agents-memory=8G
額外增加一些內存
確認 Kubernetes 及 Kubectl 是否成功安裝:
(輸出結果)
Kubernetes control plane is running at https://0.0.0.0:6443
CoreDNS is running at https://0.0.0.0:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://0.0.0.0:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
Istio¶
本篇參考 Istio Getting Started 教學,官方提供的 Istioctl 工具,讓我們可透過簡單的指令就將 Istio 元件安裝至 Kubernetes ,接下來就來看看如何使用吧!
安裝 Istioctl¶
-
前往 Istio release 網站,找到需要的版本,並使用 curl 下載程式檔:
Info
本教程安裝的是 Istio
1.16.1
版本。 -
移動到 Istio 包目錄。例如,如果包是 istio-1.16.1:
安裝目錄包含:
- 示例中的示例
samples/
bin/
目錄中的istioctl
客戶端二進製文件。
- 示例中的示例
-
將
istioctl
客戶端添加到您的路徑:
安裝 Istio¶
對於此安裝,我們使用 demo
配置組合, 詳細說明見:安裝配置文件。
核心组件 | demo |
---|---|
istiod | ✔ |
istio-ingressgateway | ✔ |
istio-egressgateway | ✔ |
或是把啟動客製設定參數加上:
istioctl install --set profile=demo \
--set meshConfig.accessLogFile="/dev/stdout" \
--set meshConfig.accessLogEncoding="JSON" -y
結果:
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
確認 istio 是否成功安裝:
結果:
NAME READY STATUS RESTARTS AGE
istiod-76db9fbfc-m4vd9 1/1 Running 0 7m26s
istio-egressgateway-77cf54b878-ms8tw 1/1 Running 0 6m46s
istio-ingressgateway-7f5ddd54c8-gcjl4 1/1 Running 0 6m46s
Info
Istio 的 Control Plane 指的就是這些安裝至 istio-system 命名空間的元件
安裝相關遙測插件¶
Istio 集成了幾個不同的遙測組件。這些組件可以幫助您了解服務網格的結構、顯示網格的拓撲並分析網格的健康狀況。
使用以下說明部署 Kiali 以及 Prometheus、Grafana 和 Jaeger 的步驟。
-
安裝 Kiali 和其他插件並等待它們被部署。
執行下列命令來安裝 Kiali、Prometheus、Grafana 與 Jaeger 元件:
結果:
serviceaccount/grafana created configmap/grafana created service/grafana created deployment.apps/grafana created configmap/istio-grafana-dashboards created configmap/istio-services-grafana-dashboards created deployment.apps/jaeger created service/tracing created service/zipkin created service/jaeger-collector created serviceaccount/kiali created configmap/kiali created clusterrole.rbac.authorization.k8s.io/kiali-viewer created clusterrole.rbac.authorization.k8s.io/kiali created clusterrolebinding.rbac.authorization.k8s.io/kiali created role.rbac.authorization.k8s.io/kiali-controlplane created rolebinding.rbac.authorization.k8s.io/kiali-controlplane created service/kiali created deployment.apps/kiali created serviceaccount/prometheus created configmap/prometheus created clusterrole.rbac.authorization.k8s.io/prometheus created clusterrolebinding.rbac.authorization.k8s.io/prometheus created service/prometheus created deployment.apps/prometheus created
檢查服務佈署的狀態:
執行下列命令 >_$ kubectl get svc -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istiod ClusterIP 10.43.144.98 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 172m istio-egressgateway ClusterIP 10.43.143.51 <none> 80/TCP,443/TCP 171m istio-ingressgateway LoadBalancer 10.43.81.49 172.22.0.2,172.22.0.3 15021:31007/TCP,80:31366/TCP,443:32297/TCP,31400:32599/TCP,15443:32439/TCP 171m grafana ClusterIP 10.43.120.74 <none> 3000/TCP 32m tracing ClusterIP 10.43.112.8 <none> 80/TCP,16685/TCP 32m zipkin ClusterIP 10.43.182.146 <none> 9411/TCP 32m jaeger-collector ClusterIP 10.43.138.129 <none> 14268/TCP,14250/TCP,9411/TCP 32m kiali ClusterIP 10.43.247.206 <none> 20001/TCP,9090/TCP 32m prometheus ClusterIP 10.43.54.209 <none> 9090/TCP $ kubectl get pods -n istio-system NAME READY STATUS RESTARTS AGE istiod-76db9fbfc-m4vd9 1/1 Running 0 173m svclb-istio-ingressgateway-w6lnz 5/5 Running 0 172m svclb-istio-ingressgateway-nbldc 5/5 Running 0 172m istio-egressgateway-77cf54b878-ms8tw 1/1 Running 0 172m istio-ingressgateway-7f5ddd54c8-gcjl4 1/1 Running 0 172m jaeger-5858c698bf-wvbt8 1/1 Running 0 32m prometheus-6956c8c6c5-qknmr 2/2 Running 0 32m kiali-64c4f869fb-xzjpd 1/1 Running 0 32m grafana-6d69f655fb-jk6wm 1/1 Running 0 32m
-
訪問 Prometheus
執行下列命令來暴露 Prometheus 服務:
-
訪問 Grafana
執行下列命令來暴露 Grafana 服務:
-
訪問 Jaeger
執行下列命令來暴露 Jaeger 服務:
-
訪問 Kiali
執行下列命令來暴露 Kiali 服務:
部署範例應用程序¶
Bookinfo 應用¶
Bookinfo 示例部署了一個用於演示多種 Istio 特性的應用,該應用由四個單獨的微服務構成。
這個應用模仿在線書店的一個分類,顯示一本書的信息。頁面上會顯示一本書的描述,書籍的細節(ISBN、頁數等),以及關於這本書的一些評論。
Bookinfo 應用分為四個單獨的微服務:Bookinfo 應用
reviews 微服務有 3 個版本:
- v1 版本不會調用
ratings
服務。 - v2 版本會調用
ratings
服務,並使用 1 到 5 個黑色星形圖標來顯示評分信息。 - v3 版本會調用
ratings
服務,並使用 1 到 5 個紅色星形圖標來顯示評分信息。
下圖展示了這個應用的端到端架構。
Bookinfo 應用中的幾個微服務是由不同的語言編寫的。這些服務對 Istio 並無依賴,但是構成了一個有代表性的服務網格的例子:
- 它由多個服務
- 多個語言構成
- 並且 reviews 服務具有多個版本
部署 Bookinfo 應用¶
要在 Istio 中運行這一應用,無需對應用自身做出任何改變。您只要簡單的在 Istio 環境中對服務進行配置和運行,具體一點說就是把 Envoy sidecar 注入到每個服務之中。最終的部署結果將如下圖所示:
所有的微服務都和 Envoy sidecar 集成在一起,被集成服務所有的出入流量都被 sidecar 所劫持,這樣就為外部控制準備了所需的 Hook,然後就可以利用 Istio 控制平面為應用提供服務路由、遙測數據收集以及策略實施等功能。
-
在
default
命名空間添加標籤以指示 Istio 自動注入 Envoy sidecar 代理: -
部署 Bookinfo 示例應用程序:
Example
################################################################################################## # Details service ################################################################################################## apiVersion: v1 kind: Service metadata: name: details labels: app: details service: details spec: ports: - port: 9080 name: http selector: app: details --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-details labels: account: details --- apiVersion: apps/v1 kind: Deployment metadata: name: details-v1 labels: app: details version: v1 spec: replicas: 1 selector: matchLabels: app: details version: v1 template: metadata: labels: app: details version: v1 spec: serviceAccountName: bookinfo-details containers: - name: details image: docker.io/istio/examples-bookinfo-details-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 securityContext: runAsUser: 1000 --- ################################################################################################## # Ratings service ################################################################################################## apiVersion: v1 kind: Service metadata: name: ratings labels: app: ratings service: ratings spec: ports: - port: 9080 name: http selector: app: ratings --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-ratings labels: account: ratings --- apiVersion: apps/v1 kind: Deployment metadata: name: ratings-v1 labels: app: ratings version: v1 spec: replicas: 1 selector: matchLabels: app: ratings version: v1 template: metadata: labels: app: ratings version: v1 spec: serviceAccountName: bookinfo-ratings containers: - name: ratings image: docker.io/istio/examples-bookinfo-ratings-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 securityContext: runAsUser: 1000 --- ################################################################################################## # Reviews service ################################################################################################## apiVersion: v1 kind: Service metadata: name: reviews labels: app: reviews service: reviews spec: ports: - port: 9080 name: http selector: app: reviews --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-reviews labels: account: reviews --- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v1 labels: app: reviews version: v1 spec: replicas: 1 selector: matchLabels: app: reviews version: v1 template: metadata: labels: app: reviews version: v1 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v1:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {} --- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v2 labels: app: reviews version: v2 spec: replicas: 1 selector: matchLabels: app: reviews version: v2 template: metadata: labels: app: reviews version: v2 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v2:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {} --- apiVersion: apps/v1 kind: Deployment metadata: name: reviews-v3 labels: app: reviews version: v3 spec: replicas: 1 selector: matchLabels: app: reviews version: v3 template: metadata: labels: app: reviews version: v3 spec: serviceAccountName: bookinfo-reviews containers: - name: reviews image: docker.io/istio/examples-bookinfo-reviews-v3:1.17.0 imagePullPolicy: IfNotPresent env: - name: LOG_DIR value: "/tmp/logs" ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp - name: wlp-output mountPath: /opt/ibm/wlp/output securityContext: runAsUser: 1000 volumes: - name: wlp-output emptyDir: {} - name: tmp emptyDir: {} --- ################################################################################################## # Productpage services ################################################################################################## apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage service: productpage spec: ports: - port: 9080 name: http selector: app: productpage --- apiVersion: v1 kind: ServiceAccount metadata: name: bookinfo-productpage labels: account: productpage --- apiVersion: apps/v1 kind: Deployment metadata: name: productpage-v1 labels: app: productpage version: v1 spec: replicas: 1 selector: matchLabels: app: productpage version: v1 template: metadata: labels: app: productpage version: v1 spec: serviceAccountName: bookinfo-productpage containers: - name: productpage image: docker.io/istio/examples-bookinfo-productpage-v1:1.17.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 volumeMounts: - name: tmp mountPath: /tmp securityContext: runAsUser: 1000 volumes: - name: tmp emptyDir: {} ---
結果:
service/details created serviceaccount/bookinfo-details created deployment.apps/details-v1 created service/ratings created serviceaccount/bookinfo-ratings created deployment.apps/ratings-v1 created service/reviews created serviceaccount/bookinfo-reviews created deployment.apps/reviews-v1 created deployment.apps/reviews-v2 created deployment.apps/reviews-v3 created service/productpage created serviceaccount/bookinfo-productpage created deployment.apps/productpage-v1 created
-
應用程序將啟動。隨著每個 pod 準備就緒,Istio sidecar 將隨之部署。
結果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 90m details ClusterIP 10.43.130.114 <none> 9080/TCP 92s ratings ClusterIP 10.43.13.141 <none> 9080/TCP 92s reviews ClusterIP 10.43.110.102 <none> 9080/TCP 92s productpage ClusterIP 10.43.243.227 <none> 9080/TCP 92s
接著看一下 Pod 的佈署:
結果:
NAME READY STATUS RESTARTS AGE details-v1-6758dd9d8d-8dbb4 2/2 Running 0 4m21s ratings-v1-f849dc6d-4pmv9 2/2 Running 0 4m21s productpage-v1-797d845774-vnwq7 2/2 Running 0 4m21s reviews-v1-74fb8fdbd8-8hgcj 2/2 Running 0 4m21s reviews-v3-55545c459b-pw68t 2/2 Running 0 4m21s reviews-v2-58d564d4db-p9bfb 2/2 Running 0 4m21s
-
驗證到目前為止的設置一切正常。運行以下命令,通過檢查響應中的頁面標題來查看應用程序是否在集群內運行並提供 HTML 頁面:
執行下列命令 >_kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" \ -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
如果看到下列結果即表示應用程式己經在集群內運行:
對外部暴露應用程序¶
Bookinfo 應用程序已部署,但無法從 Kubernetes 外部來訪問它。為了使其可訪問, 需要創建一個 Istio Ingress Gateway,它將路徑映射到網格邊緣的路由。
Istio Ingress 對比 Kubernetes Ingress
使用 Istio 來控制 North-South 流量進出的 Ingress Gateway 與傳統 Kubernetes Ingress Controller 的手法不太一樣。
詳細的對比請參閱:Istio Ingress 與 Kubernetes Ingress
將此範例應用程序的服務與 Istio gateway 進行關聯:
讓我們來看一下這個設定檔的內容:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
整體的結構如下:
Tip
如果想檢查配置是否有問題, 可使用 istioctl analyze
來驗證:
結果:
確定 Ingress IP 和端口¶
按照這些說明設置用於訪問網關的 INGRESS_HOST 和 INGRESS_PORT 變量。
執行以下命令來確定您的 Kubernetes 集群是否在支持外部負載均衡器的環境中運行:
結果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.43.81.49 172.22.0.2,172.22.0.3 15021:31007/TCP,80:31366/TCP,443:32297/TCP,31400:32599/TCP,15443:32439/TCP 117m
舉例來說在範例中的 Kubernetes 環境裡頭所暴露出來的外部 IP 是 172.22.0.2
與 172.22.0.3
。 為了方便後續的驗證,使用環境變數把 GATEWAY_URL
暴露出來:
Info
上述 GATEWAY_URL
的 IP 會根據每一個 Kuberntes 集群配置的 Load Balaner 不同而會有不同的 IP 位址。
使用瀏覽器來鍵入下列的 Url:
-
通過 K3D 的 Gateway (本機: 8080 << K3D cluster gateway: 80)
-
直接通過本機的 LoadBalancer 的 IP
- http://$GATEWAY_URL/productpage
驗證外部訪問¶
通過使用瀏覽器查看 Bookinfo 產品頁面,確認可以從外部訪問 Bookinfo 應用程序。要在 Istio 中運行這一應用,無需對應用自身做出任何改變。您只要簡單的在 Istio 環境中對服務進行配置和運行,具體一點說就是把 Envoy sidecar 注入到每個服務之中。最終的部署結果將如下圖所示:
所有的微服務都和 Envoy sidecar 集成在一起,被集成服務所有的出入流量都被 sidecar 所劫持,這樣就為外部控制準備了所需的 Hook,然後就可以利用 Istio 控制平面為應用提供服務路由、遙測數據收集以及策略實施等功能。
流量模擬¶
要了解 istio 的功能是否正常的簡單方式就是去模擬一些服務的流量。下列的指令會向 productpage
服務持續發送 10000 個請求:
Info
上述的命令稿是使用 linux 的 Bash script 來模擬服務的流量。要查看跟踪數據,您必須向您的服務發送請求。請求的數量取決於 Istio 的採樣率,並且可以使用 Telemetry API 進行配置。在默認採樣率為 1% 的情況下,您需要發送至少 100 個請求才能看到第一個跟踪。
在 Kiali UI 左側導航菜單中,選擇 Graph
,然後在 Namespace
下拉菜單中選擇 default
。
Kiali 經由 Prometheus 所收集的 envoy 指標就能夠視覺化地展現出流量與服務的拓撲圖。
步驟 02 - Istio 功能展示¶
2.1 流量管理¶
Istio 擁有強大的流量管理功能,DevOp 團隊通過相關 Istio 提供的 CRDs 來宣告相關的流量控制。
接下來會使用幾個不同的情境來展示 Istio 在流量管理的功能。
配置请求路由¶
此任務將展示如何將請求動態路由到微服務的多個版本。
Istio Bookinfo 示例包含四個獨立的微服務。其中一個微服務 reviews
的三個不同版本已經部署並同時運行。為了說明這導致的問題,在瀏覽器中訪問 Bookinfo 應用程序的 /productpage
並刷新幾次。您會注意到,有時書評的輸出包含星級評分,有時則不包含。這是因為沒有明確的默認服務版本可路由,Istio 將以循環方式將請求路由到所有可用版本。
應用默認目標規則¶
在使用 Istio 控制 Bookinfo 版本路由之前,您需要在 destionation rules
中定義好可用的版本,命名為 subsets
。
運行以下命令為 Bookinfo 服務創建的默認的目標規則:
Example
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
// point to service name
host: productpage
subsets:
- name: v1
labels:
version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
// point to service name
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: ratings
spec:
// point to service name
host: ratings
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v2-mysql
labels:
version: v2-mysql
- name: v2-mysql-vm
labels:
version: v2-mysql-vm
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: details
spec:
// point to service name
host: details
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
---
您可以使用以下命令查看目標規則:
結果:
NAME HOST AGE
productpage productpage 73m
reviews reviews 73m
ratings ratings 73m
details details 73m
應用 Virtual Service¶
要僅路由到其中特定的一個版本,請應用為微服務設置默認版本的 Virtual Service。在這種情況下,Virtual Service 將所有流量路由到每個微服務的 v1 版本。
運行以下命令以應用 Virtual Service:
Example
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: details
spec:
hosts:
- details
http:
- route:
- destination:
host: details
subset: v1
---
您已將 Istio 配置為路由到 Bookinfo 所有微服務的 v1
版本,其中最容易觀察這個流量的改變是落在 reviews 服務。reviews 有三個在線的版本 v1
, v2
與 v3
,經由 VirtualService 的設定之後,所有呼叫reviews 服務的流量都被導向至 v1
版本。
測試新的路由配置¶
您可以通過再次刷新 Bookinfo 應用程序的 /productpage
來測試新配置。
-
在瀏覽器中打開 Bookinfo 站點。網址為
http://$GATEWAY_URL/productpage
,其中 $GATEWAY_URL 是外部的入口 IP 地址。Info
請注意,無論您刷新多少次,頁面的評論部分都不會顯示評級星標。這是因為您將 Istio 配置為將評論服務的所有流量路由到版本 reviews:v1,而此版本的服務不訪問星級評分服務。
您已成功完成此任務的第一部分:將流量路由到服務的某一個版本。
基於用戶身份的路由¶
接下來,您將更改路由配置,以便將來自特定用戶的所有流量路由到特定服務版本。在這種情況下,來自名為 Jason 的用戶的所有流量將被路由到服務 reviews:v2
。
請注意,Istio 對用戶身份沒有任何特殊的內置機制。事實上,productpage 服務在所有到 reviews 服務的 HTTP 請求中都增加了一個自定義的 end-user
請求 Header,從而達到了本例子的效果。
請記住,reviews:v2
是包含星級評分功能的版本。
-
運行以下命令以啟用基於用戶的路由:
-
在 Bookinfo 應用程序的
/productpage
上,以用戶jason
身份登錄。刷新瀏覽器。您看到了什麼?星級評分顯示在每個評論旁邊。
-
以其他用戶身份登錄(選擇您想要的任何名稱)。
刷新瀏覽器。現在星星消失了。這是因為除了 jason 之外,所有用戶的流量都被路由到
reviews:v1
。從 Kiali 的流量拓撲也可觀察到這個流量的狀態。
您已成功配置 Istio 根據用戶身份路由流量。
流量轉移¶
本任務將向您展示如何將流量從微服務的一個版本逐步遷移到另一個版本。例如,您可以將流量從舊版本遷移到新版本。
一個常見的用例是將流量從微服務的一個版本的逐漸遷移到另一個版本。在 Istio 中,您可以通過配置一系列規則來實現此目標。這些規則將一定比例的流量路由到一個或另一個服務。在本任務中,您將會把 50%
的流量發送到 reviews:v1
,另外,50%
的流量發送到 reviews:v3
。接著,再把 100%
的流量發送到 reviews:v3
來完成遷移。
基於權重的路由¶
-
首先,運行此命令將所有流量路由到各個微服務的
v1
版本。Example
virtual-service-all-v1.yamlapiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: productpage spec: hosts: - productpage http: - route: - destination: host: productpage subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: ratings spec: hosts: - ratings http: - route: - destination: host: ratings subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: details spec: hosts: - details http: - route: - destination: host: details subset: v1 ---
-
在瀏覽器中打開 Bookinfo 站點。網址為
http://$GATEWAY_URL/productpage
,其中 $GATEWAY_URL 是 Ingress 的外部 IP 地址。請注意,不管刷新多少次,頁面的評論部分都不會顯示評價星級的內容。這是因為 Istio 被配置為將星級評價的服務的所有流量都路由到了 reviews:v1 版本,而該版本的服務不訪問帶評價星級的服務。
-
使用下面的命令把
50%
的流量從reviews:v1
轉移到reviews:v3
: -
刷新瀏覽器中的
/productpage
頁面,大約有50%
的機率會看到頁面中帶 紅色 星級的評價內容。這是因為 reviews 的v3
版本可以訪問帶星級評價,但v1
版本不能。 -
如果您認為
reviews:v3
微服務已經穩定,您可以通過應用 Virtual Service 規則將100%
的流量路由reviews:v3
:Example
現在,當您刷新
/productpage
時,您將始終看到帶有 紅色 星級評分的書評。從 Kiali 觀察的結果:
2.2 可觀測性¶
在分散式且複雜的應用程式中,要如何讓團隊更好的監控應用程式,就需要提高系統的 Observability (可觀測性),Observability 讓我們更好了解系統發生什麼樣的行為,當問題出現可以迅速的定位,當系統有異常時也能提前示警。提升 Observability 的方式有很多,這裡舉幾種常見的方式:
- 蒐集系統資訊並放入資料庫,當發生問題時可以查找
- 建立 Alert 機制,偵測到異常資訊時可以做示警
- 製作 Dashboard 將系統資料可視化
而現今主要的作法,是蒐集系統中的 Metrics、Logging與Tracing三大訊息,並搭配開源軟體如 Prometheus、Fluentd、Jaeger 來實現對系統的資料蒐集、示警、可視化等功能
Metrics (指標)¶
Metrics 代表系統中的數值資料,例如 CPU、Memory 的使用量,或是呼叫 HTTP 請求的次數,將這些資訊根據時間記錄下來,就能了解各個時間時系統的狀況為何。
Istio 為網格內所有的服務通信生成詳細的遙測數據。這種遙測技術提供了服務行為的可觀測性,使運維人員能夠排查故障、維護和優化應用程序,而不會給服務的開發人員帶來任何額外的負擔。通過 Istio,運維人員可以全面了解到受監控的服務如何與其他服務以及 Istio 組件進行交互。
Istio 生成以下類型的遙測數據,以提供對整個服務網格的可觀測性:
Metrics
: Istio 基於 4 個監控的黃金標識(延遲、流量、錯誤、飽和度)生成了一系列服務指標。 Istio 還為網格控制平面提供了更詳細的指標。除此以外還提供了一組默認的基於這些指標的網格監控儀表板。Distributed Traces
: Istio 為每個服務生成分佈式追踪 span,運維人員可以理解網格內服務的依賴和調用流程。Access Logs
: 當流量流入網格中的服務時,Istio 可以生成每個請求的完整記錄,包括源和目標的元數據。此信息使運維人員能夠將服務行為的審查控製到單個工作負載實例的級別。
讓我們來看一下 Istio 如何使用 sidecar (Envovy) 來暴露監控的黃金標識(延遲、流量、錯誤、飽和度)。
Prometheus¶
-
查看 Bookinfo 佈署後的 Pods 狀態
結果:
NAME READY STATUS RESTARTS AGE productpage-v1-797d845774-76f95 2/2 Running 0 8h details-v1-6758dd9d8d-n522b 2/2 Running 0 8h ratings-v1-f849dc6d-j7jpk 2/2 Running 0 8h reviews-v3-55545c459b-b72zw 2/2 Running 0 8h reviews-v1-74fb8fdbd8-bdsf8 2/2 Running 0 8h reviews-v2-58d564d4db-s6bls 2/2 Running 0 8h
可發現每一個 Pod 都包含著兩個 containers。
-
查看
productpage
的 Pod spec結果:
apiVersion: v1 kind: Pod metadata: annotations: kubectl.kubernetes.io/default-container: productpage kubectl.kubernetes.io/default-logs-container: productpage prometheus.io/path: /stats/prometheus prometheus.io/port: "15020" prometheus.io/scrape: "true" sidecar.istio.io/status: '{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["workload-socket","credential-socket","workload-certs","istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}' labels: app: productpage pod-template-hash: 797d845774 security.istio.io/tlsMode: istio service.istio.io/canonical-name: productpage service.istio.io/canonical-revision: v1 version: v1 name: productpage-v1-797d845774-76f95 namespace: default spec: containers: - image: docker.io/istio/examples-bookinfo-productpage-v1:1.17.0 ... ...
從 Pod spec 的 annotations 可發現 istio 自動注入的一個 sidecar 並且宣告這個 Pod 會在:
- port:
prometheus.io/port: "15020"
- path:
prometheus.io/path: /stats/prometheus
暴露可讓 Prometheus 括取的指標。
- port:
-
執行下列命令來暴露
productpage
服務:執行下列命令 >_kubectl port-forward -n default pod/productpage-v1-797d845774-76f95 15020:15020 --address=0.0.0.0
Info
注意要查找的 pod 的 id 會隨每個環境的佈署而有所不同
-
到 Prometheus GUI 介面 -> 在搜尋欄輸入下列字串後點擊 Execute
Info
istio_requests_total
為 Istio 預設的 Metrics,代表代理的請求數,可以在下方列表看到搜尋結果。
Grafana¶
Istio 會在 Grafana 預建立幾個 Dashboard:
- Control Plane Dashboard: 監控 Istio Control Plane 的 Health 及 Performance 資訊
- Mesh Dashboard: 提供所有 Services 的基本資料
- Performance Dashboard: 監控 Service Mesh 的資源使用量
- Service Dashboard: 提供 Services 詳細的 Metrics 資料
-
Workload Dashboard: 提供詳細的 Workload 資訊
-
在 Istio Mesh Dashboard 可看到所有 Services 的資料,如 Latency 及連線成功比率。
還有其他預設的 Istio Dashboard,可以自己嘗試看看。
Logging (日誌)¶
Logging 就是應用程式發出的 Logs ,這些資料龐雜且觸發時間不固定,但對於解決問題是非常有用的資訊,需要做的是如何蒐集不同應用程式的 Logs , 讓使用者可以輕鬆方便的查找。
訪問日誌提供了一種從單個工作負載實例的角度監控和理解行為的方法。
Istio 能夠以多種操作方式和配置的格式為流量生成 訪問日誌,使能控制記錄日誌、內容、時間地點。有關完整信息,請參見獲取 Envoy 的訪問日誌。
-
查看
productpage
的 Pod 裡頭包含了那些容器執行下列命令 >_kubectl get pod/productpage-v1-797d845774-76f95 -o jsonpath='{range .spec.containers[*]}{.name}{"\n"}{end}'
結果:
-
查看
productpage
容器打印在 stdout 的日誌結果:
send: b'GET /details/0 HTTP/1.1\r\nHost: details:9080\r\nuser-agent: curl/7.81.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nX-B3-TraceId: eac07268c287265599e50348053de42c\r\nX-B3-SpanId: 290f1e2da89d85e7\r\nX-B3-ParentSpanId: 99e50348053de42c\r\nX-B3-Sampled: 1\r\nx-request-id: 93ef3bcc-c560-94ff-a014-b8ce3088af65\r\n\r\n' reply: 'HTTP/1.1 200 OK\r\n' header: content-type: application/json header: server: envoy header: date: Thu, 10 Nov 2022 02:05:11 GMT header: content-length: 178 header: x-envoy-upstream-service-time: 1 DEBUG:urllib3.connectionpool:http://details:9080 "GET /details/0 HTTP/1.1" 200 178 DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): reviews:9080 send: b'GET /reviews/0 HTTP/1.1\r\nHost: reviews:9080\r\nuser-agent: curl/7.81.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nX-B3-TraceId: eac07268c287265599e50348053de42c\r\nX-B3-SpanId: 290f1e2da89d85e7\r\nX-B3-ParentSpanId: 99e50348053de42c\r\nX-B3-Sampled: 1\r\nx-request-id: 93ef3bcc-c560-94ff-a014-b8ce3088af65\r\n\r\n' reply: 'HTTP/1.1 200 OK\r\n' header: x-powered-by: Servlet/3.1 header: content-type: application/json header: date: Thu, 10 Nov 2022 02:05:10 GMT header: content-language: en-US header: content-length: 358 header: x-envoy-upstream-service-time: 0 header: server: envoy DEBUG:urllib3.connectionpool:http://reviews:9080 "GET /reviews/0 HTTP/1.1" 200 358 INFO:werkzeug:::ffff:127.0.0.6 - - [10/Nov/2022 02:05:11] "GET /productpage HTTP/1.1" 200 -
-
查看由 Istio 自動注入到
productpage
Pod 裡頭的 Sidecaristio-proxy
容器打印在 stdout 的日誌結果:
[2022-11-10T02:05:10.871Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 5290 77 77 "10.42.1.1" "curl/7.81.0" "7fe15347-ffca-9445-a5f1-4654112f27d0" "172.23.0.2" "10.42.1.6:9080" inbound|9080|| 127.0.0.6:50741 10.42.1.6:9080 10.42.1.1:0 outbound_.9080_._.productpage.default.svc.cluster.local default [2022-11-10T02:05:10.977Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 2 2 "-" "curl/7.81.0" "3d3ce89b-9fcc-9111-a070-a7699aab0de5" "details:9080" "10.42.0.6:9080" outbound|9080|v1|details.default.svc.cluster.local 10.42.1.6:42506 10.43.46.128:9080 10.42.1.6:51958 - - [2022-11-10T02:05:10.985Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 438 4 4 "-" "curl/7.81.0" "3d3ce89b-9fcc-9111-a070-a7699aab0de5" "reviews:9080" "10.42.0.9:9080" outbound|9080|v3|reviews.default.svc.cluster.local 10.42.1.6:49304 10.43.162.66:9080 10.42.1.6:52060 - - [2022-11-10T02:05:10.970Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 5290 23 22 "10.42.1.1" "curl/7.81.0" "3d3ce89b-9fcc-9111-a070-a7699aab0de5" "172.23.0.2" "10.42.1.6:9080" inbound|9080|| 127.0.0.6:46933 10.42.1.6:9080 10.42.1.1:0 outbound_.9080_._.productpage.default.svc.cluster.local default [2022-11-10T02:05:11.004Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 2 1 "-" "curl/7.81.0" "0cbaaff0-7d9a-92d7-b4f7-fa76e91b7cad" "details:9080" "10.42.0.6:9080" outbound|9080|v1|details.default.svc.cluster.local 10.42.1.6:42522 10.43.46.128:9080 10.42.1.6:51970 - - [2022-11-10T02:05:11.011Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 358 2 1 "-" "curl/7.81.0" "0cbaaff0-7d9a-92d7-b4f7-fa76e91b7cad" "reviews:9080" "10.42.0.8:9080" outbound|9080|v1|reviews.default.svc.cluster.local 10.42.1.6:42820 10.43.162.66:9080 10.42.1.6:52076 - - [2022-11-10T02:05:11.000Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 4294 15 15 "10.42.1.1" "curl/7.81.0" "0cbaaff0-7d9a-92d7-b4f7-fa76e91b7cad" "172.23.0.2" "10.42.1.6:9080" inbound|9080|| 127.0.0.6:55579 10.42.1.6:9080 10.42.1.1:0 outbound_.9080_._.productpage.default.svc.cluster.local default [2022-11-10T02:05:11.032Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 44 1 "-" "curl/7.81.0" "93ef3bcc-c560-94ff-a014-b8ce3088af65" "details:9080" "10.42.0.6:9080" outbound|9080|v1|details.default.svc.cluster.local 10.42.1.6:42522 10.43.46.128:9080 10.42.1.6:51972 - - [2022-11-10T02:05:11.079Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 358 1 0 "-" "curl/7.81.0" "93ef3bcc-c560-94ff-a014-b8ce3088af65" "reviews:9080" "10.42.0.8:9080" outbound|9080|v1|reviews.default.svc.cluster.local 10.42.1.6:58054 10.43.162.66:9080 10.42.1.6:52092 - - [2022-11-10T02:05:11.027Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 4294 55 54 "10.42.1.1" "curl/7.81.0" "93ef3bcc-c560-94ff-a014-b8ce3088af65" "172.23.0.2" "10.42.1.6:9080" inbound|9080|| 127.0.0.6:46603 10.42.1.6:9080 10.42.1.1:0 outbound_.9080_._.productpage.default.svc.cluster.local default
每一個不同的開發的團隊都可能使用不同的手法與格式來寫日誌,這會導致運維除錯查找根因的複雜度。Istio 的 Sidecar 可定義一致的日誌格式來減輕日誌解析的問題。另外也可使用設定來讓 Istio 使用 json 的日誌格式便於 Central Logging System 的整合(比如 Grafana Loki)。
Tracing (追蹤)¶
Distrubuted Tracing 能夠追蹤單次請求在系統內部的行為,主要用在 Distributed System 或是 Microservices,透過可視化的方式將延遲時間、觸發行為等資訊顯示在 Dashboard 上,幫助使用者追蹤故障位置或是效能瓶頸等原因。
使用 Metrics 及 Logging 資訊能清楚呈現單一 Service 資訊,但若是放到 Microservices 架構,因為系統是由多種元件所組成,單一請求會跟多個元件進行互動,若只對 Service 個別監控,在遇到複雜的問題時沒有統整資料,對系統 Troubleshooting 時會較為困難。
而 Distributed Tracing 能夠將單次請求在系統內部是如何處理的方式,包括經過哪些元件、元件之間的溝通時間、呼叫的路徑為何給記錄下來,讓我們完整的了解請求是如何被 Microservices 處理的,以此提升系統的 Observability。
而 Tracing 到底紀錄了什麼資訊?一個 Trace 其實是由一到多個 Span 所組成,每個 Span 會紀錄事件名稱、開始與結束時間等資料,透過將單一請求所產生出的 Span 統整起來即成為 Trace。
在 Istio 是如何實現 Distributed Tracing?其實是靠 Sidecar 的 Envoy’s distributed tracing 功能來完成的,Istio 會在每個元件旁都注入 Sidecar, Service 之間的流量都會藉由 Sidecar 來代理,當 Request 進來時,Proxy 就能紀錄每個 Service 產生的 Span ,並在 HTTP Headers 紀錄此次 Request 的獨立 Id,以此就能將分散的 Span 資料形成完整的 Trace。
Info
Istio 透過 Sidecar 擷取 Service 間的流量,紀錄 Span 資料,並藉由 HTTP Headers 上的 Request Id 將 Span 統整成 Tracing 資訊。
Jaeger¶
Jaeger 為 CNCF 開源專案,是一個 Tracing 平台,用來監控 microservices 相關的分散式系統,協助使用者排除故障,功能包含
- 分散式資料傳播 (Distributed context propagation)
- 分散式事務監控 (Distributed transaction monitoring)
- 根本原因分析 (Root cause analysis)
- 服務依賴性分析 (Service dependency analysis)
-
效能/延遲優化 (Performance / latency optimization)
-
在瀏覽器輸入網址連接至 Jaeger 服務
-
在 Jaeger 輸入以下資訊,並點擊
Find Traces Query
資料- Service:
productage.default
- Limit Requests:
20
- Service:
-
點擊 7 或 8 Spans 的 Traces 紀錄
從 span 的追蹤記錄所蒐集到的資訊,可以看到經過哪些 Microservices 元件,也能看出每個元件處理請求所花費的時間。
搭配 Bookinfo 架構圖,就可以了解元件的溝通順序為何。
2.3 安全¶
將應用程式從 Monolithic 改成 Microservices 架構雖然能帶來許多好處,但服務之間的流量增加也讓駭客有機會趁虛而入,所以在使用 Microservices 時會有額外的安全需求,包含需對流量進行加密以抵禦 man-in-the-middle attacks(中間人攻擊),以及在服務設置訪問策略以防未授權的流量進入系統等等,藉此保障服務的安全性。
在 Istio Scurity 提供了許多功能來幫助你解決應用程式的安全問題,包括提供強大的身份認證、TLS 加密等等機制,幫助我們保護服務及數據,達到安全目標如下:
Security by dafult
(默認安全性): 無需修改程式碼及基礎設施即可保護應用程式。Defense in depth
(深度防禦): 在現有的安全機制下提供更多層的防禦。Zero-trust network
(零信任網路): 在不安全的網路也能建立安全的解決方案。
而 Istio 在 Security 的實作方法,是在 Control Plane 管理 Certificate、認證策略等安全功能,並讓 Data Plane 中的 Sidecar 保護點對點之間的流量,以達成保護整個 Service Mesh 網路。
Kubernetes 為何需要 mTLS?¶
看到這裡可能會有一個疑問?用 mTLS 保護外部的流量很重要,但為何 Microservices 內部的流量也需要加密呢?若以抽象化角度看 Kubernetes,流量都在 Cluster 內部,資料的傳輸看似沒什麼安全問題。
但實際上 Kubernetes Cluster 是由好幾個 Node 作爲運算單元所組成,這些 Node 可能放在同個機房也可能放在不同地區,而同一個 Microservices 元件不一定會部署到同個 Node 上,所以元件之間的流量可能會經過 Internet ,若是沒對封包內容進行加密,裡面又有使用者的敏感資訊時,駭客就能擷取封包獲取這些敏感資料。
安全總結¶
在 Istio 如何實現 Security 功能,其實在安裝時系統就會預設將 mTLS 功能打開,不需要修改程式碼或做額外設定下,也能在不安全的網路中提升應用程式的安全性。
步驟 03 - Lab 環境清理¶
結束對 Bookinfo 示例應用的體驗之後,就可以使用下面的命令來完成應用的刪除和清理了:
-
刪除路由規則,並銷毀應用的 Pod
結果:
namespace ? [default] using NAMESPACE=default destinationrule.networking.istio.io "productpage" deleted destinationrule.networking.istio.io "reviews" deleted destinationrule.networking.istio.io "ratings" deleted destinationrule.networking.istio.io "details" deleted virtualservice.networking.istio.io "bookinfo" deleted virtualservice.networking.istio.io "productpage" deleted virtualservice.networking.istio.io "ratings" deleted virtualservice.networking.istio.io "details" deleted virtualservice.networking.istio.io "reviews" deleted gateway.networking.istio.io "bookinfo-gateway" deleted Application cleanup may take up to one minute service "details" deleted serviceaccount "bookinfo-details" deleted deployment.apps "details-v1" deleted service "ratings" deleted serviceaccount "bookinfo-ratings" deleted deployment.apps "ratings-v1" deleted service "reviews" deleted serviceaccount "bookinfo-reviews" deleted deployment.apps "reviews-v1" deleted deployment.apps "reviews-v2" deleted deployment.apps "reviews-v3" deleted service "productpage" deleted serviceaccount "bookinfo-productpage" deleted deployment.apps "productpage-v1" deleted Application cleanup successful
-
確認應用已經關停