跳至主要內容
ESC
GCP 核心服務 — 第 6/10 篇

GCP-111:Cloud Functions 入門——事件驅動無伺服器函式完全指南

GCP-111:Cloud Functions 入門——事件驅動無伺服器函式完全指南
Updated: 2026-07-19

前言

在 GCP 的運算服務裡,Cloud Functions 大概是門檻最低的一個——你只要寫一個函式,丟上去,剩下交給 Google。有事件來就跑、沒事件就縮到零、零成本,連伺服器、容器、程式進入點都不用你操心。

這一課我們把 Cloud Functions 從頭走一遍:它到底是什麼、Gen1 跟 Gen2 差在哪、怎麼接觸發器、定價怎麼算,還有幾個新手最容易踩的坑。ACE 考試的無伺服器選型題也會一併講到。


什麼是 Cloud Functions?

Cloud Functions 讓你部署單一函式來回應事件:

事件來源(HTTP 請求 / GCS 上傳 / Pub/Sub 訊息)


Cloud Functions 自動啟動實例,執行你的函式


處理完成,自動縮容(沒有請求就不花錢)

最後那一步有個正式名稱叫 scale-to-zero(縮容至零)——沒有流量時實例會全部關掉,這段時間 Google 一毛錢都不跟你收。代價是下一個請求進來時得重新冷啟動(後面會講),這是無伺服器服務最迷人也最容易卡住新手的特性。

2024 年 Google 將 Cloud Functions Gen2 更名為 Cloud Run functions,因為 Gen2 底層就是跑在 Cloud Run 上。但 gcloud 指令和介面仍然沿用 functions 名稱——你後面看到的指令還是 gcloud functions deploy,別被名字搞混了。

GCP Console 的 Cloud Run「建立服務」頁面,部署來源三選一:依據現有容器映像檔部署、從存放區持續部署,以及已選取的「使用內嵌編輯器建立函式」;右側費用摘要為 Cloud Run 免費方案
注意這個畫面的標題是 Cloud Run「建立服務」——這正是上面那段更名的實證:你在 Console 建函式,其實是被帶到 Cloud Run 底下,選最右邊那張「使用內嵌編輯器建立函式」的卡片。Gen2 = Cloud Run functions,連免費層都跟 Cloud Run 共用同一套。

Gen1 vs Gen2

Gen2 是目前預設且推薦的版本,Gen1 已進入維護模式。

特性Gen1Gen2(推薦)
底層平台獨立系統Cloud Run
並發處理1 個請求/實例最高 1,000 個請求/實例
HTTP 最大逾時9 分鐘60 分鐘
事件驅動最大逾時9 分鐘9 分鐘
最大記憶體8 GiB32 GiB(GA)
最大 CPU4.8 GHz(約 2 vCPU)4 vCPU(GA)
事件來源有限(GCS、Pub/Sub 等)90+ 事件來源(Eventarc)
VPC 連線VPC ConnectorDirect VPC Egress

並發處理——Gen2 的最大優勢

Gen1 每個實例只能處理一個請求。100 個同時請求 = 啟動 100 個實例。

Gen2 支援並發(預設 80),100 個同時請求只需要 2 個實例:

Gen1:100 並發請求 → 100 個實例(100 次冷啟動)
Gen2:100 並發請求 →   2 個實例(2 次冷啟動)

成本和延遲都大幅降低

這裡的**冷啟動(cold start)**指的是:實例從零被叫醒、載入你的程式碼、初始化執行環境的那段延遲,通常幾百毫秒到幾秒。實例越少、被重複利用的機會越高,冷啟動就越少——這也是 Gen2 並發省成本之外的另一個好處。

💡 重點提點

Gen2 並發是把雙面刃。同一個實例同時處理多個請求,意思是這些請求共用同一份記憶體——全域變數、資料庫連線、暫存檔,全部是共享的。新手最常踩的坑是:把使用者資料存進全域變數,結果 A 的請求讀到 B 的資料。寫並發函式時,請假設任何兩個請求隨時可能同時跑,狀態要嘛放區域變數、要嘛寫進外部儲存(Firestore、Memorystore),別偷懶塞全域。


觸發器類型

下面會用到幾個 GCP 服務名詞,先一句話交代:GCS(Cloud Storage)是 Google 的物件儲存,放圖片、檔案、備份;Pub/Sub 是訊息佇列,把「發送方」跟「處理方」解耦;Firestore 是 NoSQL 文件資料庫。觸發器的角色就是:當這些服務發生事情(檔案上傳、收到訊息、文件變更),自動叫醒你的函式。

GCP Console 建立函式的「觸發條件(選用)」區塊,點開「新增觸發條件」後出現選單,選項有 Pub/Sub 觸發條件(含子選單)、Cloud Storage 觸發條件、Firestore 觸發條件、其他 Eventarc 觸發條件
函式要「被什麼叫醒」就在這裡設。HTTP 觸發是預設(函式本身就是一個網址,不必特別在這加);事件驅動則從這個選單挑:Pub/Sub、Cloud Storage、Firestore 各有現成入口,其餘上百種來源全走最下面那條「其他 Eventarc 觸發條件」——這就是 Gen2 靠 Eventarc 撐起 90+ 事件來源的地方。

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 獨有)

