Cloud Service Mesh 是管理及監控分散式應用程式的強大工具。如要充分運用 Cloud Service Mesh,瞭解其基礎抽象化機制 (包括容器和 Kubernetes) 會有所助益。本教學課程說明如何準備應用程式,以便從原始碼到在 GKE 上執行的容器,都能使用 Cloud Service Mesh,直到安裝 Cloud Service Mesh 之前為止。
如果您已熟悉 Kubernetes 和服務網格概念,可以略過本教學課程,直接參閱 Cloud Service Mesh 安裝指南。
目標
- 探索簡單的多服務「Hello World」應用程式。
- 從來源執行應用程式
- 將應用程式容器化。
- 建立 Kubernetes 叢集。
- 將容器部署至叢集。
事前準備
請按照下列步驟啟用 Cloud Service Mesh API:- 前往 Google Cloud 控制台的 Kubernetes Engine 頁面。
- 建立或選取專案。
- 等待 API 和相關服務完成啟用。 這可能需要幾分鐘的時間。
本教學課程使用 Cloud Shell,其會佈建 g1-small Compute Engine 虛擬機器 (VM),並執行以 Debian 為基礎的 Linux 作業系統。
準備 Cloud Shell
使用 Cloud Shell 的優點如下:
- Python 2 和 Python 3 開發環境 (包括
virtualenv) 都已設定完成。 - 本教學課程使用的
gcloud、docker、git和kubectl指令列工具皆已安裝。 您可以選擇文字編輯器:
程式碼編輯器:按一下 Cloud Shell 視窗頂端的 即可存取。
Emacs、Vim 或 Nano,可從 Cloud Shell 的指令列存取。
在 Google Cloud 控制台啟用 Cloud Shell。
Google Cloud 控制台底部會開啟 Cloud Shell 工作階段,並顯示指令列提示。Cloud Shell 是已安裝 Google Cloud CLI 的殼層環境,並已設定適用於您目前專案的值。工作階段可能要幾秒鐘的時間才能初始化。
下載程式碼範例
下載
helloserver原始碼:git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples切換至程式碼範例目錄:
cd anthos-service-mesh-samples/docs/helloserver
探索多服務應用程式
範例應用程式是以 Python 編寫,並有兩個使用 REST 通訊的元件:
server:簡單的伺服器,具有一個GET端點/,可將「hello world」列印到控制台。loadgen:將流量傳送至server的指令碼,每秒要求數 (RPS) 可設定。
從來源執行應用程式
如要熟悉範例應用程式,請在 Cloud Shell 中執行。
從
sample-apps/helloserver目錄執行server:python3 server/server.pyserver啟動時會顯示以下內容:INFO:root:Starting server...
開啟另一個終端機視窗,以便將要求傳送至
server。按一下 即可開啟另一個工作階段。向
server傳送要求:curl http://localhost:8080server回覆:Hello World!
從下載程式碼範例的目錄,變更為包含
loadgen的目錄:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/loadgen
建立下列的環境變數:
export SERVER_ADDR=http://localhost:8080 export REQUESTS_PER_SECOND=5開始時間
virtualenv:virtualenv --python python3 env啟用虛擬環境:
source env/bin/activate安裝
loadgen的必要條件:pip3 install -r requirements.txt執行
loadgen:python3 loadgen.pyloadgen啟動時,會輸出類似以下的訊息:Starting loadgen: 2019-05-20 10:44:12.448415 5 request(s) complete to http://localhost:8080
在另一個終端機視窗中,
server會將訊息寫入控制台,類似於下列內容:127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 - INFO:root:GET request, Path: / Headers: Host: localhost:8080 User-Agent: python-requests/2.22.0 Accept-Encoding: gzip, deflate Accept: */*
從網路的角度來看,整個應用程式現在都在同一個主機上執行。因此,您可以使用
localhost將要求傳送至server。如要停止
loadgen和server,請在每個終端機視窗中輸入Ctrl-c。在
loadgen終端機視窗中停用虛擬環境:deactivate
將應用程式容器化
如要在 GKE 上執行應用程式,您必須將範例應用程式 (server 和 loadgen) 封裝至容器。容器是一種封裝應用程式的方式,可將應用程式與基礎環境隔離。
如要將應用程式容器化,您需要 Dockerfile。Dockerfile 是文字檔案,定義了將應用程式原始碼及其依附元件組合成 Docker 映像檔所需的指令。建構映像檔後,請將其上傳至容器登錄檔,例如 Docker Hub 或 Container Registry。
這個範例包含 Dockerfile 和 loadgen 的 server,以及
建構映像檔所需的所有指令。以下是 server 的 Dockerfile:
FROM python:3-slim as base指令會告知 Docker 使用最新的 Python 3 映像檔做為基本映像檔。COPY . .指令會將目前工作目錄中的來源檔案 (在本例中只有server.py) 複製到容器的檔案系統。ENTRYPOINT會定義用於執行容器的指令。在本例中,這個指令與您用來從原始碼執行server.py的指令幾乎相同。EXPOSE指令會指定server監聽通訊埠8080。這個指令不會公開任何通訊埠,但會做為說明文件,指出您在執行容器時需要開啟通訊埠8080。
準備將應用程式容器化
設定下列環境變數。將
PROJECT_ID替換為Google Cloud 專案 ID。export PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
建構 Docker 映像檔時,您會使用
PROJECT_ID和GCR_REPO的值標記映像檔,然後將映像檔推送至私人 Container Registry。設定 Google Cloud CLI 的預設 Google Cloud 專案。
gcloud config set project $PROJECT_ID
設定 Google Cloud CLI 的預設可用區。
gcloud config set compute/zone us-central1-b確認Google Cloud 專案已啟用 Container Registry 服務。
gcloud services enable containerregistry.googleapis.com
將 server 容器化
切換至範例
server所在的目錄:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
使用
Dockerfile和先前定義的環境變數建構映像檔:docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .-t旗標代表 Docker 標記。這是部署容器時使用的映像檔名稱。將映像檔推送至 Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
將 loadgen 容器化
切換至範例
loadgen所在的目錄:cd ../loadgen建構映像檔:
docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .將映像檔推送至 Container Registry:
docker push gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1
列出映像檔
取得存放區中的映像檔清單,確認映像檔已推送:
gcloud container images list --repository gcr.io/$PROJECT_ID/asm-ready
系統會傳回您剛才推送的映像檔名稱:
NAME gcr.io/PROJECT_ID/asm-ready/helloserver gcr.io/PROJECT_ID/asm-ready/loadgen
建立 GKE 叢集
您可以使用 docker run 指令,在 Cloud Shell VM 上執行這些容器。但在正式環境中,您需要以更統一的方式自動調度管理容器。舉例來說,您需要一個系統來確保容器持續運作,並需要一種方法來擴充及啟動容器的其他執行個體,以處理增加的流量。
您可以使用 GKE 執行容器化應用程式。GKE 是容器協調平台,可將 VM 連線至叢集。每個 VM 都稱為「節點」。GKE 叢集是由 Kubernetes 開放原始碼叢集管理系統提供技術支援。您可以透過 Kubernetes 提供的機制與叢集互動。
如要建立 GKE 叢集,請按照下列步驟操作:
建立叢集:
gcloud container clusters create asm-ready \ --cluster-version latest \ --machine-type=n1-standard-4 \ --num-nodes 4
gcloud指令會在您先前設定的Google Cloud 專案和可用區中建立叢集。如要執行 Cloud Service Mesh,建議至少使用 4 個節點和 n1-standard-4 機型。建立叢集的指令需要幾分鐘才能完成。叢集準備就緒時,指令會輸出類似以下的訊息:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS asm-ready us-central1-b 1.13.5-gke.10 203.0.113.1 n1-standard-2 1.13.5-gke.10 4 RUNNING
向
kubectl指令列工具提供憑證,以便使用該工具管理叢集:gcloud container clusters get-credentials asm-ready現在您可以使用
kubectl與 Kubernetes 通訊。舉例來說,您可以執行下列指令來取得節點狀態:kubectl get nodes指令會傳回節點清單,類似於下列內容:
NAME STATUS ROLES AGE VERSION gke-asm-ready-default-pool-dbeb23dc-1vg0 Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-36z5 Ready <none> 100s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-fj7s Ready <none> 99s v1.13.6-gke.13 gke-asm-ready-default-pool-dbeb23dc-wbjw Ready <none> 99s v1.13.6-gke.13
瞭解 Kubernetes 的重要概念
下圖顯示在 GKE 上執行的應用程式:
將容器部署至 GKE 之前,建議您先瞭解一些重要的 Kubernetes 概念。本教學課程的結尾提供相關連結,方便您進一步瞭解各項概念。
節點和叢集:在 GKE 中,節點是 VM。在其他 Kubernetes 平台上,節點可以是實體或虛擬機器。叢集是一組節點,可視為單一機器,您可以在其中部署容器化應用程式。
Pod:在 Kubernetes 中,容器是在 Pod 內執行。Pod 是 Kubernetes 的基本單位。Pod 包含一或多個容器。您將
server和loadgen容器分別部署在各自的 Pod 中。當 Pod 執行多個容器時 (例如應用程式伺服器和Proxy 伺服器),這些容器會以單一實體的形式管理,並共用 Pod 的資源。Deployment:Deployment 是代表一組相同 Pod 的 Kubernetes 物件。Deployment 會執行多個 Pod 副本,並分散在叢集的節點中。Deployment 會自動替換任何失敗或沒有回應的 Pod。
Kubernetes Service:在 GKE 中執行應用程式程式碼會變更
loadgen和server之間的網路。在 Cloud Shell VM 中執行服務時,您可以使用localhost:8080位址將要求傳送至server。部署至 GKE 後,Pod 會排定在可用的節點上執行。根據預設,您無法控制 Pod 在哪個節點上執行,因此 Pod 沒有穩定的 IP 位址。如要取得
server的 IP 位址,您必須在 Pod 之上定義稱為 Kubernetes Service 的網路抽象層。Kubernetes Service 可為一組 Pod 提供穩定的網路端點。服務分為多種類型。server使用LoadBalancer,公開外部 IP 位址,因此您可以從叢集外部連上server。Kubernetes 也內建 DNS 系統,可為 Service 指派 DNS 名稱 (例如
helloserver.default.cluster.local)。這樣一來,叢集內的 Pod 就能透過穩定的位址,連線至叢集內的其他 Pod。您無法在叢集外 (例如從 Cloud Shell) 使用這個 DNS 名稱。
Kubernetes 資訊清單
從原始碼執行應用程式時,您使用了命令式指令:python3 server.py
命令式是指以動詞為主的「執行這項操作」。
相較之下,Kubernetes 則採用宣告式模型。也就是說,您不必明確指示 Kubernetes 該怎麼做,而是提供 Kubernetes 預期狀態。舉例來說,Kubernetes 會視需要啟動及終止 Pod,確保實際系統狀態符合所需狀態。
您可以在一組資訊清單或 YAML 檔案中指定所需狀態。YAML 檔案包含一或多個 Kubernetes 物件的規格。
範例包含 server 和 loadgen 的 YAML 檔案。每個 YAML 檔案都會指定 Kubernetes Deployment 物件和服務的所需狀態。
伺服器
kind表示物件類型。metadata.name會指定 Deployment 的名稱。- 第一個
spec欄位包含所需狀態的說明。 spec.replicas會指定所需的 Pod 數量。spec.template區段定義了 Pod 範本。Pod 的規格包含image欄位,也就是要從 Container Registry 提取的映像檔名稱。
「服務」定義如下:
LoadBalancer:用戶端會將要求傳送至網路負載平衡器的 IP 位址,該位址穩定且可從叢集外部連線。targetPort:請注意,Dockerfile中的EXPOSE 8080指令實際上不會公開任何連接埠。公開通訊埠8080,以便從叢集外部連線至server容器。在本例中,hellosvc.default.cluster.local:80(簡短名稱:hellosvc) 會對應至helloserverPod IP 的通訊埠8080。port:叢集中的其他服務傳送要求時,會使用這個通訊埠編號。
負載產生器
loadgen.yaml 中的 Deployment 物件與 server.yaml 類似。其中一項顯著差異是 Deployment 物件包含名為 env 的區段。本節定義 loadgen 所需的環境變數,這些變數是您先前從來源執行應用程式時設定的。
由於 loadgen 不接受傳入要求,因此 type 欄位會設為 ClusterIP。這種類型會提供穩定的 IP 位址,可供叢集中的服務使用,但不會向外部用戶端公開。
將容器部署至 GKE
切換至範例
server所在的目錄:cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
在文字編輯器中開啟
server.yaml。將
image欄位中的名稱替換為 Docker 映像檔名稱。image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
將
PROJECT_ID替換為 Google Cloud 專案 ID。儲存並關閉
server.yaml。將 YAML 檔案部署至 Kubernetes:
kubectl apply -f server.yaml如果成功,指令會傳回下列內容:
deployment.apps/helloserver created service/hellosvc created
切換至
loadgen所在的目錄。cd ../loadgen在文字編輯器中開啟
loadgen.yaml。將
image欄位中的名稱替換為 Docker 映像檔名稱。image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
將
PROJECT_ID替換為 Google Cloud 專案 ID。儲存並關閉
loadgen.yaml,然後關閉文字編輯器。將 YAML 檔案部署至 Kubernetes:
kubectl apply -f loadgen.yaml如果成功,指令會傳回下列內容:
deployment.apps/loadgenerator created service/loadgensvc created
檢查 Pod 的狀態:
kubectl get pods指令會傳回類似下列內容的狀態:
NAME READY STATUS RESTARTS AGE helloserver-69b9576d96-mwtcj 1/1 Running 0 58s loadgenerator-774dbc46fb-gpbrz 1/1 Running 0 57s
從
loadgenPod 取得應用程式記錄。將POD_ID替換為先前輸出內容中的 ID。kubectl logs loadgenerator-POD_ID
取得
hellosvc的外部 IP 位址:kubectl get service該指令會輸出類似以下的結果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hellosvc LoadBalancer 10.81.15.158 192.0.2.1 80:31127/TCP 33m kubernetes ClusterIP 10.81.0.1 <none> 443/TCP 93m loadgensvc ClusterIP 10.81.15.155 <none> 80/TCP 4m52s
向
hellosvc傳送要求。將EXTERNAL_IP替換為hellosvc的外部 IP 位址。curl http://EXTERNAL_IP
可使用 Cloud Service Mesh
您現在已將應用程式部署至 GKE。loadgen可以使用 Kubernetes DNS (hellosvc:80) 將要求傳送至 server,您也可以使用外部 IP 位址將要求傳送至 server。雖然 Kubernetes 提供許多功能,但缺少一些服務相關資訊:
- 服務如何互動?這些服務之間的關係為何?流量如何在服務之間流動?您知道
loadgen會向server傳送要求,但假設您不熟悉這個應用程式。您無法透過查看 GKE 上執行中的 Pod 清單來回答這些問題。 - 指標:
server需要多久時間才能回應傳入的要求?server每秒收到的要求數 (RPS) 為何?是否有任何錯誤回應? - 安全性資訊:
loadgen和server之間的流量是純文字HTTP還是 mTLS?
Cloud Service Mesh 可協助您解答這些問題。Cloud Service Mesh 是 Google Cloud代管的開放原始碼 Istio 專案版本。Cloud Service Mesh 會在每個 Pod 中放置 Envoy Sidecar Proxy,Envoy Proxy 會攔截所有傳入和傳出應用程式容器的流量。這表示 server 和 loadgen 各自取得 Envoy Sidecar Proxy,且從 loadgen 到 server 的所有流量都會由 Envoy Proxy 進行中介。這些 Envoy Proxy 之間的連線會形成服務網格。這項服務網格架構會在 Kubernetes 上方提供控制層。
由於 Envoy Proxy 是在自己的容器中執行,因此您可以在 GKE 叢集上安裝 Cloud Service Mesh,而不必大幅變更應用程式程式碼。不過,您在準備應用程式,以便使用 Cloud Service Mesh 檢測時,有幾個關鍵做法:
- 所有容器的服務:
server和loadgenDeployment 都已附加 Kubernetes 服務。即使是loadgen,雖然不會收到任何傳入要求,但也有服務。 - 服務中的通訊埠必須命名:雖然 GKE 允許您定義未命名的服務通訊埠,但 Cloud Service Mesh 要求您提供與通訊埠通訊協定相符的通訊埠名稱。在 YAML 檔案中,
server的通訊埠名為http,因為server使用HTTP通訊協定。如果service使用gRPC,請將通訊埠命名為grpc。 - Deployment 加上標籤:這樣您就能使用 Cloud Service Mesh 流量管理功能,例如在相同服務的不同版本之間分配流量。
安裝 Cloud Service Mesh
請參閱 Cloud Service Mesh 安裝指南,按照說明在叢集上安裝 Cloud Service Mesh。
清除所用資源
為避免因為本教學課程所用資源,導致系統向 Google Cloud 帳戶收取費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。
如要清除資源,請刪除 GKE 叢集。刪除叢集會刪除組成容器叢集的所有資源,例如運算執行個體、磁碟和網路資源。
gcloud container clusters delete asm-ready
後續步驟
進一步瞭解本教學課程使用的技術:
進一步瞭解工具:
進一步瞭解 Kubernetes 概念: