GCP-111:Cloud Functions 入門——事件驅動無伺服器函式完全指南
前言
Cloud Functions 是 GCP 最簡潔的運算服務,你只要寫一個函式,剩下交給 GCP。有事件來就執行,沒事件就不花錢。不用管容器、不用管伺服器,連程式的進入點怎麼設定都不用煩惱。
這篇文章是 GCP 入門系列第 11 課,帶你認識 Cloud Functions 的核心概念和實際操作。
什麼是 Cloud Functions?
Cloud Functions 讓你部署單一函式來回應事件:
事件來源(HTTP 請求 / GCS 上傳 / Pub/Sub 訊息)
│
▼
Cloud Functions 自動啟動實例,執行你的函式
│
▼
處理完成,自動縮容(沒有請求就不花錢)
2024 年 Google 將 Cloud Functions Gen2 更名為 Cloud Run functions,因為 Gen2 底層就是跑在 Cloud Run 上。但 gcloud 指令和介面仍然沿用
functions名稱。
Gen1 vs Gen2
Gen2 是目前預設且推薦的版本,Gen1 已進入維護模式。
| 特性 | Gen1 | Gen2(推薦) |
|---|---|---|
| 底層平台 | 獨立系統 | Cloud Run |
| 並發處理 | 1 個請求/實例 | 最高 1,000 個請求/實例 |
| HTTP 最大逾時 | 9 分鐘 | 60 分鐘 |
| 事件驅動最大逾時 | 9 分鐘 | 9 分鐘 |
| 最大記憶體 | 8 GiB | 16 GiB(GA) |
| 最大 CPU | 4.8 GHz(約 2 vCPU) | 4 vCPU(GA) |
| 事件來源 | 有限(GCS、Pub/Sub 等) | 90+ 事件來源(Eventarc) |
| VPC 連線 | VPC Connector | Direct VPC Egress |
並發處理——Gen2 的最大優勢
Gen1 每個實例只能處理一個請求。100 個同時請求 = 啟動 100 個實例。
Gen2 支援並發(預設 80),100 個同時請求只需要 2 個實例:
Gen1:100 並發請求 → 100 個實例(100 次冷啟動)
Gen2:100 並發請求 → 2 個實例(2 次冷啟動)
成本和延遲都大幅降低
觸發器類型
HTTP 觸發器
最直接的一種,函式本身就是一個 HTTPS Endpoint:
# Python 範例
import functions_framework
@functions_framework.http
def hello(request):
name = request.args.get("name", "World")
return f"Hello, {name}!"
# 部署
gcloud functions deploy hello \
--gen2 \
--runtime=python312 \
--trigger-http \
--allow-unauthenticated \
--region=asia-east1 \
--entry-point=hello
# 取得 URL
gcloud functions describe hello \
--region=asia-east1 \
--format="value(serviceConfig.uri)"
Cloud Storage 觸發器
GCS 有檔案變動時自動執行:
import functions_framework
from cloudevents.http import CloudEvent
@functions_framework.cloud_event
def on_file_upload(cloud_event: CloudEvent):
data = cloud_event.data
bucket = data["bucket"]
name = data["name"]
print(f"New file: gs://{bucket}/{name}")
gcloud functions deploy on-file-upload \
--gen2 \
--runtime=python312 \
--trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
--trigger-event-filters="bucket=my-upload-bucket" \
--region=asia-east1 \
--entry-point=on_file_upload
Pub/Sub 觸發器
收到 Pub/Sub 訊息時自動執行:
import base64
import functions_framework
from cloudevents.http import CloudEvent
@functions_framework.cloud_event
def on_message(cloud_event: CloudEvent):
data = base64.b64decode(cloud_event.data["message"]["data"]).decode()
print(f"Received message: {data}")
gcloud functions deploy on-message \
--gen2 \
--runtime=python312 \
--trigger-topic=my-topic \
--region=asia-east1 \
--entry-point=on_message
Eventarc 觸發器(Gen2 獨有)
Gen2 透過 Eventarc 支援 90+ 種事件來源,包括:
- Cloud SQL 資料庫變更
- BigQuery 作業完成
- Cloud Build 建置狀態變更
- Firestore 文件變更
- 第三方服務(GitHub、Stripe 等)
支援的語言
| 語言 | 版本(2026) |
|---|---|
| Node.js | 24 |
| Python | 3.11、3.12、3.13 |
| Go | 1.23 |
| Java | 17、21 |
| .NET | 最新穩定版 |
| Ruby | 最新穩定版 |
| PHP | 最新穩定版 |
資源配置與冷啟動
資源配置
gcloud functions deploy my-func \
--gen2 \
--runtime=nodejs24 \
--trigger-http \
--memory=512Mi \ # 記憶體(128Mi ~ 16Gi)
--cpu=1 \ # vCPU(0.083 ~ 4)
--min-instances=1 \ # 最小實例(消除冷啟動)
--max-instances=20 \ # 最大實例(控制成本)
--concurrency=80 \ # 每實例並發數(Gen2)
--timeout=60 \ # 逾時(秒)
--region=asia-east1
消除冷啟動
# 保留暖機實例
gcloud functions deploy my-func \
--min-instances=1
# 設定 0 就是允許縮容至零(預設)
gcloud functions deploy my-func \
--min-instances=0
事件交付語義
At-Least-Once(至少一次)
Cloud Functions 的事件觸發是 at-least-once 語義,意思是同一個事件可能觸發你的函式好幾次。
解法:設計冪等函式
from google.cloud import firestore
db = firestore.Client()
@functions_framework.cloud_event
def process_order(cloud_event):
event_id = cloud_event["id"] # 每個事件有唯一 ID
# 檢查是否已經處理過
doc = db.collection("processed_events").document(event_id).get()
if doc.exists:
print(f"Already processed: {event_id}")
return
# 執行業務邏輯
do_business_logic(cloud_event.data)
# 記錄已處理
db.collection("processed_events").document(event_id).set({
"processed_at": firestore.SERVER_TIMESTAMP
})
Secret Manager 整合
方式一:部署時引用(推薦)
# 掛載為環境變數
gcloud functions deploy my-func \
--set-secrets=DB_PASSWORD=db-password:latest
# 掛載為檔案
gcloud functions deploy my-func \
--set-secrets=/secrets/api-key=api-key:latest
方式二:程式碼中呼叫
from google.cloud import secretmanager
def get_secret(secret_id):
client = secretmanager.SecretManagerServiceClient()
name = f"projects/my-project/secrets/{secret_id}/versions/latest"
response = client.access_secret_version(name=name)
return response.payload.data.decode("utf-8")
IAM 需求:函式的 Service Account 需要 roles/secretmanager.secretAccessor。
本地開發與測試
Cloud Functions 提供 Functions Framework,可在本地模擬雲端執行環境:
安裝與啟動
# Python
pip install functions-framework
functions-framework --target=hello --debug --port=8080
# Node.js
npm install @google-cloud/functions-framework
npx functions-framework --target=hello --port=8080
測試 HTTP 函式
curl http://localhost:8080?name=Bobo
測試事件驅動函式(CloudEvents)
curl -X POST http://localhost:8080 \
-H "ce-specversion: 1.0" \
-H "ce-type: google.cloud.storage.object.v1.finalized" \
-H "ce-source: //storage.googleapis.com/projects/my-project" \
-H "ce-id: test-001" \
-H "Content-Type: application/json" \
-d '{"bucket": "my-bucket", "name": "test.txt"}'
定價與免費層
免費層(每月)
| 項目 | 免費額度 |
|---|---|
| 呼叫次數 | 200 萬次 |
| 運算(記憶體) | 400,000 GB-秒 |
| 運算(CPU) | 200,000 GHz-秒 |
| 對外流量 | 5 GB |
超過免費層
| 項目 | 費用 |
|---|---|
| 呼叫 | $0.40 / 100 萬次 |
| CPU | $0.000024 / vCPU-秒 |
| 記憶體 | $0.0000025 / GB-秒 |
定價和 Cloud Run 幾乎一樣,畢竟 Gen2 底層就是 Cloud Run。
Cloud Functions vs Cloud Run vs App Engine
這是 ACE 考試最高頻的選型題:
| 特性 | Cloud Functions | Cloud Run | App Engine |
|---|---|---|---|
| 部署單位 | 單一函式 | 容器 | 應用程式 |
| 語言 | 7 種 runtime | 任何(Docker) | 指定 runtime |
| 觸發方式 | 事件 / HTTP | HTTP | HTTP |
| 最大逾時 | 60 分鐘(HTTP Gen2) | 60 分鐘 | 24 小時 |
| 並發 | 1000/實例(Gen2) | 1000/實例 | 依 instance class |
| 最適合 | 事件驅動函式 | 容器化微服務 | 傳統 Web 應用 |
| 免費層 | 200 萬次/月 | 200 萬次/月 | 28 F-hours/天 |
選型公式
收到事件(GCS 上傳、Pub/Sub 訊息)→ 執行一個函式?
→ Cloud Functions ✅
部署一個容器化 API / Web Service?
→ Cloud Run ✅
部署一個傳統 Web App,不想管容器?
→ App Engine ✅
ACE 考試重點整理
必背知識點
- Gen2 是預設,底層是 Cloud Run,Gen1 進入維護模式
- Gen2 支援並發(最高 1000/實例),Gen1 只能 1 個請求/實例
- HTTP 觸發最長 60 分鐘(Gen2),事件觸發最長 9 分鐘
- 事件交付是 at-least-once,需要冪等設計
- Eventarc 讓 Gen2 支援 90+ 種事件來源
- 免費層:每月 200 萬次呼叫
- Functions Framework 可本地測試
常見陷阱題
Q:Cloud Functions 能處理長時間運行的 ETL 任務嗎? A:HTTP 觸發最長 60 分鐘,事件觸發最長 9 分鐘。超過這個時間就該改用 Cloud Run Jobs(最長 7 天)。
Q:100 個用戶同時呼叫 Gen1 函式,需要幾個實例? A:100 個。Gen1 每實例只能處理 1 個請求。Gen2 只需要 2 個實例(concurrency=80)。
Q:Cloud Functions 保證事件只處理一次嗎? A:不保證。Cloud Functions 是 at-least-once,需要自己設計冪等邏輯。
Q:GCS 上傳自動觸發處理,用什麼服務? A:Cloud Functions(GCS 觸發器最自然的搭配)。
實戰範例:圖片上傳自動生成縮圖
# main.py
import functions_framework
from cloudevents.http import CloudEvent
from google.cloud import storage
from PIL import Image
import io
storage_client = storage.Client()
@functions_framework.cloud_event
def generate_thumbnail(cloud_event: CloudEvent):
data = cloud_event.data
bucket_name = data["bucket"]
file_name = data["name"]
# 跳過非圖片和已是縮圖的檔案
if not file_name.lower().endswith((".jpg", ".jpeg", ".png")):
return
if file_name.startswith("thumbnails/"):
return
# 下載原圖
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(file_name)
image_data = blob.download_as_bytes()
# 生成縮圖
image = Image.open(io.BytesIO(image_data))
image.thumbnail((200, 200))
# 上傳縮圖
output = io.BytesIO()
image.save(output, format="JPEG", quality=85)
output.seek(0)
thumb_blob = bucket.blob(f"thumbnails/{file_name}")
thumb_blob.upload_from_file(output, content_type="image/jpeg")
print(f"Thumbnail created: thumbnails/{file_name}")
# 部署
gcloud functions deploy generate-thumbnail \
--gen2 \
--runtime=python312 \
--trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
--trigger-event-filters="bucket=my-image-bucket" \
--region=asia-east1 \
--memory=512Mi \
--entry-point=generate_thumbnail
總結
Cloud Functions 是 GCP 最輕量的運算方式,核心要點:
- Gen2 為預設:底層是 Cloud Run,支援並發(1000/實例)、60 分鐘逾時
- 觸發器:HTTP、GCS、Pub/Sub、Eventarc(90+ 事件來源)
- 事件交付:at-least-once,需要冪等設計
- 本地測試:Functions Framework 模擬雲端環境
- 免費層:每月 200 萬次呼叫
- 選型:事件驅動 → Functions;容器化 → Cloud Run;Web App → App Engine
下一課 ACE-212:App Engine 應用開發與部署,學習 GCP 最早的 PaaS 平台如何在 2026 年定位。
運算服務選型系列
| 課程 | 服務 | 適合場景 |
|---|---|---|
| GCP-109 | Cloud Run | 容器化 API/微服務,scale-to-zero |
| 本課 GCP-111 | Cloud Functions | 事件驅動單一函式(GCS/Pub/Sub 觸發) |
| ACE-212 | App Engine | 快速部署 Web App、免費層最多 |
| ACE-206 | GKE | 完整 K8s 控制、大規模微服務 |
| ACE-203 | 綜合比較 | 全部 Serverless 選型決策樹 |