Eventarc 是 GCP 的統一事件路由服務——它把各種 Google Cloud 服務(甚至第三方)發生的事件,標準化後轉送給你的函式。有了它,Gen2 不用為每種來源各寫一套整合,支援 90+ 種事件來源,包括:

  • Cloud SQL 資料庫變更
  • BigQuery 作業完成
  • Cloud Build 建置狀態變更
  • Firestore 文件變更
  • 第三方服務(GitHub、Stripe 等)

支援的語言

語言版本(2026)
Node.js24
Python3.12、3.13、3.14
Go1.26
Java21、25
.NET最新穩定版
Ruby最新穩定版
PHP最新穩定版

各語言的支援版本會持續往前推進(新版本上架、舊版本退役都很頻繁),實際部署前以官方的 runtime support 頁面為準。考試不會考你某個 runtime 的精確小版本,記得「Cloud Functions 支援主流語言、版本跟著官方滾動」這個概念就夠了。

GCP Console 建立函式的「執行階段」語言選單展開,可見 Java 21、Java 17、Node.js 26(預先發布版)、Node.js 24、Node.js 22(已選)、Node.js 20(已不適用)、PHP 8.5、PHP 8.4 等選項,清單可捲動至 Python、Go、Ruby 等
「執行階段」就是挑程式語言的地方。可以看到同一個語言會有多個版本並列,還會標「預先發布版」或「已不適用」——正好對上這一節說的:Cloud Functions 支援主流語言、版本跟著官方一直滾動。這也是為什麼別去背精確小版本,挑當下的穩定版就對了。

資源配置與冷啟動

資源配置

gcloud functions deploy my-func \
  --gen2 \
  --runtime=nodejs24 \
  --trigger-http \
  --memory=512Mi \         # 記憶體(128Mi ~ 32Gi)
  --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(至少一次) 語義,意思是同一個事件可能觸發你的函式好幾次——Google 保證「至少送到一次」,但不保證「剛好一次」。

💡 重點提點

「事件可能重複觸發」既是 ACE 高頻考點,也是實務最痛的地雷。解法只有一個:把函式寫成冪等(idempotent)——同一個事件跑一次、跑十次,結果都一樣。最常見的做法是用事件的唯一 ID 當作「處理過沒」的鎖(下面的範例就是這招)。如果你的函式會扣款、發信、寫入訂單,沒做冪等就上線,遲早會出現重複扣款、重複寄信的災難。

解法:設計冪等函式

所謂冪等(idempotent),白話講就是「同一個操作做幾次,效果都跟做一次一樣」。下面用事件的唯一 ID 先查一次「處理過了沒」,處理過就直接跳出:

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 這個 IAM 角色,否則讀 Secret 會被拒。權限不足是新手部署完第一次踩的雷,看到 PermissionDenied 先回來檢查這一條。


本地開發與測試

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"}'

定價與免費層

⚠️ 官方定價頁已把 Gen2(Cloud Run functions)併入 Cloud Run 計費,下面是 Gen2 的額度。Gen1 用的是不同單位、不同數字:200 萬次呼叫、400,000 GB-秒、200,000 GHz-秒、5 GB 對外流量——兩代別搞混。

免費層(每月,Gen2)

項目免費額度
呼叫次數200 萬次
運算(CPU)180,000 vCPU-秒
運算(記憶體)360,000 GiB-秒
對外流量北美區域出站 1 GB

超過免費層

項目費用
呼叫$0.40 / 100 萬次
CPU$0.000024 / vCPU-秒
記憶體$0.0000025 / GiB-秒

定價就是 Cloud Run 定價,因為 Gen2 底層直接跑在 Cloud Run 上。


Cloud Functions vs Cloud Run vs App Engine

這是 ACE 考試最高頻的選型題:

特性Cloud FunctionsCloud RunApp Engine
部署單位單一函式容器應用程式
語言7 種 runtime任何(Docker)指定 runtime
觸發方式事件 / HTTPHTTPHTTP
最大逾時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 考試重點整理

必背知識點

  1. Gen2 是預設,底層是 Cloud Run,Gen1 進入維護模式
  2. Gen2 支援並發(最高 1000/實例),Gen1 只能 1 個請求/實例
  3. HTTP 觸發最長 60 分鐘(Gen2),事件觸發最長 9 分鐘
  4. 事件交付是 at-least-once,需要冪等設計
  5. Eventarc 讓 Gen2 支援 90+ 種事件來源
  6. 免費層:每月 200 萬次呼叫
  7. 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;並發是把雙面刃,狀態別亂塞全域;事件是 at-least-once,函式一定要冪等。前面兩個 💡 重點提點講的就是這兩個最容易翻車的地方,記熟它們,比背一堆定價數字實用得多。

選型上記住一句話就好:收到事件要跑一段邏輯,先想 Cloud Functions;要部署容器化服務,去 Cloud Run;要架傳統 Web App,找 App Engine。

下一課 ACE-212:App Engine 應用開發與部署,我們來看 GCP 這個歷史最悠久的 PaaS 平台,今天還適合用在哪些場景。

運算服務選型系列

課程服務適合場景
GCP-109Cloud Run容器化 API/微服務,scale-to-zero
本課 GCP-111Cloud Functions事件驅動單一函式(GCS/Pub/Sub 觸發)
ACE-212App Engine快速部署 Web App、免費層最多
ACE-206GKE完整 K8s 控制、大規模微服務
ACE-203綜合比較全部 Serverless 選型決策樹
GCP 核心服務 — 6/10 完成 查看系列全覽 →

留言討論

徽章解鎖!