使用 API 閘道部署和保護無伺服器 API:挑戰實驗室
Deploy and Secure Serverless APIs with API Gateway: Challenge Lab
https://www.skills.google/games/7399/labs/45439
整個流程整理成一份「學習筆記」。包含完整的 CLI 指令,還加入了每個步驟背後的架構意義與除錯小提醒。
本實作的資料流與架構如下:[用戶端 (Client)] ➡️ [API Gateway] ➡️ [Cloud Run Function (後端邏輯)] ➡️ [Pub/Sub (事件驅動/訊息發布)]
說明: 在雲端環境操作時,將常用的專案 ID、編號與區域設為環境變數,可以大幅減少手動輸入錯誤並提升指令的重複使用性。
# 取得當前專案的 Project ID 和 Project Number
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
# 設定本次 Lab 的預設 Region
export REGION="us-east1"
# 確保啟用本架構所需的所有 Google Cloud APIs
gcloud services enable \
apigateway.googleapis.com \
servicemanagement.googleapis.com \
servicecontrol.googleapis.com \
run.googleapis.com \
cloudfunctions.googleapis.com
說明: 建立一個 Node.js 22 的後端函式。這是我們整個架構的運算核心。
💡 避坑提示: Node.js 函式需要
@google-cloud/functions-framework才能正確啟動,務必在package.json的dependencies中宣告,否則會發生 Container Healthcheck 失敗的錯誤。
# 建立並進入工作目錄
mkdir ~/my_api_backend && cd ~/my_api_backend
# 1. 建立 package.json (宣告必要套件)
cat <<EOF > package.json
{
"name": "gcfunction",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0"
}
}
EOF
# 2. 建立 index.js (撰寫回傳 Hello World 的基礎邏輯)
cat <<EOF > index.js
const functions = require('@google-cloud/functions-framework');
functions.http('helloHttp', (req, res) => {
res.status(200).send("Hello World!");
});
EOF
# 3. 部署 Cloud Run Function (2nd gen)
# 參數說明:允許未經驗證的呼叫 (--allow-unauthenticated),由 HTTP 觸發 (--trigger-http)
gcloud functions deploy gcfunction \
--gen2 \
--region=$REGION \
--runtime=nodejs22 \
--source=. \
--entry-point=helloHttp \
--trigger-http \
--allow-unauthenticated
# 4. 提取部署後的真實 Function URL (供下一步 API Gateway 使用)
export FUNCTION_URL=$(gcloud functions describe gcfunction --gen2 --region=$REGION --format="value(serviceConfig.uri)")
echo "後端 Function URL 為: $FUNCTION_URL"
說明: 我們不希望用戶端直接呼叫 Function URL,而是透過 API Gateway 來統一管理、路由與保護 API。這裡需要撰寫一份 OpenAPI (Swagger) 規格書來定義路由。
cd ~
# 1. 建立 OpenAPI 規格檔 (openapispec.yaml)
# 注意 x-google-backend.address 這裡會自動代入剛才取得的 $FUNCTION_URL
cat <<EOF > openapispec.yaml
swagger: '2.0'
info:
title: gcfunction API
description: Sample API on API Gateway with a Google Cloud Run functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-backend:
address: $FUNCTION_URL
paths:
/gcfunction:
get:
summary: gcfunction
operationId: gcfunction
responses:
'200':
description: A successful response
schema:
type: string
EOF
# 2. 建立 API 實體 (定義這是一個 API 服務)
gcloud api-gateway apis create gcfunction-api \
--display-name="gcfunction API" \
--project=$PROJECT_ID
# 3. 建立 API Config (將 OpenAPI 規格書與服務帳戶綁定)
gcloud api-gateway api-configs create gcfunction-api \
--api=gcfunction-api \
--openapi-spec=openapispec.yaml \
--project=$PROJECT_ID \
--backend-auth-service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
# 4. 部署 API Gateway (將 Config 實例化到特定 Region,此步驟需耗時數分鐘)
gcloud api-gateway gateways create gcfunction-api \
--api=gcfunction-api \
--api-config=gcfunction-api \
--location=$REGION \
--project=$PROJECT_ID
說明: 在實際業務場景中,API 被呼叫後通常會觸發其他非同步事件。這裡我們將 Function 升級,讓它在收到請求時,推送一筆訊息到 Pub/Sub Topic。
# 1. 建立 Pub/Sub Topic (訊息主題) 與預設的 Subscription (訂閱者)
gcloud pubsub topics create demo-topic
gcloud pubsub subscriptions create demo-topic-sub --topic=demo-topic
# 回到後端程式碼目錄
cd ~/my_api_backend
# 2. 更新 package.json (加入 Pub/Sub SDK 依賴)
cat <<EOF > package.json
{
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0",
"@google-cloud/pubsub": "^3.4.1"
}
}
EOF
# 3. 更新 index.js (加入推送訊息到 demo-topic 的邏輯)
cat <<EOF > index.js
const {PubSub} = require('@google-cloud/pubsub');
const pubsub = new PubSub();
const topic = pubsub.topic('demo-topic');
const functions = require('@google-cloud/functions-framework');
exports.helloHttp = functions.http('helloHttp', (req, res) => {
// 發送訊息到 Pub/Sub
topic.publishMessage({data: Buffer.from('Hello from Cloud Run functions!')});
res.status(200).send("Message sent to Topic demo-topic!");
});
EOF
# 4. 重新部署 Cloud Run Function (套用新程式碼)
gcloud functions deploy gcfunction \
--gen2 \
--region=$REGION \
--runtime=nodejs22 \
--source=. \
--entry-point=helloHttp \
--trigger-http \
--allow-unauthenticated
# ==========================================
# 🎯 最終測試與驗證
# ==========================================
# 取得 API Gateway 的公開網址
export GATEWAY_URL=$(gcloud api-gateway gateways describe gcfunction-api --location=$REGION --format="value(defaultHostname)")
echo "API Gateway URL 為: https://$GATEWAY_URL/gcfunction"
# 透過 API Gateway 觸發整個資料流
curl -s https://$GATEWAY_URL/gcfunction
# (進階驗證) 去 Pub/Sub 檢查是否真的有收到剛才推送的訊息
gcloud pubsub subscriptions pull demo-topic-sub --auto-ack
將這份筆記存下來,未來如果需要架設一套「API 閘道 + 無伺服器運算 + 非同步事件傳遞」的系統,只要照著這個骨架稍作修改!