使用 NodeJS 進行內部迴圈

1. 總覽

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

學習目標

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

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

2. 設定和需求

自修環境設定

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

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 不使用的字元字串,您可以隨時更新。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常稱為 PROJECT_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 叢集和資料庫

  1. 下載設定指令碼並設為可執行狀態。
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/nodejs/setup.sh
chmod +x setup.sh

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

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

  1. 開啟 setup.sh 檔案,然後編輯目前設為 CHANGEME 的密碼值
  2. 執行設定指令碼,建立將在本研究室中使用的 GKE 叢集和 CloudSQL 資料庫
./setup.sh
  1. 在 Cloud Shell 中建立名為「mynodejsapp」的新目錄
mkdir mynodejsapp
  1. 請變更為這個目錄,然後以工作區的形式開啟。這項操作會在新建立的資料夾中建立工作區設定,重新載入編輯器。
cd mynodejsapp && cloudshell workspace .
  1. 使用 NVM 安裝節點和 NPM。
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/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

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

  1. 將應用程式初始化

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

npm init
    Choose the entry point: (index.js) src/index.js and default values for the rest of the parameters. This will create the 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. 新增進入點

請編輯這個檔案,在指令碼 "start": "node src/index.js", 中加入 start 指令。變更後的指令碼應如以下程式碼片段所示:

"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": "Your Name",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}
  1. 建立 index.js 檔案

建立名為 src 的來源目錄

使用下列程式碼建立 src/index.js

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,進而自動建立基礎 Kubernetes 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 設定也會自動在編輯器和執行中的容器之間啟用熱同步處理。您無需額外設定即可啟用熱同步。

4. 逐步完成開發程序

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

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

部署到 Kubernetes

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

fdc797a769040839.png

  1. 在頂端的面板中,選取「Run on Kubernetes」。如果出現提示,請選取「是」以使用目前的 Kubernetes 結構定義。

cfce0d11ef307087.png

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

817ee33b5b412ff8.png

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

eb4469aed97a25f6.png

  1. 選取下方窗格中的「Output」分頁標籤,即可查看進度和通知

f95b620569ba96c5.png

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

94acdcdda6d2108.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) 的網址上,然後在顯示的工具提示中選取「Open Web Preview」。

回應將為:

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

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

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

設定依附元件

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

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

將 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

6. 清除

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

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

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