搭配 NodeJS 使用 Cloud Workstations 進行內部迴圈開發

1. 總覽

本研究室介紹的功能和功能,協助負責在容器化環境中開發 NodeJS 應用程式的軟體工程師,簡化開發工作流程。一般的容器開發作業會要求使用者瞭解容器和容器建構程序的詳細資料。此外,開發人員通常必須中斷流程,從 IDE 中移出 IDE,才能在遠端環境中對應用程式進行測試及偵錯。有了本教學課程中提及的工具和技術,開發人員不必離開 IDE,就能有效地使用容器化應用程式。

學習目標

在本研究室中,您將瞭解在 Google Cloud 中使用容器進行開發的方法,包括:

  • 建立範例應用程式 Nodejs 應用程式
  • 設定適用於容器開發的 Nodejs 應用程式
  • 編寫簡易 CRUD 靜態服務
  • 部署至 GKE
  • 偵錯錯誤狀態
  • 使用中斷點 / 記錄
  • 熱部署變更回 GKE
  • 選用:整合 CloudSQL 來維持後端持續性

58a4cdd3ed7a123a.png

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 未使用的字元字串。您隨時可以更新這項資訊。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。此外,您也可以自行嘗試,看看系統是否提供該付款方式。在完成這個步驟後就無法變更,而且在專案期間仍會保持有效。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行這個程式碼研究室並不會產生任何費用,如果有的話。如要關閉資源,以免系統產生本教學課程結束後產生的費用,您可以刪除自己建立的資源,或刪除整個專案。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。

啟動 Cloud Shell 編輯器

本研究室專為與 Google Cloud Shell 編輯器搭配使用而設計和測試。如要存取編輯器

  1. 前往 https://console.cloud.google.com 存取您的 Google 專案。
  2. 按一下右上角的「Cloud Shell 編輯器」圖示

8560cc8d45e8c112.png

  1. 視窗底部隨即會開啟新的窗格
  2. 點選「開啟編輯器」按鈕

9e504cb98a6a8005.png

  1. 編輯器隨即開啟,右側會顯示多層檢視,中央區則顯示編輯者
  2. 畫面底部應會顯示終端機窗格
  3. 如果終端機「未」開啟,使用 `ctrl+` 的按鍵組合開啟新的終端機視窗

設定 gcloud

在 Cloud Shell 中設定專案 ID 和您要部署應用程式的區域。將其儲存為 PROJECT_IDREGION 變數。

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

佈建本研究室中使用的基礎架構

在本研究室中,您會將程式碼部署至 GKE,並存取 CloudSQL 資料庫中儲存的資料。下列設定指令碼可協助您完成這個基礎架構的設定。

  1. 下載設定指令碼並設為可執行狀態。
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/setup_with_cw.sh
chmod +x setup_with_cw.sh
  1. 開啟 setup_with_cw.sh 檔案,然後編輯目前設為 CHANGEME 的密碼值
  2. 執行設定指令碼,建立將在本研究室中使用的 GKE 叢集和 CloudSQL 資料庫
./setup_with_cw.sh &

Cloud Workstations 叢集

  1. 在 Cloud 控制台中開啟 Cloud Workstations。等待叢集處於 READY 狀態。

305e1a3d63ac7ff6.png

建立工作站設定

  1. 如果 Cloud Shell 工作階段已中斷連線,請按一下 [重新連線]然後執行 gcloud cli 指令設定專案 ID。在執行指令前,請先將下方的範例專案 ID 替換為 qwiklabs 專案 ID。
gcloud config set project qwiklabs-gcp-project-id
  1. 請在終端機中下載並執行以下指令碼,以便建立 Cloud Workstations 設定。
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/workstation_config_setup.sh
chmod +x workstation_config_setup.sh
./workstation_config_setup.sh
  1. 在「設定」部分下方確認結果。系統需要 2 分鐘的時間才能轉換為「就緒」狀態。

c8f0b8662fdb827e.png

  1. 開啟控制台中的 Cloud Workstations 並建立新的執行個體。

a53adeeac81a78c8.png

  1. 將名稱變更為 my-workstation,並選取現有設定:codeoss-js

675d83f30c1319df.png

  1. 在「Workstations」區段下方驗證結果。

bf67586e6695852.png

啟動工作站

  1. 啟動及啟動工作站。啟動工作站需要幾分鐘的時間。

a9ad54f4b4b668e9.png

  1. 按一下網址列中的圖示,允許第三方 Cookie。1b8923e2943f9bc4.png

fcf9405b6957b7d7.png

  1. 按一下「網站無法正常運作嗎?」。

36a84c0e2e3b85b.png

  1. 按一下 [允許 Cookie]。

2259694328628fba.png

  1. 工作站啟動後,您會看到 Code OSS IDE。按一下「標示為完成」選用於「入門指南」 其中一個工作站 IDE

94874fba9b74cc22.png

3. 建立新的 Nodejs 範例應用程式

在本節中,您將建立新的 Nodejs 應用程式。

  1. 開啟新的終端機。

c31d48f2e4938c38.png

  1. 在 Cloud Shell 中建立名為「mynodejsapp」的新目錄
mkdir mynodejsapp

若您看到這則訊息,請按一下「允許」按鈕,以便複製內容到工作站。

58149777e5cc350a.png

  1. 請變更為這個目錄,然後以工作區的形式開啟。這項操作會在新建立的資料夾中建立工作區設定,重新載入編輯器。
cd mynodejsapp && code-oss-cloud-workstations -r --folder-uri="$PWD"
  1. 再次開啟新的終端機。使用 NVM 安裝節點和 NPM。
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash
        
        # This loads nvm bash_completion
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  

nvm install stable

nvm alias default stable

4. 建立新的範例應用程式

  1. 將應用程式初始化

執行下列指令來建立 package.json 檔案

npm init
    Choose the `entry point: (index.js) src/index.js` and leave default values for the rest of the parameters. This will create the `package.json` file with following contents
{
  "name": "mynodejsapp",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
  1. 新增進入點

在 IDE 中開啟並編輯 package.json 檔案,將 start 指令加入指令碼 "start": "node src/index.js",。變更後的指令碼應如以下程式碼片段所示:

"scripts": {
    "start": "node src/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  1. 新增 Express 依附元件

要新增的程式碼也會使用 express,因此讓我們將依附元件新增至這個 package.json 檔案。完成所有變更後,package.json 檔案應如下所示。

{
 "name": "mynodejsapp",
 "version": "1.0.0",
 "description": "",
 "main": "src/index.js",
 "scripts": {
   "start": "node src/index.js",
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "dependencies": {
   "express": "^4.17.3"
 }
}
  1. 建立 index.js 檔案

在 Explorer 檢視畫面中選取「New Folder」,建立名為 src 的來源目錄。

eb507d48f283ce46.png

建立 src/index.js 檔案

3e3e6e6062e501fc.png

使用下列程式碼

const express = require('express');
const app = express();
const PORT = 8080;

app.get('/', (req, res) => {
    var message="Greetings from Node";
    res.send({ message: message });
  });

app.listen(PORT, () => {
  console.log(`Server running at: http://localhost:${PORT}/`);

});

請注意,PORT 已設為 8080

產生資訊清單

Skaffold 提供整合式工具,可簡化容器開發程序。在這個步驟中,您將初始化 Skaffold,並自動建立基礎 YAML 檔案。執行下列指令來開始這項程序。

在終端機中執行下列指令

skaffold init --generate-manifests

出現提示時:

  • 輸入通訊埠 8080
  • 輸入 y 來儲存設定

工作區向量「skaffold.yaml」和「deployment.yaml」已新增兩個檔案

更新應用程式名稱

設定中的預設值與您的應用程式名稱不符。更新檔案以參照您的應用程式名稱,而非使用預設值。

  1. 變更 Skaffold 設定中的項目
  • 開啟「skaffold.yaml
  • 選取目前設為「package-json-image」的映像檔名稱
  • 按一下滑鼠右鍵,選擇「變更所有出現項目」
  • 輸入新名稱,格式為「mynodejsapp
  1. 變更 Kubernetes 設定的項目
  • 開啟 deployment.yaml 檔案
  • 選取目前設為「package-json-image」的映像檔名稱
  • 按一下滑鼠右鍵,選擇「變更所有出現項目」
  • 輸入新名稱,格式為「mynodejsapp

請注意,在 skaffold.yaml 檔案中,build 區段使用 buildpacks 將應用程式容器化。這個程式碼不含 Dockerfile,開發人員不需要任何 docker 知識,就能將這個應用程式容器化。

此外,這個 Skaffold 設定也會自動在編輯器和執行中的容器之間啟用熱同步處理。您無需額外設定即可啟用熱同步。

5. 逐步完成開發程序

本節將逐步引導您使用 Cloud Code 外掛程式完成幾個步驟,藉此瞭解基本程序,並驗證範例應用程式的設定和設定。

Cloud Code 與 Skaffold 整合,簡化開發程序。按照下列步驟部署至 GKE 時,Cloud Code 和 Skaffold 會自動建構容器映像檔並推送至 Container Registry,然後將應用程式部署至 GKE。這會在背景執行,將詳細資料從開發人員流程中抽離出來。此外,Cloud Code 對容器型開發提供傳統的偵錯和熱同步功能,可改善您的開發程序。

登入 Google Cloud

  1. 按一下「Cloud Code」圖示,然後選取「登入 Google Cloud」:

1769afd39be372ff.png

  1. 按一下「繼續登入」。

923bb1c8f63160f9.png

  1. 查看終端機的輸出內容並開啟連結:

517fdd579c34aa21.png

  1. 使用 Qwiklabs 學生憑證登入。

db99b345f7a8e72c.png

  1. 選取「允許」:

a5376553c430ac84.png

  1. 複製驗證碼並返回「工作站」分頁。

6719421277b92eac.png

  1. 貼上驗證碼,然後按 Enter 鍵。

e9847cfe3fa8a2ce.png

新增 Kubernetes 叢集

  1. 新增叢集

62a3b97bdbb427e5.png

  1. 選取 Google Kubernetes Engine:

9577de423568bbaa.png

  1. 選取專案。

c5202fcbeebcd41c.png

  1. 選取「mycluster」在初始設定中建立的 ID

33863e94d1c5045f.png

  1. 叢集現在會顯示在 Cloud Code 下方的 Kubernetes 叢集清單中。從這裡瀏覽及探索叢集。

7e5f50662d4eea3c.png

使用 gcloud cli 設定目前的專案 ID

  1. 從 Qwiklabs 頁面複製這個研究室的專案 ID。

fcff2d10007ec5bc.png

  1. 在終端機中,執行 gcloud cli 指令設定專案 ID。在執行指令前替換範例專案 ID。請先提交專案 ID,再執行下方指令。
gcloud config set project qwiklabs-gcp-project-id

部署到 Kubernetes

  1. 在 Cloud Shell 編輯器底部的窗格中,選取「Cloud Code」 圖示 。

c5dd5a749136407b.png

  1. 在頂端的「開發工作階段」下方顯示的面板中,選取「在 Kubernetes 中執行」。如果出現提示,請選取「是」以使用目前的 Kubernetes 結構定義。

7da53b9480e8eb0d.png

  1. 首次執行指令時,畫面頂端會顯示提示,詢問您是否要使用目前的 Kubernetes 環境,請選取「是」。可接受並使用目前的內容。

a6e58a7f0d117391.png

  1. 接著系統會顯示提示,詢問要使用哪個 Container Registry。按下 Enter 鍵即可接受提供的預設值

13236a26c8dbe84f.png

  1. 選取下窗格中的「Output」分頁標籤,然後在下拉式選單中選取「Kubernetes: Run/Debug」,即可查看進度和通知

606ff9cdebc03dff.png

  1. 選取「Kubernetes: Run/Debug - 詳細」按一下管道下拉式選單中的右側,即可查看其他詳細資料和從容器串流的即時記錄檔

ab45d2574f4f2478.png

  1. 選取「Kubernetes:執行/偵錯」即可返回簡化的檢視畫面
  2. 建構和測試完成後,「Output」(輸出) 分頁標籤會顯示 Resource deployment/mynodejsapp status completed successfully,以及一個網址:「Forwarded URL from service demo-app: http://localhost:8080」
  3. 在 Cloud Code 終端機中,將滑鼠遊標懸停在輸出 (http://localhost:8080) 的網址上,然後在顯示的工具提示中,選取「 Follow Link」(追蹤連結)。

回應將為:

{"message":"Greetings from Node"}

熱重新載入

  1. 前往 src/index.js。將問候語訊息的程式碼編輯為 'Hello from Node'

請注意,在 Output 視窗 Kubernetes: Run/Debug 檢視畫面中,監看員會將更新的檔案與 Kubernetes 中的容器同步處理

Update initiated
File sync started for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
File sync succeeded for 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Update succeeded
  1. 如果切換至「Kubernetes: Run/Debug - Detailed」檢視畫面,就會看到檔案變更可辨識檔案變更,也會重新啟動節點。
files modified: [src/index.js]
Copying files:map[src/index.js:[/workspace/src/index.js]]togcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Syncing 1 files for gcr.io/myproject/mynodejsapp:latest@sha256:f554756b3b4d6c301c4b26ef96102227cfa2833270db56241248ae42baa1971a
Watching for changes...
[mynodejsapp]
[mynodejsapp]> mynodejsapp@1.0.0 start /workspace
[mynodejsapp]> node src/index.js
[mynodejsapp]
[mynodejsapp]Server running at: http://localhost:8080/
  1. 重新整理瀏覽器即可查看更新後的結果。

偵錯

  1. 前往「Debug」(偵錯) 檢視畫面,並停止目前的執行緒 647213126d7a4c7b.png
  2. 按一下底部選單中的 Cloud Code 並選取 Debug on Kubernetes,即可透過 debug 模式執行應用程式。

dbd0c6cfd9e9d0e9.png

  • 請注意,在 Output 視窗的 Kubernetes Run/Debug - Detailed 檢視畫面中,Skaffold 會在偵錯模式部署這個應用程式。
  • 建構及部署應用程式需要幾分鐘的時間。這次您會看到附加偵錯工具。
Port forwarding pod/mynodejsapp-6bbcf847cd-vqr6v in namespace default, remote port 9229 -> http://127.0.0.1:9229
[mynodejsapp]Debugger attached.
  1. 底部狀態列的顏色會從藍色變成橘色,表示目前處於偵錯模式。

d1224f12cd659995.png

  1. 請注意,在 Kubernetes Run/Debug 檢視畫面中,可進行偵錯的容器已啟動
**************URLs*****************
Forwarded URL from service mynodejsapp-service: http://localhost:8080
Debuggable container started pod/mynodejsapp-deployment-6bc7598798-xl9kj:mynodejsapp (default)
Update succeeded
***********************************

善用中斷點

  1. 打開 src/index.js
  2. 找出讀取 var message="Hello from Node"; 的陳述式
  3. 按一下行號左側的空白處,為該行新增中斷點。系統會顯示紅色指標,說明已設定中斷點
  4. 重新載入瀏覽器並留意偵錯工具,會在中斷點停止程序,然後針對在 GKE 中從遠端執行的應用程式調查變數和狀態
  5. 點選進入「變數」部分,找出 "message" 變數。
  6. 按下「Step over 7cfdee4fd6ef5c3a.png」按鈕執行線條
  7. 觀察目前"message"變數變更至 "Hello from Node"
  8. 按兩下變數名稱「target」在彈出式視窗中,將值變更為其他值,例如 "Hi from Node"
  9. 按一下偵錯控制台中的 [繼續] 按鈕
  10. 請在瀏覽器中查看回應,以便顯示剛才輸入的更新值。
  11. 停止「Debug」模式,方法是按下停止按鈕 647213126d7a4c7b.png,然後再次按一下中斷點來移除中斷點。

6. 開發簡易的 CRUD 靜態服務

此時您的應用程式已全面完成容器化開發作業,您也完成了 Cloud Code 的基本開發工作流程。在接下來的各節中,您將學到以下內容:新增連結至 Google Cloud 代管資料庫的 REST 服務端點。

設定依附元件

應用程式程式碼會使用資料庫來保存其餘服務資料。在 package.json 檔案中加入以下內容,確保依附元件可用

  1. package.json 檔案中另外新增兩個依附元件 pgsequelize,以建構 CRUD 應用程式 Postgres。發布變更的依附元件部分應如下所示。
    "dependencies": {
    "express": "^4.17.3",
    "pg": "^8.8.0",
    "sequelize": "^6.25.7"
  }

將 REST 服務編寫為程式碼

  1. 將 CRUD 應用程式程式碼加入這個應用程式
wget -O app.zip https://github.com/GoogleCloudPlatform/container-developer-workshop/raw/main/labs/nodejs/app.zip

unzip app.zip

這個程式碼有

  • 含有 item 實體模型的 models 資料夾
  • controllers 資料夾,其中包含執行 CRUD 作業的程式碼
  • routes 資料夾,可將特定網址模式轉送至不同的呼叫
  • 含有資料庫連線詳細資料的 config 資料夾
  1. 請注意,db.config.js 檔案中的資料庫設定是指必須提供的環境變數,才能連線至資料庫。您也必須剖析傳入的網址編碼要求。
  2. src/index.js 中加入下列程式碼片段,即可在最後一個部分以 app.listen(PORT, () => { 開頭的區段前,從主要 JavaScript 檔案連線至 CRUD 程式碼
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(
 bodyParser.urlencoded({
   extended: true,
 })
)
const db = require("../app/models");
db.sequelize.sync();
require("../app/routes/item.routes")(app);
  1. deployment.yaml 檔案中編輯部署作業,新增環境變數,提供資料庫連線資訊。

請更新檔案結尾的規格項目,使其符合下列定義

    spec:
      containers:
      - name: mynodejsapp
        image: mynodejsapp
        env:
        - name: DB_HOST
          value: ${DB_INSTANCE_IP}        
        - name: DB_PORT
          value: "5432"  
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: username
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: gke-cloud-sql-secrets
              key: database
  1. 將 DB_HOST 值替換為您的資料庫位址
export DB_INSTANCE_IP=$(gcloud sql instances describe mytest-instance \
    --format=json | jq \
    --raw-output ".ipAddresses[].ipAddress")

envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml

部署及驗證應用程式

  1. 在 Cloud Shell 編輯器底部的窗格中,依序選取 Cloud Code 和畫面頂端的 Debug on Kubernetes
  2. 建構和測試完成後,「輸出」分頁會顯示 Resource deployment/mynodejsapp status completed successfully,以及一個網址:「Forwarded URL from service mynodejsapp: http://localhost:8080」
  3. 請新增幾個項目。

在 Cloud Shell 終端機執行下列指令

URL=localhost:8080
curl -X POST $URL/items -d '{"itemName":"Body Spray", "itemPrice":3.2}' -H "Content-Type: application/json"
curl -X POST $URL/items -d '{"itemName":"Nail Cutter", "itemPrice":2.5}' -H "Content-Type: application/json"
  1. 在瀏覽器中執行 $URL/items,以測試 GET。您也可以在指令列中執行 curl 指令
curl -X GET $URL/items
  1. 測試刪除:現在執行下列指令,嘗試刪除項目。請視需要變更 item-id 的值。
curl -X DELETE $URL/items/1
    This throws an error message
{"message":"Could not delete Item with id=[object Object]"}

找出並修正問題

  1. 應用程式正以偵錯模式執行。因此,請使用中斷點找出問題。以下提供幾項訣竅:
  • 我們知道 DELETE 發生問題,因為它未傳回所需的結果。因此,您需要在 itemcontroller.js->exports.delete 方法中設定中斷點。
  • 逐步執行並觀察每個步驟中的變數,觀察左側視窗中的本機變數值。
  • 如要觀察特定值 (例如 request.params),請在智慧手錶視窗新增這個變數。
  1. 請注意,指派給 id 的值為 undefined。變更程式碼即可解決問題。

已修正的程式碼片段看起來會像這樣。

// Delete a Item with the specified id in the request
exports.delete = (req, res) => {
    const id = req.params.id;
  1. 應用程式重新啟動後,嘗試刪除應用程式並再次進行測試。
  2. 按一下偵錯工具列中的紅色方塊,即可停止偵錯工作階段 647213126d7a4c7b.png

7. 清除

恭喜!在本研究室中,您已從頭開始建立新的 Nodejs 應用程式,並將其設定為搭配容器以熱部署模式運作。接著,您按照傳統應用程式堆疊中的相同開發人員流程,將應用程式部署至遠端 GKE 叢集,並進行偵錯。

如要在完成研究室後清除所用資源,請按照下列步驟操作:

  1. 刪除研究室中使用的檔案
cd ~ && rm -rf mynodejsapp && rm -f setup.sh
  1. 刪除專案,移除所有相關的基礎架構和資源