基於阿里雲 ASK 的 Istio 微服務應用部署初探

語言: CN / TW / HK

作者:王飛龍(不物)

目前 Kubernetes 已經成為業界容器編排系統的事實標準,基於 Kubernetes 的雲原生應用生態(Helm, Istio, Knative, Kubeflow, Spark on Kubernetes 等)更是讓 Kubernetes 成為雲作業系統。在這樣的背景下,Serverless 容器成為現有 Container as a Service 的進化方向之一,一方面通過 Serverless 方式根本性解決了 Kubernetes 自身的管理複雜性,讓使用者無需受困於 Kubernetes 叢集容量規劃、安全維護、故障診斷;另一方面也進一步釋放了雲端計算的能力,將安全、可用性、可伸縮性等需求由基礎設施實現。

ASK 作為阿里雲 Serverless Kubernetes 平臺 [ 1] ,不僅有免運維、秒級彈性、超大 Pod 容量、彈性預測等重磅能力,更重要的是它依然是一個標準 Kubernetes 平臺。

本文會通過在 ASK 上試用 Istio 部署微服務應用的方式,來驗證 ASK 對標準 Kubernetes 的相容性。Istio 作為 Service Mesh(服務網格)的領導解決方案,一方面本身足夠複雜具有代表性,另一方面它也代表了雲原生時代微服務架構的趨勢具有參考意義。

現在就讓我們開始吧!

建立叢集

試用 Istio 前,需要準備一個 ASK 叢集。登入阿里雲控制檯,選擇產品與服務 > 容器服務 Kubernetes 版,在左側邊欄選擇叢集進入叢集列表頁面。點選右上角建立叢集開始建立叢集,配置叢集引數如下:

  • 叢集名稱:hello-istio
  • 叢集規格:Pro 版
  • 地域:美國(矽谷)
  • 付費型別:按量付費
  • Kubernetes 版本:1.20.11-aliyun.1
  • 專有網路:自動建立
  • Service CIDR:172.21.0.0/20
  • API Server 訪問:標準型I(slb.s2.small)
  • 使用 EIP 暴露 API Server:是
  • 時區:Aisa/Shanghai(UTC+08:00)
  • 服務發現:CoreDNS
  • 使用日誌服務:建立新 Project

確認配置後點擊建立叢集進入等待叢集建立完成。Istio 依賴 DNS 服務,這裡選擇建立叢集時預設安裝 CoreDNS 元件。

1.png

叢集建立完成後,進入叢集列表 > hello-istio > 詳情 > 叢集資訊 > 連線資訊頁面,複製公網訪問內容到本地/tmp/kube/config 檔案,並通過如下命令配置好 kubelet:

$ export KUBECONFIG=/tmp/kube/config

試用 Istio

kubectl 配置好後就可以開始在叢集安裝和試用 Istio。

下載 Istio

進入 Istio 釋出頁面 [ 2] 下載針對作業系統的安裝檔案,也可以通過如下命令下載並提取最新版本:

$ curl -L http://istio.io/downloadIstio | sh -

因為我本機~/bin 目錄已加入 PATH,這裡我將提取的 Istio 目錄複製~/bin 目錄,並建好軟連結。

$ cp istio-1.13.3 ~/bin $ cd ~/bin $ ln -s istio-1.13.3/bin/istioctl $ ls -al ~/bin/ total 28 drwxr-xr-x 5 feilong.wfl staff 160 5 4 22:40 ./ drwxr-xr-x+ 95 feilong.wfl staff 3040 5 8 22:30 ../ drwxr-x--- 9 feilong.wfl staff 288 4 15 00:48 istio-1.13.3/ lrwxr-xr-x 1 feilong.wfl staff 25 5 4 22:40 istioctl -> istio-1.13.3/bin/istioctl*

如果 istioctl --help 命令輸出正常,則 istioctl 已正確配置。

安裝 Istio

  1. 本次安裝採用 demo profile [ 3] ,它包含了一組專為測試準備的功能集合,另外還有使用者生產或效能測試的配置組合。

$ istioctl install --set profile=demo -y ✔ Istio core installed ✔ Istiod installed ✔ Egress gateways installed ✔ Ingress gateways installed ✔ Installation complete

  1. 給名稱空間新增標籤,指示 Istio 在部署應用的時候,自動注入 Envoy 邊車代理:

$ kubectl label namespace default istio-injection=enabled namespace/default labeled

部署示例應用

  1. 部署 Bookinfo 示例應用 [ 4]

$ kubectl apply -f ~/bin/istio-1.13.3/samples/bookinfo/platform/kube/bookinfo.yaml 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

  1. 檢查 Pod 已就緒:

$ kubectl get pods NAME READY STATUS RESTARTS AGE details-v1-79f774bdb9-t2jhq 2/2 Running 0 2m54s productpage-v1-6b746f74dc-qc9lg 2/2 Running 0 2m46s ratings-v1-b6994bb9-tmbh6 2/2 Running 0 2m51s reviews-v1-545db77b95-xdhp4 2/2 Running 0 2m49s reviews-v2-7bf8c9648f-4gn6f 2/2 Running 0 2m48s reviews-v3-84779c7bbc-jfndj 2/2 Running 0 2m48s

要等待並確保所有的 Pod 達到此狀態:就緒狀態(READY)的值為 2/2 、狀態(STATUS)的值為 Running。基於平臺的不同,這個操作過程可能會花費幾分鐘的時間。

  1. 檢查 Service 已就緒:

$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE details ClusterIP 172.21.11.168 <none> 9080/TCP 59s kubernetes ClusterIP 172.21.0.1 <none> 443/TCP 33m productpage ClusterIP 172.21.0.124 <none> 9080/TCP 51s ratings ClusterIP 172.21.9.7 <none> 9080/TCP 57s reviews ClusterIP 172.21.13.223 <none> 9080/TCP 55s

  1. 確保網頁服務正常。如果命令返回頁面標題,則應用已在叢集中執行。

$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -s productpage:9080/productpage | grep -o "<title>.*</title>" <title>Simple Bookstore App</title>

對外開放服務

現在,BookInfo 應用已經部署,但還不能被外界訪問。 要開放訪問,需要建立 Istio 入站閘道器(Ingress Gateway), 它會把一個路徑路由到網格內的服務。

  1. 把應用關聯到 Istio 閘道器:

$ kubectl apply -f ~/bin/istio-1.13.3/samples/bookinfo/networking/bookinfo-gateway.yaml gateway.networking.istio.io/bookinfo-gateway created virtualservice.networking.istio.io/bookinfo created

  1. 確保配置檔案沒有問題:

$ istioctl analyze ✔ No validation issues found when analyzing namespace: default.

確定入站 IP 和埠

使用如下命令為訪問閘道器設定 INGRESS_HOST 和 INGRESS_PORT 兩個變數:

$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}') $ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')

設定變數 GATEWAY_URL,並確保 IP 地址和埠均成功的賦值給了該變數:

$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT $ echo "$GATEWAY_URL" 47.88.21.82:80

驗證外部訪問

執行下面命令,獲取 Bookinfo 應用的外部訪問地址:

$ echo "http://$GATEWAY_URL/productpage" http://47.88.21.82:80/productpage

複製上面命令的輸出地址到瀏覽器並訪問,確認 Bookinfo 已經實現了外部訪問。重新整理頁面,發現 Book Reviews 的顯示樣式會不斷變化。

2.png

檢視儀表盤

儀表盤能幫助瞭解服務網格的結構、展示網路的拓撲結構、分析網格的健康狀態。

  1. 首先安裝 Kiali 和其他外掛,等待部署完成。

$ kubectl apply -f ~/bin/istio-1.13.3/samples/addons $ kubectl rollout status deployment/kiali -n istio-system Waiting for deployment "kiali" rollout to finish: 0 of 1 updated replicas are available... deployment "kiali" successfully rolled out

  1. 訪問 Kiali 儀表板。

$ istioctl dashboard kiali

  1. 在左側的導航選單,選擇 Graph,然後在 Namespace 下拉列表中,選擇 default

Kiali 儀表板展示了網格的概覽、以及 Bookinfo 示例應用的各個服務之間的關係。 它還提供過濾器來視覺化流量的流動。

3.png

新增預設目標規則

使用 Istio 控制 Bookinfo 版本路由前,需要先在目標規則 [ 5] 中定義好可用的版本。執行以下命令為 Bookinfo 服務建立預設的目標規則:

$ kubectl apply -f ~/bin/istio-1.13.3/samples/bookinfo/networking/destination-rule-all.yaml destinationrule.networking.istio.io/productpage created destinationrule.networking.istio.io/reviews created destinationrule.networking.istio.io/ratings created destinationrule.networking.istio.io/details created

等待幾秒鐘,目標規則生效。您可以使用如下命令檢視目標規則:

$ kubectl get destinationrules NAME HOST AGE details details 30s productpage productpage 32s ratings ratings 31s reviews reviews 32s

路由所有流量到 v1 版本

執行以下命令建立 Virtual Service 將所有流量路由到微服務的 v1 版本:

$ kubectl apply -f ~/bin/istio-1.13.3/samples/bookinfo/networking/virtual-service-all-v1.yaml virtualservice.networking.istio.io/productpage created virtualservice.networking.istio.io/reviews created virtualservice.networking.istio.io/ratings created virtualservice.networking.istio.io/details created

您可以通過再次重新整理 Bookinfo 應用程式的/productpage 頁面測試新配置。請注意,無論您重新整理多少次,頁面的評論部分都不會顯示評級星標。這是因為當前已將 Istio 配置為評論服務的所有流量路由到版本 reviews:v1,而此版本的服務不訪問星級評分服務。

基於使用者身份的路由

接下來將更改路由配置,實現將來自特定使用者的所有流量路由到特定的服務版本。示例中來自名為 Jason 使用者的所有流量將被路由到服務 review:v2。

Istio 對使用者身份沒有任何特殊的內建機制。本例中,productpage 服務在所有到 reviews 服務的 HTTP 請求中都增加了一個自定義的 end-user 請求頭,從而達到效果。

  1. 執行以下命令以啟用基於使用者的路由:

$ kubectl apply -f ~/bin/istio-1.13.3/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml virtualservice.networking.istio.io/reviews created

  1. 確保規則已建立:

$ kubectl get virtualservice reviews -o yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"networking.istio.io/v1alpha3","kind":"VirtualService","metadata":{"annotations":{},"name":"reviews","namespace":"default"},"spec":{"hosts":["reviews"],"http":[{"match":[{"headers":{"end-user":{"exact":"jason"}}}],"route":[{"destination":{"host":"reviews","subset":"v2"}}]},{"route":[{"destination":{"host":"reviews","subset":"v1"}}]}]}} creationTimestamp: "2022-05-15T16:05:55Z" generation: 1 name: reviews namespace: default resourceVersion: "1984849" uid: f3bd3dcb-d83c-4a75-9511-1fc9308ca05b spec: hosts: - reviews http: - match: - headers: end-user: exact: jason route: - destination: host: reviews subset: v2 - route: - destination: host: reviews subset: v1

  1. 在 Bookinfo 應用程式的/productpage 上,以使用者 jason 身份登入。重新整理瀏覽器,看到每個評論旁邊顯示星級評分。

4.png

  1. 以其他使用者身份登入,重新整理瀏覽器。發現星級評分消失了。

原理和限制

資料平面,Istio 通過向 Pod 注入的 Sidecar 代理(istio-proxy)來負責協調和控制微服務之前的所有網路通訊。為了讓 Sidecar 代理(istio-proxy)劫持業務容器流量,Istio 需要向 Pod 所在網路下發 iptables 規則。常規安裝模式下,iptables 規則下發是由 Istio 向 Pod 注入的初始化容器 istio-init 完成。向 Pod 網路下發 iptables 規則需要容器可以使用 NET_ADMIN 和 NET_RAW 兩個高許可權的能力(Capabilities)。ASK 叢集中這兩個高許可權能力受 ASK Pod Security Policy [ 6] 和 ECI Container Security Policy [ 7] 的影響。

ASK Pod Security Policy 的 CAPS 為 *,表示沒有限制。

$ kubectl get psp NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES ack.privileged true * RunAsAny RunAsAny RunAsAny RunAsAny false *

ECI Container Security Policy 允許通過容器安全上下文配置即可。Istio 中 Pod 注入模板檔案~/bin/istio-1.13.3/manifests/charts/istio-control/istio-discovery/files/injection-template.yaml 包含如下程式碼:不啟用 Istio CNI 外掛 [ 8] 將新增 NET_ADMIN 和 NET_RAW 兩個高許可權能力:

securityContext: allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} privileged: {{ .Values.global.proxy.privileged }} capabilities: {{- if not .Values.istio_cni.enabled }} add: - NET_ADMIN - NET_RAW {{- end }} drop: - ALL

所以從原理上分析當前 ASK 叢集使用 Istio 沒有相容性問題。

總結

本次在 ASK 上試用 Istio 這類高複雜度的軟體,未發現相容性問題。又從原理上正面分析論證了產生相容性問題的可能性較低。因此,ASK 對原生 Kubernetes 還是有著極好的相容性。後續將在 ASK 叢集上深入探索 Istio 其他功能,以進一步驗證 ASK 對原生 Kubernetes 的相容性。

參考連結:

[1] 阿里雲 Serverless Kubernetes

http://help.aliyun.com/document_detail/127525.html

[2] Istio 釋出頁面

http://github.com/istio/istio/releases/tag/1.13.3

[3] demo profile**

http://istio.io/latest/docs/setup/additional-setup/config-profiles/

[4] Bookinfo 示例應用

http://istio.io/latest/zh/docs/examples/bookinfo/

[5] 目標規則

http://istio.io/latest/docs/concepts/traffic-management/#destination-rules)中定義好可用的版本中定義好可用的版本)

[6] ASK Pod Security Policy

http://help.aliyun.com/document_detail/165047.html

[7] ECI Container Security Policy

http://help.aliyun.com/document_detail/163023.html

[8] Istio CNI 外掛

http://istio.io/latest/docs/setup/additional-setup/cni/

點選此處,瞭解阿里雲 ASK 更多詳情和最佳實踐