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 和相關服務完成啟用。 這可能需要幾分鐘的時間。
-
Verify that billing is enabled for your Google Cloud project.
本教學課程使用 Cloud Shell,這會佈建執行 Debian 型 Linux 作業系統的 g1-small Compute Engine 虛擬機器 (VM)。
準備 Cloud Shell
使用 Cloud Shell 的優點如下:
- Python 2 和 Python 3 開發環境 (包括
virtualenv
) 都已設定完成。 - 本教學課程使用的
gcloud
、docker
、git
和kubectl
指令列工具已安裝完畢。 您可以選擇使用下列文字編輯器:
程式碼編輯器:按一下 Cloud Shell 視窗頂端的 即可存取。
Emacs、Vim 或 Nano,可透過 Cloud Shell 的指令列存取。
In the Google Cloud console, activate Cloud Shell.
下載程式碼範例
下載
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:8080
server
會回應: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
,適用於 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
替換為專案 ID。Google Cloudexport PROJECT_ID="PROJECT_ID"
export GCR_REPO="asm-ready"
建構 Docker 映像檔並推送至私人 Container Registry 時,您會使用
PROJECT_ID
和GCR_REPO
的值標記映像檔。設定 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 的資源。部署作業:部署作業是 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 提供穩定的網路端點。 Service 分為幾種類型。server
使用LoadBalancer
,公開外部 IP 位址,讓您從叢集外部連線至server
。Kubernetes 也有內建的 DNS 系統,可將 DNS 名稱 (例如
helloserver.default.cluster.local
) 指派給 Service。這樣一來,叢集內的 Pod 就能透過穩定位址連線至叢集中的其他 Pod。您無法在叢集外部使用這個 DNS 名稱,例如從 Cloud Shell。
Kubernetes 資訊清單
從原始碼執行應用程式時,您使用了命令式指令:python3 server.py
命令式是指以動詞為主的語氣:「執行這項操作」。
相較之下,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
) 會對應至「helloserver
」Pod 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
改成您的專案 ID。 Google Cloud儲存並關閉
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
改成您的專案 ID。 Google Cloud儲存並關閉
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
從
loadgen
Pod 取得應用程式記錄。將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 補充 Proxy,Envoy Proxy 會攔截應用程式容器的所有傳入和傳出流量。也就是說,server
和 loadgen
各自取得 Envoy 補充 Proxy,且從 loadgen
到 server
的所有流量都會由 Envoy Proxy 媒介。這些 Envoy Proxy 之間的連線會形成服務網格。這項服務網格架構會在 Kubernetes 上方提供控制層。
由於 Envoy 代理程式會在自己的容器中執行,因此您可以在 GKE 叢集上安裝 Cloud Service Mesh,不必大幅變更應用程式程式碼。不過,您準備應用程式以透過 Cloud Service Mesh 進行檢測時,有幾項重要做法:
- 所有容器的服務:
server
和loadgen
Deployment 都已附加 Kubernetes 服務。即使是loadgen
(未收到任何傳入要求),也有服務。 - 服務中的通訊埠必須命名:雖然 GKE 允許您定義未命名的服務通訊埠,但 Cloud Service Mesh 要求您為通訊埠提供名稱,且該名稱須與通訊埠的通訊協定相符。在 YAML 檔案中,
server
的通訊埠命名為http
,因為server
使用HTTP
通訊協定。如果service
使用gRPC
,您會將通訊埠命名為grpc
。 - 部署作業會加上標籤:方便您使用 Cloud Service Mesh 流量管理功能,例如在同一服務的不同版本之間拆分流量。
安裝 Cloud Service Mesh
請參閱 Cloud Service Mesh 安裝指南,按照說明在叢集上安裝 Cloud Service Mesh。
清除所用資源
如要避免系統向您的 Google Cloud 帳戶收取本教學課程中所用資源的相關費用,請刪除含有該項資源的專案,或者保留專案但刪除個別資源。
如要清除資源,請刪除 GKE 叢集。刪除叢集會一併刪除容器叢集的組成資源,例如運算執行個體、磁碟和網路資源。
gcloud container clusters delete asm-ready
後續步驟
進一步瞭解本教學課程使用的技術:
進一步瞭解相關工具:
進一步瞭解 Kubernetes 概念: