iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0

Day27_是時候展現你的作品了,將網站部署至 Google Cloud

前言:把做好的網站搬出開發電腦

前一天把雲端比喻成網站準備入住的新店面。現在店面選好了,接下來就要真的搬家:先接好網路與資料庫,再搬進後端 API,最後把前端網頁的大門打開。

本篇會把 Vue、ASP.NET Core API 與 SQL Server 部署到 Google Cloud。完成後,使用者可以從瀏覽器開啟網站、登入系統,並且真的把資料寫進雲端資料庫。

這次部署會分成三條主線:

  1. 資料庫:建立 Cloud SQL for SQL Server,再用專用的 Migration Job 建立 Schema。
  2. 後端 API:把 ASP.NET Core 容器部署到 Cloud Run,連上私有網路內的 Cloud SQL。
  3. 前端網頁:用 Nginx 提供 Vue 建置後的靜態檔,並把 /api 請求代理給後端。

API 得先找得到資料庫,前端也得知道 API 住在哪裡。所以不能像搬箱子一樣想搬哪箱就搬哪箱,而是要照著「資料庫 → 後端 API → 前端網頁」的相依順序進行。

*本文需要在 Google Cloud 建立專案並連結付款帳戶。Cloud SQL 等資源建立後可能持續產生費用,請先確認自己可以接受後再繼續。

本篇的部署前提

本文專心處理 Google Cloud 的操作。後端與前端所需的 Dockerfile、Cloud Build 設定、Nginx 設定與正式環境參數,都視為已在部署前完成並驗證。這些檔案就像搬家前已經打包好的箱子;本篇要處理的,是雲端資源的建立、設定、部署與驗收。

還有一條邊界需要先說清楚。Day26 提到的「Cloud Scheduler 定時啟動 Cloud Run Job」是到期提醒功能的雲端改造目標,但目前後端程式仍由 Hangfire 常駐排程。本篇只部署網站主線,不把尚未改造的排程工作說成已上線;API 部署時會先關閉 ReminderJobs,等專用 Job 完成後,再由 Cloud Scheduler 啟動新的提醒流程。

先看懂這次的部署地圖

本機內容 Google Cloud 上的位置 本篇對應章節
SQL Server Cloud SQL for SQL Server 資料庫部署
EF Core Migration Cloud Run Job 資料庫部署
ASP.NET Core API Cloud Run service 後端 API 部署
Vue 3 網頁與 Nginx Cloud Run service 前端網頁部署
Docker 映像 Artifact Registry 共用的部署倉庫
連線字串、JWT Key Secret Manager 機密設定

完整建立順序

以下流程圖分成兩列。第一列先準備共用資源與資料庫,第二列才輪到後端、前端與瀏覽器驗收。每一格都是下一格的前置條件;若某一格失敗,先留在原地查清楚,不要急著往後按「建立」。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487ZvzIrPXynA.png

部署前的共同準備

先把三條部署路線共用的專案、帳單、API 與區域設定好。這一段很像搬家前先確認地址、簽好租約、接上水電;地基沒有處理好,後面的服務再多也站不穩。

確認 Google Cloud Project 與 Billing

開啟 Google Cloud Console。

在頁面最上方的 Project 選擇器確認:

專案名稱:ProjectManagementWeb
Project ID:solid-terra-509706-e5

專案名稱和 Project ID 是兩個不同欄位。這次畫面上顯示的名稱是 ProjectManagementWeb,真正會出現在 Service Account、映像路徑與資源識別資訊裡的 Project ID,則是 solid-terra-509706-e5。後面的設定若需要填寫 Project ID,不能直接拿專案名稱代替。

接著前往:

主選單
→ Billing
→ My projects

確認 solid-terra-509706-e5 已連結有效的 Billing Account。本文不放付款帳戶與信用卡畫面,避免把帳務資訊一併公開。

進入帳單總覽後,左上角會顯示目前選取的帳單帳戶,中間則是費用摘要。只要能正常開啟總覽,並在「我的專案」中看到 solid-terra-509706-e5 已連結,就表示這個 Project 可以建立需要計費的雲端資源。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487WzGJIgSjPQ.png

啟用 API 本身不會建立 Cloud SQL,但後面按下「Create instance」後,Cloud SQL 就會開始產生運算與儲存費用。

啟用必要 API

API 在這次部署中的用途
Cloud SQL Admin API 建立與管理 Cloud SQL for SQL Server
Compute Engine API 支援 VPC 與部分網路資源
Service Networking API 建立 Private Services Access
Cloud Run Admin API 執行 API、前端網頁與 Migration Job
Artifact Registry API 儲存 Docker 映像
Secret Manager API 保存連線字串與機密設定
Cloud Build API 從原始碼或 Dockerfile 建置映像

先點選左上角的導覽選單,依序進入:

導覽選單
→ API 和服務
→ 程式庫

https://ithelp.ithome.com.tw/upload/images/20260926/20126487DqXSWAY1SF.png

進入 API 程式庫後,在「搜尋 API 和服務」欄位輸入要啟用的 API 名稱。例如先搜尋 Cloud SQL Admin API,再從搜尋結果點進服務詳細頁面。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487nVJdkGmbQe.png

確認服務名稱後按下「啟用」。其餘 API 也按照相同步驟逐一處理。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487x0WwYRXVGI.png

畫面顯示「API 已啟用」,只代表這個 Project 取得使用服務的入場券。它不會自動幫忙建立 Cloud SQL 或 Cloud Run,也不代表計費資源已經開始運作。

統一 Region 與資源命名

這次主要使用台灣的 asia-east1,讓 Cloud Run、Artifact Registry 與 Cloud SQL 盡量住在同一個 Region。把倉庫、店面與資料庫安排在同一個區域,連線較單純,也比較不容易產生沒必要的跨區流量。

資源 本次使用的名稱
VPC projectmanagementweb-vpc
Cloud SQL instance projectmanagementweb-sql
Database ProjectManagementWeb
Artifact Registry repository projectmanagementweb
Migration Job database-migrator
後端 Cloud Run service api
前端 Cloud Run service projectmanagement-web

部分 Google Cloud 資源建立後不能直接修改 Region,因此按下「建立」前,記得確認設定為 asia-east1。

打通 Cloud Run 與 Cloud SQL 之間的私有網路

Cloud SQL 使用 Private IP 時,不會自動和 Cloud Run 變成鄰居。我們要先準備一條不經公開網際網路的內部通道,讓 VPC 和 Cloud SQL 所在的 Google 代管服務網路連起來。官方名稱是 Private Services Access,完整概念可參考 Google Cloud Private Services Access。

先建立自訂 VPC 網路

在分配私人 IP 範圍之前,專案裡要先有一個 VPC。VPC 可以先想成雲端裡的私有社區;之後會讓 Cloud Run 透過這個社區的內部道路前往 Cloud SQL。點選左上角的導覽選單,進入「虛擬私有雲網路 → 虛擬私有雲網路」。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487diB87G3oAz.png

進入網路清單後,按下頁面上方的「建立虛擬私有雲網路」。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487zgfGTUE3Mn.png

在建立頁面填入這次使用的網路設定:

欄位 本次設定
名稱 projectmanagementweb-vpc
說明 ProjectManagementWeb Cloud Run and Cloud SQL private network
MTU 自動設定
子網路建立模式 自訂
私人 IPv6 位址設定 不啟用

https://ithelp.ithome.com.tw/upload/images/20260926/20126487kLUum6fk1j.png

接著在「新的子網路」中建立 Cloud Run Direct VPC egress 使用的子網路:

欄位 本次設定
名稱 projectmanagementweb-asia-east1
區域 asia-east1
IP 堆疊類型 IPv4(單一堆疊)
主要 IPv4 範圍 使用不與其他子網路或稍後 PSA 範圍重疊的私人 CIDR

其餘選項維持本次畫面中的預設值:動態轉送模式選「單一地區」,最佳路徑選取模式選「舊版(預設)」。檢查名稱、Region 與 IPv4 範圍後,按下頁面底部的「建立」。等 projectmanagementweb-vpc 出現在網路清單後,再繼續分配私人服務使用的 IP 範圍。

配置私人 IP 範圍

VPC 是我們可以管理的網路,Cloud SQL 則住在 Google 管理的網路裡。接下來要先替 Google 代管服務預留一段不會和現有子網路打架的 IP 範圍,再用它建立兩邊的私人連線。

依照目前的 Google Cloud 中文介面,先點選左上角的導覽選單,再依序進入:

導覽選單
→ 虛擬私有雲網路
→ 虛擬私有雲網路
→ 選擇 projectmanagementweb-vpc
→ 私人服務連線
→ 分配的服務 IP 範圍
→ 分配 IP 範圍

第一個「虛擬私有雲網路」是導覽選單中的服務分類,第二個則是進入服務後,左側功能列中的網路清單。選擇 projectmanagementweb-vpc 後,畫面上方會出現「私人服務連線」分頁;切換到「分配的服務 IP 範圍」,再按下「分配 IP 範圍」。

填入:

欄位 建議值
Name google-managed-services-projectmanagementweb-vpc
Description Cloud SQL private services access
IP range allocation Automatic
Prefix length 16

接著點擊 Allocate。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487CF34joIY2C.png

/16 可為未來其他 Region 或 Google 代管服務保留空間;Cloud SQL 每個 Region/資料庫類型至少需要可用的 /24 範圍。

建立私人連線

私人 IP 範圍分配完成後,仍留在 projectmanagementweb-vpc 的「私人服務連線」頁面,接著依序操作:

私人服務連線
→ 私人服務連線
→ 建立連線

第一個「私人服務連線」是 VPC 詳細資料上方的功能分頁,第二個則是頁面內用來查看現有私人連線的子分頁。

填入:

欄位 設定
已連線的服務供應商 Google Cloud Platform
連線名稱 servicenetworking-googleapis-com,由 Google Cloud 自動產生
已指派的分配範圍 google-managed-services-projectmanagementweb-vpc

展開「已指派的分配範圍」,勾選前一節建立的 IP 範圍,先按下「確定」,再按下「連線」。

https://ithelp.ithome.com.tw/upload/images/20260926/201264874LrjbdZxNJ.png

建立完成後,連線清單應顯示:

servicenetworking-googleapis-com

這條私人連線建立後,可供同一個 VPC 中其他支援私人服務存取權的 Google 服務共用,因此不要在日後隨意刪除。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487Wjtixv5DzV.png

讓 Cloud Run 進入同一個 VPC

Private Services Access 只是把 Cloud SQL 所在的 Google 代管網路接到 VPC,像是已經鋪好社區外的連絡道。Migration Job 與後端 API 還要設定 Direct VPC egress,才知道該從這條路前往 Cloud SQL 的 Private IP。

這次在 Migration Job 與後端 API 都選擇:

欄位 設定
Network projectmanagementweb-vpc
Subnet projectmanagementweb-asia-east1
Network tags 留白
Traffic routing 只將私人 IP 的流量傳送到 VPC

稍後建立 Migration Job 與 API 時,都要套用這組網路設定,否則連線 Cloud SQL 時可能發生逾時。

第一部分:部署 SQL Server 資料庫

這一部分會建立 Cloud SQL instance、空白 Database 與兩組資料庫帳號,再透過 Migration Job 建立 ProjectManagementWeb 所需的 Schema 和初始資料。可以把 instance 想成整棟資料庫大樓,Database 則是這棟大樓裡專門給 ProjectManagementWeb 使用的房間。

先決定是「建立 Schema」還是「搬現有資料」

這次沒有把本機開發資料整批搬上雲端,而是先建立一個空白 Database,再由 EF Core Migration 照著程式裡的版本記錄,建立資料表、關聯與初始資料。這比較像照施工圖布置一個全新空間,不是把舊房間裡的家具全部搬過來。

Database Migration Service(DMS)用來把既有資料從來源資料庫搬到目標資料庫;EF Core Migration 則依照程式專案中的 Migration 建立或更新 Schema。本篇採用後者。若正式環境還要保留本機資料,必須另外規劃資料遷移、停機時間與遷移後驗證。

建立 Cloud SQL for SQL Server instance

前往「SQL → 建立執行個體 → 選擇 SQL Server」,依序填入:

欄位 本次設定
Instance ID projectmanagementweb-sql
Edition Enterprise
Database version SQL Server 2022 Express
Region asia-east1
Zonal availability Single zone,asia-east1-c
Machine 1 vCPU、3.75 GB 記憶體
Storage 10 GB
Connectivity Private IP
VPC projectmanagementweb-vpc
Public IP 關閉
Collation Chinese_Taiwan_Stroke_BIN
Time zone UTC

這是教學與展示用途的低規格配置。正式上線時,仍要依流量、備份、可用性與復原目標重新評估。

建立完成後,執行個體清單會顯示 projectmanagementweb-sql 為可用狀態:

https://ithelp.ithome.com.tw/upload/images/20260926/20126487cgaq9RyQwX.png

建立空的 Database

Cloud SQL 執行個體建立完成後,點選左上角的導覽選單,依序進入「資料庫 → Cloud SQL」。

https://ithelp.ithome.com.tw/upload/images/20260926/2012648727uUJlgfsC.png

從執行個體清單點進 projectmanagementweb-sql,再選擇左側功能列的「資料庫」。剛建立完成時,清單中只有 master、model、msdb 與 tempdb 等 SQL Server 系統資料庫;不要直接把應用程式資料放進這些資料庫。按下頁面上方的「建立資料庫」,開始建立 ProjectManagementWeb 專用的資料庫。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487aOrx16CJ0w.png

右側會開啟「建立資料庫」面板,在「資料庫名稱」輸入:

ProjectManagementWeb

畫面也會提示名稱必須遵守 SQL Server ID 規則。確認拼字與大小寫後,按下「建立」。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487SBGvqTlX1P.png

建立作業完成後,回到資料庫清單,確認 ProjectManagementWeb 已經出現。此時 Database 仍是空的,資料表會在執行 Migration Job 後建立。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487cw4fPvbNRc.png

分開 Migrator 與 Runtime 資料庫帳號

接著在 Cloud SQL 的「使用者」頁面建立兩組 SQL Server 帳號:

帳號 用途 權限原則
pmw_migrator 執行 EF Core Migration 與 Hangfire Schema 初始化 可建立或修改 Schema,只在部署時使用
pmw_app API 平常讀寫業務資料 只保留執行階段需要的讀寫權限

把帳號拆開,就像裝潢工人與店員不該共用同一把萬能鑰匙。pmw_migrator 只在需要改變結構時出場;API 平常使用的 pmw_app 只能讀寫業務資料,就算 API 發生漏洞,也不會順便送出改資料表結構的權限。

在 Cloud SQL「使用者」頁面建立 SQL Server login 後,還要進入 ProjectManagementWeb Database 建立對應的 user,並加入正確的 database role。本機環境的 docker/sql/init.sql 使用相同原則:pmw_migrator 加入 db_owner,pmw_app 只加入 db_datareader 與 db_datawriter。不要因為 login 已建立,就以為 Database 內的權限也自動跟著完成。

實際密碼請使用隨機高強度字串,而且不要放進文章截圖、Git 或 Dockerfile。

把連線字串放進 Secret Manager

Secret Manager 像一個上鎖的鑰匙櫃。應用程式記住的是 Secret 名稱,不是直接把密碼貼進設定檔或容器映像。

前往「安全性 → Secret Manager」,分別建立:

pmw-db-migrator-connection
pmw-db-app-connection

第一個 Secret 保存 pmw_migrator 的連線字串,交給 Migration Job;第二個保存 pmw_app 的連線字串,交給後端 API。建立 Secret 時才輸入完整連線字串,文章與截圖只保留 Secret 名稱,不公開內容。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487jPodvfIEni.png

建立 Secret 不代表 Cloud Run 自動擁有讀取權。還要建立專給 Migration Job 使用的 pmw-migrator Service Account,再到 pmw-db-migrator-connection 的「權限」頁面,只授予它 Secret Manager Secret Accessor 角色。Service Account 像服務在雲端上的員工證:有鑰匙櫃,還是得有正確的員工證才拿得到鑰匙。

https://ithelp.ithome.com.tw/upload/images/20260926/201264871nxBDwX7ux.png

建立 Artifact Registry 與 Cloud Build 建置流程

Artifact Registry 與 Cloud Build 的名稱很接近,而且不一定會直接顯示在左側主選單。先釐清兩者的責任:

服務 這次負責的工作
GitHub Repository 保存 ASP.NET Core 原始碼、Dockerfile 與部署當時使用的 cloudbuild.yaml
Cloud Build 讀取 GitHub 原始碼,執行容器建置與推送指令
Artifact Registry 保存建置完成的 api 與 database-migrator Docker 映像

Cloud Build 像打包工廠,負責把原始碼與 Dockerfile 做成容器映像;Artifact Registry 則是倉庫,只負責收好建置完成的映像。先建立空倉庫,不會自動變出貨物。Cloud Build 實際成功執行並推送後,裡面才會出現可供 Cloud Run 部署的映像。

從哪裡找到 Artifact Registry 與 Cloud Build?

最快的方法是使用 Google Cloud Console 頁面上方的搜尋列:

  1. 關閉左側導覽選單。
  2. 在上方搜尋列輸入 Artifact Registry 或 Cloud Build。
  3. 從搜尋結果選擇同名的 Google Cloud 產品。

如果搜尋結果不容易辨認,也可以走完整產品清單:

導覽選單
→ 查看所有產品
→ CI/CD
→ Artifact Registry 或 Cloud Build

在「所有產品」的 CI/CD 分類中,可以同時看到 Cloud Build 與 Artifact Registry。名稱左側的星號可以把服務加入收藏,之後就會比較容易從導覽選單開啟。

https://ithelp.ithome.com.tw/upload/images/20260926/201264876bkeTtAnp0.png

建立 Artifact Registry Docker 存放區

進入 Artifact Registry 後,選擇左側的「存放區」,再按下「建立存放區」。這次建立的是保存容器映像的 Docker 存放區:

中文介面欄位 本次設定
名稱 projectmanagementweb
格式 Docker
模式 標準
位置類型 區域
區域 asia-east1
加密 Google 代管的加密金鑰
不可變更的映像檔標記 停用

建立頁面可能會詢問是否啟用安全漏洞掃描。這不是完成本篇部署的必要條件,而且畫面會提示可能產生額外費用;是否啟用應依專案的安全與成本需求決定。

按下「建立」後,進入 projectmanagementweb 存放區。剛建立完成時沒有 api 或 database-migrator,這是正常狀態,因為 Cloud Build 還沒有執行。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487TXyeQRC5jx.png

讓 Cloud Build 連接後端 GitHub Repository

用前面的搜尋方式開啟 Cloud Build,選擇左側的「存放區」。這次使用第 2 代 Cloud Build Repository,操作順序是:

Cloud Build
→ 存放區
→ 第 2 代
→ 連結存放區

依照畫面完成 GitHub 授權,選擇 GitHub 帳號,再連接後端原始碼存放區:

JJDing-Louis/ProjectManagementWeb_BackEnd

這裡連接的是 GitHub 原始碼 Repository,不是前面建立的 Artifact Registry Docker 存放區。完成後,Cloud Build 的存放區清單會顯示 GitHub 供應商與後端 Repository。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487759Q6oUGIH.png

建立手動執行的 Cloud Build 觸發條件

接著選擇 Cloud Build 左側的「觸發條件」,按下「建立觸發條件」。本次不是每次 push 都自動建置,而是先建立一個可以手動執行的觸發條件:

中文介面欄位 本次設定
名稱 manual-build-backend-images
區域 asia-east1(台灣)
說明 手動觸發 / Manual invocation
事件 手動叫用
來源存放區服務 Cloud Build 存放區
存放區 JJDing-Louis/ProjectManagementWeb_BackEnd

https://ithelp.ithome.com.tw/upload/images/20260926/20126487BbgVO85tyU.png

往下找到「設定」,選擇:

中文介面欄位 本次設定
類型 Cloud Build 設定檔(YAML 或 JSON)
位置 存放區
Cloud Build 設定檔位置 /cloudbuild.yaml

https://ithelp.ithome.com.tw/upload/images/20260926/20126487VZLU4ICBoX.png

/cloudbuild.yaml 前面的 / 代表檔案位於 Repository 根目錄。這是本次部署當下使用的設定;如果日後移動或重新命名檔案,觸發條件也要一起更新,否則 Cloud Build 會找不到設定檔。

部署當時的 cloudbuild.yaml 會依後端 Dockerfile 建立兩個用途不同的映像:

  • api:部署為長時間接收 HTTP 請求的 Cloud Run service。
  • database-migrator:部署為執行完成就停止的 Cloud Run Job。

手動執行並確認映像真的推送成功

建立觸發條件後,回到「觸發條件」清單,找到 manual-build-backend-images 並按下「執行」。選擇這次要建置的 Git revision 後送出,再到 Cloud Build 的「記錄」查看進度。

建置狀態變成成功後,還要檢查兩個地方:

  1. Cloud Build 記錄中,每個步驟都成功完成,沒有權限或找不到 cloudbuild.yaml 的錯誤。
  2. 回到 Artifact Registry 的 projectmanagementweb 存放區,確認 api 與 database-migrator 兩個映像都出現。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487d6yufSmJGZ.png

https://ithelp.ithome.com.tw/upload/images/20260926/20126487aMfXW0NbIN.png

確認兩個映像都已出現在 Artifact Registry 後,再建立 Migration Job。若 Cloud Build 顯示成功但存放區沒有映像,先查看建置記錄中的映像路徑與推送步驟,再檢查 Cloud Build 的執行身分是否有寫入這個存放區的權限。

建立 Cloud Run Migration Job

前往「Cloud Run → Jobs → 部署容器」,建立 database-migrator,並選擇 Artifact Registry 中的 database-migrator 映像。這次配置為 1 CPU、512 MiB 記憶體,Task timeout 設為 15 分鐘,執行身分則選擇剛才建立的 pmw-migrator Service Account。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487njzIsT5sm7.png

在變數與 Secret 設定中加入:

名稱 來源或值
ConnectionStrings__DefaultConnection 參照 pmw-db-migrator-connection Secret
PMW_MIGRATION_DEFAULT_TIME_ZONE_ID Asia/Taipei
Hangfire__PrepareSchemaIfNecessary true

https://ithelp.ithome.com.tw/upload/images/20260926/20126487fievvBhEDl.png

網路部分開啟 Direct VPC egress,選擇 projectmanagementweb-vpc 與 projectmanagementweb-asia-east1,流量路由選擇只傳送私人 IP 流量。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487Mr5i7q74zf.png

部署完成後按下「執行」。這個映像會先執行 dotnet ef database update,再初始化 Hangfire 所需的 Schema。Job 成功完成後就停止,不會像 Cloud Run service 一樣持續提供 HTTP 服務。

本次執行紀錄 database-migrator-mpfx5 顯示一個 Task 成功、Exit code 為 0,約 13 秒完成。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487uSpQGvMS2g.png

驗證 Schema、初始資料與帳號權限

Job 顯示成功後,開啟 Cloud SQL Studio,連進 ProjectManagementWeb 並依序檢查:

  1. __EFMigrationsHistory 是否有 Migration 紀錄。
  2. 應用程式所需的資料表是否已建立。
  3. 初始角色資料是否存在。
  4. 初始使用者資料是否存在。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487TEq4YbInKJ.png

https://ithelp.ithome.com.tw/upload/images/20260926/20126487QSW84J4bdR.png

https://ithelp.ithome.com.tw/upload/images/20260926/20126487hmgJyyJhu8.png

最後用 pmw_app 帳號測試 API 所需的讀寫操作,並確認它不能修改 Schema。完成這項檢查後,資料庫部署就告一段落。

第二部分:部署 ASP.NET Core 後端 API

資料庫可用後,接著把 API 部署到 Cloud Run。完成標準是 Cloud Run Revision 正常啟動、/health 回應成功,而且 API 可以讀寫 Cloud SQL。

確認 API 映像已準備好

本篇使用前面 Cloud Build 產生的 api 映像。後端需要的 Forwarded Headers、CORS、CSRF、Cookie 安全設定及容器設定,都視為已在部署前完成;Schema 更新也已交由 database-migrator Job 處理,API 啟動時不會再次執行 Migration。

後端 API 與 Migration Job 由同一次 Cloud Build 產生。它們使用同一份原始碼,但工作壽命不同:API 像每天營業的店員,會持續接收 HTTP 請求;Migration Job 像裝潢工班,建好 Schema 就離開。前一節已確認 api 與 database-migrator 都在 Artifact Registry 中,因此不需要從本機再次執行 docker push。

日後若有新版後端程式,先把變更推送到 GitHub,再重新執行 manual-build-backend-images。Cloud Build 成功後,回到 Cloud Run 部署新的 api 映像版本。

建立 API 使用的 Service Account

人會用帳號登入 Google Cloud,雲端服務彼此合作時也需要可辨識的身分。Service Account 就是 API 的員工證。員工證上不該印著「所有門都可以開」,只要給 API 執行當下工作所需的權限。

先從左上角的導覽選單進入:

導覽選單
→ IAM 與管理
→ 服務帳戶

https://ithelp.ithome.com.tw/upload/images/20260926/20126487MJNLkr5EFJ.png

進入「服務帳戶」頁面後,按下「建立服務帳戶」,並填入:

欄位 本次設定
服務帳戶名稱 pmw-api
服務帳戶 ID pmw-api
說明 ProjectManagementWeb Cloud Run API runtime identity

確認後按下「建立並繼續」。這裡不直接授予範圍過大的 Project 角色;建立完成後,再針對 API 需要讀取的 Secret 個別授權。最後產生的 Service Account 電子郵件為:

pmw-api@solid-terra-509706-e5.iam.gserviceaccount.com

在建立 Cloud Run service 前,先到下列 Secret 的「權限」頁面,把 Secret Manager Secret Accessor 授予 pmw-api:

  • pmw-db-app-connection
  • pmw-jwt-private-key
  • API 執行時會使用的其他 Secret

pmw-db-migrator-connection 不在這份清單中,因為它只提供給 Migration Job 使用。

建立 Cloud Run API service

從導覽選單進入「Cloud Run → 服務」。這個頁面會列出目前 Project 中所有持續接收 HTTP 請求的 Cloud Run service;前面建立的 database-migrator 則會出現在「工作」頁面。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487PhJsVPLznB.png

進入服務清單後,按下頁面上方的「部署容器」。如果 Project 還沒有任何 Cloud Run service,也可以按畫面中央的「建立服務」。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487sOof3mo8Ej.png

在「建立服務」頁面選擇「依據現有的容器映像檔部署單一修訂版本」,再從 Artifact Registry 選擇 projectmanagementweb/api 映像。接著填入:

欄位 本次設定
Service name api
Region asia-east1
Container port 8080
Billing Request-based
Minimum instances 0
Service Account pmw-api
Authentication 允許未經驗證的叫用

前端 Nginx 會從另一個 Cloud Run service 轉送瀏覽器的 API 請求,因此這裡允許未經驗證的叫用。這句話容易誤會:它只是讓網路請求到得了 Cloud Run 大門,不是讓任何人直接變成系統管理員。API 內部的登入、授權、CSRF 與輸入驗證仍會照常執行。

在環境變數與 Secret 中設定正式環境需要的值,包括:

  • ASPNETCORE_ENVIRONMENT。
  • ConnectionStrings__DefaultConnection,來源為 pmw-db-app-connection。
  • Cors__AllowedOrigins__0,值為前端 Cloud Run 實際使用的 origin。
  • ReminderJobs__Enabled=false,在專用的雲端排程 Job 完成前,不讓 request-based Cloud Run service 假裝是會常駐的排程主機。
  • JWT 簽章金鑰與其他機密設定,各自從 Secret Manager 注入。
  • SMTP 等外部服務設定;沒有使用的功能不要先放入不必要的憑證。

若前端 service 還沒建立,此時還不知道它的最終 origin。可以先完成 API 部署,等前端取得 Cloud Run 網址後,回到 API 補上 Cors__AllowedOrigins__0、部署新 Revision,再進行整合驗收。

網路部分和 Migration Job 相同,使用 Direct VPC egress 連到 projectmanagementweb-vpc,並只將私人 IP 流量送進 VPC。

部署完成後,Cloud Run 會提供 asia-east1.run.app 網址。這次服務的主要網址為:

https://api-956023471429.asia-east1.run.app

https://ithelp.ithome.com.tw/upload/images/20260926/20126487rhn6HczEVn.png

確認設定後按下「建立」。部署完成時,服務狀態會轉為綠色,並顯示目前正在接收流量的 Revision。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487ePdpc4r5yp.png

先測 /health,再測需要資料庫的 API

API Revision 顯示綠色後,先開啟:

https://api-956023471429.asia-east1.run.app/health

/health 像先問店員「你有沒有上班?」,能回應只能證明應用程式活著。接著還要呼叫一支會讀取資料庫的 API,才能證明店員拿得到後方倉庫的資料。兩項檢查都通過,再繼續部署前端。若檢查失敗,可從 Cloud Run Log 依序確認 Secret 權限、連線字串、Direct VPC egress、Cloud SQL Private IP 與資料庫帳號。

第三部分:部署 Vue 前端網頁

後端通過檢查後,就可以把它的 Cloud Run URL 填入前端容器的 BACKEND_ORIGIN。這裡的 Nginx 像服務台:瀏覽器只會對前端同網域下的 /api/v1 提出請求,Nginx 看到 /api/ 開頭的路徑後,再從容器內部把請求轉給後端。

確認前端部署資料已準備好

這裡假設前端 Repository 已有可用的 Dockerfile 與 Nginx 設定:Vue production build 會被包進容器、Vue Router 重新整理時會回到 index.html,而 /api/** 會代理到 $BACKEND_ORIGIN。本篇直接使用這份已驗證的部署設定連接 Cloud Run。

用 Cloud Run 連接 GitHub Repository 部署

前往「Cloud Run → Services → Connect repository」,選擇使用 Cloud Build,接著連接:

JJDing-Louis/ProjectManagementWeb_FrontEnd

https://ithelp.ithome.com.tw/upload/images/20260926/20126487F9WupmvbZ5.png

建置設定使用 ^main$ 作為 Branch regex,Build type 選擇 Dockerfile,路徑填 /Dockerfile。服務設定如下:

欄位 設定
Service name projectmanagement-web
Region asia-east1
Container port 8080
Billing Request-based
Minimum instances 0
Authentication 允許未經驗證的叫用
Ingress 全部

https://ithelp.ithome.com.tw/upload/images/20260926/20126487CniiMPTKD9.png

在環境變數加入 BACKEND_ORIGIN,值填部署後端時取得的 origin。只填到網域,不加 /api/v1,結尾也不要再加 /:

BACKEND_ORIGIN=https://實際的後端-Cloud-Run-網址

下圖保留部署當時使用的有效後端網址。若日後重建後端服務,請以 Cloud Run 當下顯示的網址為準。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487YYedf1jF91.png

這個網站要公開展示,因此 Ingress 選擇「全部」,並允許未經驗證的叫用。設定完成後按下「建立」,等待 Cloud Build 建置映像並完成 Cloud Run Revision 部署。

確認前端網頁與 API 真的連在一起

部署成功後,Cloud Run 提供的前端網址為:

https://projectmanagement-web-956023471429.asia-east1.run.app

先開啟登入頁,再使用預先建立的帳號登入。登入後能顯示使用者與專案資料,表示前端、Nginx 代理、後端 API 與 Cloud SQL 已經接通。

https://ithelp.ithome.com.tw/upload/images/20260926/20126487uJnW4oT3Hd.png

https://ithelp.ithome.com.tw/upload/images/20260926/20126487FZMwctIuGT.png

https://ithelp.ithome.com.tw/upload/images/20260926/20126487NQojakAGua.png

整合驗收:從瀏覽器走完一次真正的操作

三個部分都部署完成後,不要只看 Cloud Run 上的綠色狀態。那像是搬家公司通知「箱子已送達」,還不代表水龍頭、門鎖與收銀機都能用。回到瀏覽器,依序檢查:

  1. 開啟前端首頁。
  2. 直接進入並重新整理 /sign-in,確認沒有 404。
  3. 檢查 /api/v1/security/csrf-token。
  4. 實際登入,確認 API 狀態碼與畫面轉場。
  5. 重新整理頁面,檢查 /api/v1/auth/me。
  6. 檢查 PMW-REFRESH Cookie 的 HttpOnly、Secure、SameSite=Lax 與 Path=/api/v1/auth。
  7. 新增、讀取、修改實際的專案或工作項目,確認 Cloud SQL 有寫入資料。
  8. 登出後確認受保護頁面不再可以存取。

費用、安全與示範結束後的收尾

哪些資源可能持續計費?

Cloud Run 設為 Minimum instances 0 時,沒有請求可以縮到零,但 Cloud SQL instance 不會因為沒有人使用就自動消失,仍可能持續產生運算與儲存費用。Artifact Registry 的映像儲存、Cloud Build 的建置時間、Secret Manager 的存取與 Cloud Logging 的用量,也各有自己的計費方式。

展示期間可以設定 Budget 與 Alert 追蹤費用。Budget Alert 只會發出通知,不會自動停止服務。

哪些機密與權限需要回頭檢查?

部署完成後,再做一次最小權限檢查:

  • pmw-api 只能讀取 API 實際需要的 Secret。
  • Migration Job 才能取得 pmw-db-migrator-connection。
  • Cloud SQL 維持關閉 Public IP。
  • pmw_app 不具備修改 Schema 的高權限。
  • 前端與 API 雖允許公開叫用,應用程式層仍保留登入、授權與 CSRF 防護。
  • 截圖、Log 與 Git 歷史中沒有連線字串、密碼、Private Key 或付款資料。

展示完成後要停止或刪除什麼?

若網站只用於短期展示,可以依照下列順序收尾:

  1. 先確認資料是否需要匯出或保留備份。
  2. 刪除不再使用的前端與 API Cloud Run services。
  3. 刪除 Migration Job 與不再需要的舊映像版本。
  4. 確認不需要復原資料後,再刪除 Cloud SQL instance。
  5. 移除不再使用的 Secret 與 Service Account 權限。
  6. 最後檢查 Billing 報表,確認沒有遺漏的持續計費資源。

Private Services Access 或 VPC 可能同時被其他資源使用,刪除前要先檢查相依關係,不要只因為本篇部署結束就直接移除。

小結

這次的建立順序是:先準備 VPC 與 Private Services Access,再建立 Cloud SQL、空白 Database、帳號與 Secret,接著透過 Cloud Build 產生映像,並用 Cloud Run Job 建立 Schema。資料庫驗證完成後,依序部署後端 API 與前端網頁,最後從瀏覽器完成登入、讀取、寫入與登出測試。

把順序排清楚後,每一段都有明確的輸入與檢查點。之後需要重新部署時,也可以沿著同一條路線判斷要更新映像、Cloud Run Revision,還是資料庫 Migration,而不必重建整套環境。

網站搬上雲端不是故事結束。使用者開始操作後,新想法與修正一定會再出現。下一篇會把鏡頭拉回開發流程,看看需求改變時,如何請 Agent 讀懂現況、開發修改,並保留可審查的變更記錄。


上一篇
Day26_什麼是雲端服務?來談談 Google Cloud
下一篇
Day28_誒Codex,我有個大膽的想法,我想再做一些修改
系列文
Codex的規格驅動開發 :30 天打造 .NET 內部專案管理系統 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言