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.py啟動時,
server會顯示下列內容: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.py啟動時,
loadgen會輸出類似下列內容的訊息: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。
範例隨附 server 和 loadgen 的 Dockerfile,其中包含建構映像檔所需的所有指令。以下是 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 映像檔並推送至私人 Container Registry 時,您會使用
PROJECT_ID和GCR_REPO的值來標記 Docker 映像檔。設定 Google Cloud CLI 的預設 Google Cloud 專案。
gcloud config set project $PROJECT_ID
設定 Google Cloud CLI 的預設可用區。
gcloud config set compute/zone us-central1-b請確認專案已啟用 Container Registry 服務。Google Cloud
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 是 Kubernetes 物件,代表一組相同的 Pod。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。您無法在叢集外部使用這個 DNS 名稱,例如從 Cloud Shell。
Kubernetes 資訊清單
從原始碼執行應用程式時,您使用了命令式指令:python3 server.py
命令式是指以動詞為主的「執行這項操作」。
相較之下,Kubernetes 採用宣告式模型運作。也就是說,您不必明確指示 Kubernetes 該怎麼做,而是提供 Kubernetes 預期狀態。舉例來說,Kubernetes 會視需要啟動及終止 Pod,確保實際系統狀態符合所需狀態。
您可以在一組資訊清單或 YAML 檔案中指定所需狀態。YAML 檔案包含一或多個 Kubernetes 物件的規格。
範例包含 server 和 loadgen 的 YAML 檔案。每個 YAML 檔案都會指定 Kubernetes Deployment 物件和 Service 的所需狀態。
伺服器
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 代理程式會在自己的容器中執行,因此您可以在 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 概念: