使用 Google Kubernetes Engine (GKE) 部署、擴充及更新網站

1. 簡介

執行網站和應用程式並不容易。

發生錯誤的情況包括:伺服器異常終止、增加的需求增加,因而必須利用更多資源,而且在不停機的情況下進行變更會相當複雜且令人壓力。

請設想一下,這項工具可以幫助您完成上述所有事務,甚至可以直接使用,有了 GKE,實現上述所有目標並不容易!在本程式碼研究室中,您將假定開發人員負責為一間虛構公司 (Fancy Store) 經營電子商務網站的開發人員。由於資源調度和服務中斷方面的問題,您的任務是將應用程式部署至 GKE!

這些練習經過排序,以反映常見的雲端開發人員體驗:

  1. 建立 GKE 叢集。
  2. 建立 Docker 容器。
  3. 將容器部署至 GKE。
  4. 透過服務公開容器。
  5. 將容器擴充為多個備用資源。
  6. 修改網站。
  7. 推出新版本時完全不必停機。

架構圖

ddba666bd2b02d0d.png

課程內容

  • 如何建立 GKE 叢集
  • 如何建立 Docker 映像檔
  • 如何將 Docker 映像檔部署至 Kubernetes
  • 如何在 Kubernetes 上調度應用程式資源
  • 如何在 Kubernetes 上執行滾動式更新

必要條件

  • 具備管理員權限的 Google 帳戶,可建立專案或具備專案擁有者角色的專案
  • 對 Docker 和 Kubernetes 有基本的瞭解 (如果不熟悉基本知識,請立即參閱 DockerKubernetes)。

2. 環境設定

自修環境設定

如果您還沒有 Google 帳戶,請先建立帳戶。登入 Google Cloud 控制台,然後建立新專案。

53dad2cefdae71da.png

螢幕截圖取自 2016-02-10 12:45:26.png

請注意,專案 ID 在所有的 Google Cloud 專案中均是不重複的名稱 (上述名稱已有人使用,無法協助您解決問題!)。這個 ID 之後會稱為 PROJECT_ID

接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Google Cloud 資源。Google Cloud 的新使用者符合免費試用$300 美元的資格。如果不是新使用者,也不必擔心,因為程式碼研究室不會向您收取超過數美元的費用。不過,如果您耗用更多資源或讓程式碼繼續運作,程式碼研究室的成本可能會增加 (請參閱結尾的「清理」一節)。詳情請參閱「定價」一文。

Cloud Shell

雖然您可以使用筆記型電腦遠端操作 Google Cloud 和 GKE,但在程式碼研究室中使用 Cloud Shell (在 Cloud 中執行的指令列環境)。

這種以 Debian 為基礎的虛擬機器,搭載各種您需要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。換言之,本程式碼研究室只需要在 Chromebook 上運作即可。

  1. 如要透過 Cloud 控制台啟用 Cloud Shell,只要點選「啟用 Cloud Shell」 圖示 fEbHefbRynwXpq1vj2wJw6Dr17O0np8l-WOekxAZYlZQIORsWQE_xJl-cNhogjATLn-YxLVz8CgLvIW1Ncc0yXKJsfzJGMYgUeLsVB7zSwz7p6ItNgx4tXqQjag7BfWPcZN5kP-X3Q 即可 (整個佈建作業只需幾分鐘的時間,操作完畢即可)。

I5aEsuNurCxHoDFjZRZrKBdarPPKPoKuExYpdagmdaOLKe7eig3DAKJitIKyuOpuwmrMAyZhp5AXpmD_k66cBuc1aUnWlJeSfo_aTKPY9aNMurhfegg1CYaE11jdpSTYNNIYARe01A

Screen Shot 2017-06-14 at 10.13.43 PM.png

連線至 Cloud Shell 後,您應會發現自己通過驗證,且專案已設為 PROJECT_ID

gcloud auth list

指令輸出

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

指令輸出

[core]
project = <PROJECT_ID>

如因故未設定專案,請直接發出以下指令:

gcloud config set project <PROJECT_ID>

正在尋找 PROJECT_ID 嗎?查看您在設定步驟中使用的 ID,或在 Cloud 控制台資訊主頁查詢:

R7chO4PKQfLC3bvFBNZJALLTUiCgyLEq_67ECX7ohs_0ZnSjC7GxDNxWrJJUaoM53LnqABYamrBJhCuXF-J9XBzuUgaz7VvaxNrkP2TAn93Drxccyj2-5zz4AxL-G3hzxZ4PsM5HHQ

根據預設,Cloud Shell 也會設定一些環境變數,方便您之後執行指令。

echo $GOOGLE_CLOUD_PROJECT

指令輸出

<PROJECT_ID>
  1. 最後,進行預設可用區和專案設定。
gcloud config set compute/zone us-central1-f

您可以選擇各種不同的可用區。詳情請參閱「區域與可用區

3. 建立 GKE 叢集

您有了運作中的開發人員環境,接下來需要 GKE 叢集,才能將網站部署至其中!建立叢集前,您必須確保已啟用適當的 API。執行下列指令,啟用 Container API:

gcloud services enable container.googleapis.com

您現在可以建立叢集了!請按照下列步驟建立具有 3 個節點並命名為 fancy-cluster 的叢集:

gcloud container clusters create fancy-cluster --num-nodes 3

可能需要幾分鐘時間才能建立叢集。之後,請執行下列指令,查看叢集的三個工作站虛擬機器 (VM) 執行個體:

gcloud compute instances list

輸出:

NAME                                          ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
gke-fancy-cluster-default-pool-ad92506d-1ng3  us-east4-a  n1-standard-1               10.150.0.7   XX.XX.XX.XX    RUNNING
gke-fancy-cluster-default-pool-ad92506d-4fvq  us-east4-a  n1-standard-1               10.150.0.5   XX.XX.XX.XX    RUNNING
gke-fancy-cluster-default-pool-ad92506d-4zs3  us-east4-a  n1-standard-1               10.150.0.6   XX.XX.XX.XX    RUNNING

您也可以在 Cloud 控制台中查看叢集和相關資訊。按一下左上角的選單按鈕,向下捲動至 Kubernetes Engine,然後按一下「叢集」。您應該會看到名為 fancy-cluster 的叢集。

795c794b03c5d2b0.png

6b394dfb8a6031f2.png

恭喜!您已建立第一個叢集!

4. 複製原始碼存放區

由於這是現有網站,因此您只需要從存放區複製原始碼,即可專心建立 Docker 映像檔並部署至 GKE。

執行下列指令,將原始碼存放區複製到 Cloud Shell 執行個體,並變更為適當的目錄。您也會安裝 Node.js 依附元件,以便在部署應用程式前先進行測試。

cd ~
git clone https://github.com/googlecodelabs/monolith-to-microservices.git
cd ~/monolith-to-microservices
./setup.sh

即可複製存放區、變更目錄,並安裝在本機執行應用程式所需的依附元件。執行該指令碼可能需要幾分鐘的時間。

做好盡職調查並測試應用程式。執行下列指令來啟動網路伺服器:

cd ~/monolith-to-microservices/monolith
npm start

輸出:

Monolith listening on port 8080!

如要預覽應用程式,請點選 Cloud Shell 選單中的網頁預覽圖示,然後選取通訊埠 8080 的「預覽」。

5869738f0e9ec386.png

系統應該會開啟新視窗,讓您查看花俏商店的實際運作情形!

9ed25c3f0cbe62fa.png

瀏覽網站後,即可關閉該視窗。在終端機視窗中按下 Control+C (Windows 或 Mac),即可停止網路伺服器處理程序。

5. 使用 Cloud Build 建立 Docker 容器

現在您的來源檔案已準備就緒,接著要進行應用程式 Docker 化!

一般來說,您必須採取兩步驟,也就是建構 Docker 容器並推送至登錄檔,儲存 GKE 提取的映像檔。不過,您可以使用 Cloud Build 建立 Docker 容器,並使用單一指令將映像檔置於 Container Registry 中,讓生活更便利!如要查看建立並推送 Docker 檔案的手動程序,請參閱 Container Registry 快速入門導覽課程

Cloud Build 會壓縮目錄中的檔案,並將檔案移至 Cloud Storage 值區。接著,建構程序會從值區接收檔案,並使用 Dockerfile 執行 Docker 建構程序。由於您已將 --tag 旗標的主機指定為 gcr.io,用於 Docker 映像檔,系統會將產生的 Docker 映像檔推送至 Container Registry。

首先,請執行下列指令來啟用 Cloud Build API:

gcloud services enable cloudbuild.googleapis.com

啟用 API 後,請在 Cloud Shell 中執行下列指令來啟動建構程序:

cd ~/monolith-to-microservices/monolith
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 .

這項程序需要幾分鐘才能完成,但作業完成後,終端機中會顯示下列輸出內容:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ID                                    CREATE_TIME                DURATION  SOURCE                                                                                  IMAGES                              STATUS
1ae295d9-63cb-482c-959b-bc52e9644d53  2019-08-29T01:56:35+00:00  33S       gs://<PROJECT_ID>_cloudbuild/source/1567043793.94-abfd382011724422bf49af1558b894aa.tgz  gcr.io/<PROJECT_ID>/monolith:1.0.0  SUCCESS

如要查看建構作業記錄或即時觀看程序,請前往 Cloud 控制台。按一下左上角的選單按鈕,向下捲動至「C/CD」,接著按一下「Cloud Build」,最後點選「記錄」。在這裡,您可以查看先前版本的清單,但只能找到您建立的版本。

4c753ede203255f6.png

按一下版本 ID,即可查看該版本的所有詳細資料,包括記錄輸出。

在建構詳細資料頁面中,按一下建構資訊部分中的映像檔名稱,即可查看建立的容器映像檔。

6e88ed1643dfe629.png

6. 將容器部署至 GKE

完成將網站容器化並推送至 Container Registry 之後,您就能將容器部署至 Kubernetes!

如要在 GKE 叢集中部署及管理應用程式,您必須與 Kubernetes 叢集管理系統通訊。一般來說,您可以使用 kubectl 指令列工具進行這項操作。

Kubernetes 會以 Pod 的形式呈現應用程式,這是容器 (或緊密結合的容器群組) 的單位。Pod 是 Kubernetes 中最小的可部署單位。這裡,每個 Pod 僅包含單體容器。

如要部署應用程式,您必須建立部署。Deployment 會管理應用程式的多個副本 (稱為備用資源),並安排這些副本在叢集中的個別節點上執行。在這種情況下,Deployment 只會執行應用程式的一個 Pod。Deployment 必須透過建立 ReplicaSet 來確保這一點。ReplicaSet 會確保指定的備用資源數量一律在運作中。

kubectl create deployment 指令會讓 Kubernetes 在具有 1 備用資源的叢集中建立名為 monolith 的 Deployment。

執行下列指令來部署應用程式:

kubectl create deployment monolith --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0

驗證部署

如要確認 Deployment 是否已成功建立,請執行下列指令 (Pod 狀態可能需要一點時間才顯示「執行中」):

kubectl get all

輸出:

NAME                            READY   STATUS    RESTARTS   AGE
pod/monolith-7d8bc7bf68-htm7z   1/1     Running   0          6m21s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.27.240.1   <none>        443/TCP   24h

NAME                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/monolith   1         1         1            1           20m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/monolith-7d8bc7bf68   1         1         1       20m

該輸出內容會顯示幾個項目。您會看到自己的 DeploymentReplicaSet 以及所需 Pod 計數和正在執行的 Pod看來您已成功建立所有內容!

如要個別查看資源,您可以執行下列指令:

# Show pods
kubectl get pods

# Show deployments
kubectl get deployments

# Show replica sets
kubectl get rs

#You can also combine them
kubectl get pods,deployments

如要瞭解 Kubernetes 的完整優點,您可以模擬伺服器當機情形、刪除 Pod,看看會發生什麼情況!

從上一個指令複製 Pod 名稱,然後執行下列指令來刪除該名稱:

kubectl delete pod/<POD_NAME>

如果速度夠快,可以執行先前的指令再次查看所有 Pod,然後應該會看到兩個終止,而另一個 Pod 建立或執行:

kubectl get all

輸出:

NAME                            READY   STATUS        RESTARTS   AGE
pod/monolith-7d8bc7bf68-2bxts   1/1     Running       0          4s
pod/monolith-7d8bc7bf68-htm7z   1/1     Terminating   0          9m35s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.27.240.1   <none>        443/TCP   24h

NAME                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/monolith   1         1         1            1           24m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/monolith-7d8bc7bf68   1         1         1       24m

原因為何?ReplicaSet 發現 Pod 已終止並觸發新的 Pod,以達到所需的備用資源數量。稍後您將學習如何調度資源,確保有多個執行個體執行,如果其中一個執行個體下降,使用者不會看見任何停機時間。

7. 公開 GKE 部署作業

您已將應用程式部署至 GKE,但無法在叢集外存取應用程式。根據預設,您在 GKE 上執行的容器無法透過網際網路存取,因為這些容器沒有外部 IP 位址。您必須透過服務資源,將應用程式明確公開到來自網際網路的流量。Service 可為應用程式的 Pod 提供網路和 IP 支援。GKE 會為您的應用程式建立外部 IP 和負載平衡器 (費用取決於)。

執行下列指令,將網站公開到網際網路:

kubectl expose deployment monolith --type=LoadBalancer --port 80 --target-port 8080

輸出:

service/monolith exposed

存取服務

GKE 會將外部 IP 位址指派給服務資源,而非 Deployment。如要找出 GKE 為應用程式佈建的外部 IP,可以使用 kubectl get service 指令檢查 Service:

kubectl get service

輸出:

NAME         CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
monolith     10.3.251.122    203.0.113.0     80:30877/TCP     3d

決定應用程式的外部 IP 位址後,請複製。將瀏覽器指向該網址 (例如 http://203.0.113.0),檢查您的應用程式是否可供存取。

9ed25c3f0cbe62fa.png

您應該會看見先前測試的網站!恭喜!您的網站完全在 Kubernetes 中運作!

8. 調度 GKE 部署作業資源

您已在 GKE 中建構了執行中的應用程式執行個體,並將執行個體公開至網際網路,您的網站變得如此熱門!您需要將應用程式擴充為多個執行個體,以利處理流量。瞭解如何將應用程式擴充至最多三個備用資源。

執行下列指令,將 Deployment 擴充最多三個備用資源:

kubectl scale deployment monolith --replicas=3

輸出:

deployment.apps/monolith scaled

驗證經過資源調度的部署作業

如要確認 Deployment 是否成功調度資源,請執行下列指令:

kubectl get all

輸出:

NAME                            READY   STATUS    RESTARTS   AGE
pod/monolith-7d8bc7bf68-2bxts   1/1     Running   0          36m
pod/monolith-7d8bc7bf68-7ds7q   1/1     Running   0          45s
pod/monolith-7d8bc7bf68-c5kxk   1/1     Running   0          45s

NAME                 TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
service/kubernetes   ClusterIP      10.27.240.1    <none>         443/TCP        25h
service/monolith     LoadBalancer   10.27.253.64   XX.XX.XX.XX   80:32050/TCP   6m7s

NAME                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/monolith   3         3         3            3           61m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/monolith-7d8bc7bf68   3         3         3       61m

您應該會看見三個 Pod 正在執行中。另請注意,您的 Deployment 和 ReplicaSet 現已指定三個數量。

9. 變更網站

您的行銷團隊要求您變更網站的首頁。他們認為透過說明公司和實際銷售的產品,取得更豐富的資訊。在這部分,您要在首頁加入一些文字,供行銷團隊參考!我們的其中一位開發人員似乎已使用 index.js.new 檔案名稱建立了變更。您可以將檔案複製到 index.js,變更內容應該會隨之反映。按照下方說明操作,進行適當變更。

執行下列指令,將更新後的檔案複製到正確的檔案名稱,並顯示檔案內容來驗證變更:

cd ~/monolith-to-microservices/react-app/src/pages/Home
mv index.js.new index.js
cat ~/monolith-to-microservices/react-app/src/pages/Home/index.js

顯示的程式碼應如下所示:

/*
Copyright 2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
const useStyles = makeStyles(theme => ({
  root: {
    flexGrow: 1
  },
  paper: {
    width: "800px",
    margin: "0 auto",
    padding: theme.spacing(3, 2)
  }
}));
export default function Home() {
  const classes = useStyles();
  return (
    <div className={classes.root}>
      <Paper className={classes.paper}>
        <Typography variant="h5">
          Fancy Fashion &amp; Style Online
        </Typography>
        <br />
        <Typography variant="body1">
          Tired of mainstream fashion ideas, popular trends and societal norms?
          This line of lifestyle products will help you catch up with the Fancy trend and express your personal style.
          Start shopping Fancy items now!
        </Typography>
      </Paper>
    </div>
  );
}

您已更新 React 元件,但需要建構 React 應用程式,才能產生靜態檔案。執行下列指令即可建構 React 應用程式,並將其複製到單體公開目錄:

cd ~/monolith-to-microservices/react-app
npm run build:monolith

程式碼已更新完畢,您需要重新建構 Docker 容器並發布至 Container Registry。您可以使用先前的指令,但這次只能更新版本標籤!

執行下列指令,使用更新版 2.0.0 版本的新 Cloud Build:

cd ~/monolith-to-microservices/monolith

#Feel free to test your application
npm start

gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 .

在終端機視窗中按下 Control+C (Windows 或 Mac),即可停止網路伺服器處理程序。

在下一節中,您將使用該映像檔更新應用程式,完全不會停機。

10. 不必停機即可更新網站

變更已完成,行銷團隊十分樂意更新內容!該更新網站時,應確保使用者不會受到干擾。請按照下方操作說明更新網站。

採用 GKE 的滾動式更新功能時,即使系統在所有執行中的備用資源中,將舊容器映像檔的執行個體取代為新的映像檔,應用程式仍能維持可用且可供使用。

您可以透過指令列,向 Kubernetes 使用下列指令將 Deployment 的映像檔更新為新版本:

kubectl set image deployment/monolith monolith=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0

輸出:

deployment.apps/monolith image updated

驗證部署作業

您可以執行下列指令,驗證 Deployment 更新:

kubectl get pods

輸出:

NAME                        READY   STATUS              RESTARTS   AGE
monolith-584fbc994b-4hj68   1/1     Terminating         0          60m
monolith-584fbc994b-fpwdw   1/1     Running             0          60m
monolith-584fbc994b-xsk8s   1/1     Terminating         0          60m
monolith-75f4cf58d5-24cq8   1/1     Running             0          3s
monolith-75f4cf58d5-rfj8r   1/1     Running             0          5s
monolith-75f4cf58d5-xm44v   0/1     ContainerCreating   0          1s

您會看到正在建立三個新的 Pod,舊的 Pod 也關閉。您可判斷新舊年齡。之後,只會再看到三個 Pod,也就是三個更新後的 Pod。

如要驗證變更,請再次前往負載平衡器的外部 IP,並留意應用程式已更新。

執行下列指令,列出服務,並查看您忘記的 IP 位址:

kubectl get svc

你的網站應會顯示新增至首頁元件的文字!

8006c9938dbd5aa5.png

11. 清除所用資源

刪除 Git 存放區

cd ~
rm -rf monolith-to-microservices

刪除 Container Registry 映像檔

注意:如果您建立了其他版本,您也可以使用相同的語法刪除這些映像檔。本程式碼研究室假設您只有兩個標記。

# Delete the container image for version 1.0.0 of our monolith
gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --quiet

# Delete the container image for version 2.0.0 of our monolith
gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 --quiet

從 Cloud Storage 刪除 Cloud Build 構件

注意:如果您使用 Cloud Build 處理本程式碼研究室以外的構件,就必須從 Cloud Storage 值區 gs://<PROJECT_ID>_cloudbuild/source 中手動刪除來源。

# The following command will take all source archives from all builds and delete them from cloud storage

# Run this command to print all sources:
# gcloud builds list | awk 'NR > 1 {print $4}'

gcloud builds list | awk 'NR > 1 {print $4}' | while read line; do gsutil rm $line; done

刪除 GKE 服務

kubectl delete service monolith
kubectl delete deployment monolith

刪除 GKE 叢集

gcloud container clusters delete fancy-cluster

注意:這個指令可能需要一點時間才能完成。

12. 恭喜!

您已在 GKE 中部署、擴充及更新網站。您現在已熟悉 Docker 和 Kubernetes 的使用方式!

其他資源