還記得第一次接觸無伺服器(Serverless)的時候,那種「沒有機器要顧」的感動嗎?一開始,把 API 都寫成 Serverless Function,真的非常方便!不用管理 Server、不用煩惱 Scaling,只需要專心寫自己的程式。
但隨著專案規模變大,RESTful API 越來越複雜,路由、共用邏輯與 Middleware 也開始變多,本地端測試與部署管理也逐漸變得麻煩,開發與部署時間也跟著拉長。
這時候我開始思考:「到底該繼續使用 Functions,還是走向 Container?」
這也是這次專案中,從開始了解 Cloud Run,到最後選擇它作為主要部署方式的原因。
很多剛接觸 Google Cloud 的開發者會有一種錯覺:
「Cloud Run 要打包 Docker Image,還要跑 Container,感覺是不是比 Functions 麻煩很多?」(就是我)
但其實未必。尤其到了 Cloud Functions Gen 2,它本身已經建立在 Cloud Run 的執行環境之上,也支援並發(Concurrency)。
所以現在兩者最大的差異,已經不是「誰可以併發」,而是:
你想用 Function,還是 Container 作為主要的部署單位?
| 比較維度 | Cloud Functions Gen 2 | Cloud Run |
|---|---|---|
| 主要抽象 | Function | Container |
| 開發方式 | Function Handler | 完整 Application / Web Framework |
| Concurrency | 支援多請求 | 支援多請求 |
| 環境掌控 | 較低 | 較高 |
看到上面的表格,眼尖的讀者可能會問:「既然 Functions Gen 2 的底層也是 Cloud Run,而且也解決了併發跟費用的問題,那為什麼不直接用 Gen 2 就好了?」
這次選擇 Cloud Run,其實是因為以下兩個主要原因。
這裡其實是最容易誤會的地方。
如果比較的是 Cloud Functions Gen 2 與 Cloud Run,兩者的運算成本已經非常接近,不能簡單說:
「流量越大,Cloud Functions 就一定比 Cloud Run 貴。」
因為 Gen 2 本身就是建立在 Cloud Run 的執行環境上,也支援並發。真正影響費用的,還是 CPU、Memory、執行時間、Concurrency、Min/Max Instances,以及實際流量等條件。
所以到了 Gen 2,「Cloud Run 比 Functions 便宜」已經不能當成主要結論。
如果今天只是單一目的、事件驅動的工作,Functions 其實非常適合:
Cloud Storage
↓
Function
↓
處理檔案
但如果今天是一個完整的 RESTful API,需要處理多個 Endpoint、Routing 與共用邏輯,這時候需要的已經不是單純「執行一個 Function」,而是部署一個完整的 Backend Service:
Client
↓
Cloud Run
↓
Spring Boot
├── Controller
├── Service
└── Repository
Cloud Run 可以直接使用 Spring Boot、Express、FastAPI 等熟悉的 Web Framework,讓原本的 Application 架構維持下來。
更重要的是,如果專案需要特定 Runtime、OS Package 或其他系統依賴,也可以透過 Dockerfile 將這些環境一起打包進 Container。
這種對執行環境更高的掌控權,也是我最後選擇 Cloud Run 的重要原因。
今天比較了 Cloud Functions 與 Cloud Run,也釐清了一個容易混淆的觀念:Gen 2 已經支援 Concurrency,因此真正的差異不是誰比較強,而是 Function-centric 還是 Container-centric。
如果是簡單的事件驅動任務,Functions 依然是很好的選擇;但如果是完整的 RESTful API,需要 Spring Boot、複雜 Routing 或自訂執行環境,那麼 Cloud Run 會更適合。
這也是為什麼在這次專案中,我最後選擇了 Cloud Run。
明天(Day 4)將開始建立 Google Cloud 基礎環境與安全設定,從 IAM、Service Account 到基本的權限控管,正式把我們的服務放進雲端環境。