架站筆記

GitHub Actions 自動部署(CD)到 GCP Cloud Run 完整教學

2026-06-02 #GCP#Cloud Run#GitHub Actions#CI/CD#Workload Identity Federation

本文聚焦在 「程式碼推上 GitHub → 自動 build → 自動部署到 Cloud Run」 這條 CD 管線的設定。

⚠️ 安全提醒:文中所有專案 ID、專案編號、Service Account email、WIF 路徑等敏感資訊,都以佔位符(<...>)取代。實際操作時請替換成自己的值,切勿把明碼寫進公開文件。

整體流程

整條 CD 管線只要一個 git push 就會自動跑完:

flowchart TD
    A([git push origin main]) --> B[GitHub Actions 觸發]
    B --> C["① 透過 WIF 認證 GCP
(免金鑰)"] C --> D["② docker build 映像檔"] D --> E["③ docker push 到
Artifact Registry"] E --> F["④ gcloud run deploy
部署到 Cloud Run"] F --> G(["瀏覽器開 Cloud Run URL
看到網站 🎉"])

💡 核心觀念:用 Workload Identity Federation(WIF) 建立 GitHub 與 GCP 的信任關係,GitHub Actions 不需要持有任何金鑰即可取得部署權限。


前置準備

1. 啟用必要的 GCP API

於 GCP Console 啟用以下 API:

  • Cloud Run Admin API
  • Artifact Registry API
  • Cloud Build API
  • Service Networking API
  • Secret Manager API

2. 建立 Artifact Registry(存放 Docker 映像檔)

設定 值
Format Docker
Region asia-east1
Mode Standard

完整路徑格式:

1
asia-east1-docker.pkg.dev/<PROJECT_ID>/<REPOSITORY>

3. 建立 Service Account 並授予角色

建立一個專供 GitHub 推送/部署使用的 Service Account,逐一加上以下 3 個角色:

角色 用途
Artifact Registry 寫入者(Writer) 推送映像檔(⚠️ 不是「服務代理」)
Cloud Run 管理員 部署服務
服務帳戶使用者 部署時模擬執行身分

設定 Workload Identity Federation(免金鑰認證)

建立 Workload Identity Pool

  • Pool ID:github-pool

新增 OIDC Provider

設定 值
Provider type OpenID Connect (OIDC)
Provider Name github-provider
Issuer URL https://token.actions.githubusercontent.com

屬性對應(Attribute Mapping)

Google OIDC
google.subject assertion.sub
attribute.repository assertion.repository
attribute.repository_owner assertion.repository_owner

屬性條件(關鍵安全設定)

限制只有自己的 GitHub 帳號/組織能使用此 Provider:

1
assertion.repository_owner == '<GITHUB_OWNER>'

綁定 Service Account 與 WIF

到 Service Account 的 「具備存取權的主體(Principals with access)」 分頁,點 「授予存取權」,新增主體:

1
principalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/github-pool/attribute.repository/<GITHUB_OWNER>/<REPO_NAME>

角色:Workload Identity 使用者

📌 容易搞混的地方:「這個 SA 能做什麼」要在 IAM 頁編輯;「誰能用這個 SA」要在 SA 的「具備存取權的主體」頁編輯。


GitHub Secrets 設定

到 GitHub repo 的 Settings → Secrets and variables → Actions,新增 3 個 Secrets(實際值請填自己的,勿外流):

Name 內容說明
GCP_PROJECT_ID 你的 GCP 專案 ID
GCP_WIF_PROVIDER projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/github-pool/providers/github-provider
GCP_SA_EMAIL 部署用 Service Account 的 email

GitHub Actions Workflow

於 .github/workflows/push-image.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
name: Build, Push and Deploy to Cloud Run

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
id-token: write # WIF 取得 OIDC token 必須

env:
REGION: asia-east1
REPOSITORY: <REPOSITORY>
IMAGE_NAME: <IMAGE_NAME>
SERVICE_NAME: <SERVICE_NAME>

jobs:
build-push-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
service_account: ${{ secrets.GCP_SA_EMAIL }}

- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v2

- name: Configure Docker auth
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev --quiet

- name: Build Docker image
run: |
docker build -t ${{ env.REGION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

- name: Push to Artifact Registry
run: |
docker push ${{ env.REGION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

- name: Deploy to Cloud Run
run: |
gcloud run deploy ${{ env.SERVICE_NAME }} \
--image=${{ env.REGION }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
--region=${{ env.REGION }} \
--platform=managed \
--allow-unauthenticated \
--port=8080 \
--memory=256Mi \
--cpu=1 \
--min-instances=0 \
--max-instances=2

- name: Show service URL
run: |
URL=$(gcloud run services describe ${{ env.SERVICE_NAME }} --region=${{ env.REGION }} --format='value(status.url)')
echo "Service URL: $URL"

觸發部署

1
2
3
git add .
git commit -m "feat: setup CI/CD pipeline"
git push origin main

推送後,到 GitHub repo 的 Actions 分頁看執行狀況;跑完後開 Cloud Run 配發的 URL 即可看到部署結果。


踩過的坑(CD 相關)

🕳️ 坑 1:組織政策禁止建立 SA 金鑰

錯誤訊息

1
2
服務帳戶金鑰建立功能已停用
組織政策:iam.disableServiceAccountKeyCreation

解法:改用 Workload Identity Federation,完全不用金鑰 —— 這其實是更安全的業界最佳實踐。

🕳️ 坑 2:Artifact Registry 角色加錯

錯誤訊息

1
denied: Permission 'artifactregistry.repositories.uploadArtifacts' denied
錯誤的角色 正確的角色
Artifact Registry 服務代理(Service Agent) Artifact Registry 寫入者(Writer)

🕳️ 坑 3:授予存取權的入口位置

要在 SA 詳情頁分頁列最右邊的「具備存取權的主體 / Principals with access」,才會看到正確的「+ 授予存取權」按鈕,而不是「權限」分頁。

🕳️ 坑 4:Cloud Run 要求容器必須監聽 HTTP port

只「跑完就結束」的容器會一直重啟。Cloud Run 是「無狀態 HTTP 服務」,容器必須監聽 port(預設 8080)。


安全提醒

  • 🔒 切勿把專案 ID、專案編號、SA email、WIF 完整路徑等寫進公開文件;統一以 Secrets 管理。
  • 🔒 WIF 的屬性條件(repository_owner)務必設定,避免其他人的 repo 冒用你的 Provider。
  • 🔒 permissions: id-token: write 是 WIF 運作的必要條件,別漏掉。
Creative Commons 姓名標示 非商業性

本文採用 CC BY-NC 4.0 授權

歡迎轉載與引用,請標明出處(GitHub Actions 自動部署(CD)到 GCP Cloud Run 完整教學 — mur mur);禁止用於商業用途。

商業使用或合作提案,歡迎來信洽談:[email protected]

留言
分享

留言