每次上傳新的 Docker Image、要部署到 Google Cloud Run 時,都要另外打 gcloud
指令實在是有點繁瑣,本篇教學會與你分享怎麼利用 GitHub Action,在你每次 commit 後,就能自動同時部署到 Cloud Run 上,不用再打部署指令,簡化開發流程!
前情提要
這是筆者第一篇程式的技術學習筆記,所以在解釋跟教學步驟上會略顯繁瑣、或是有需改善的地方,還請大佬或是讀者不吝指教。
而筆者盡可能將此文的技術門檻降至最低,所以會含括一些前置步驟的教學,如果你已經設定過可以直接略過!
Cloud Run + GitHub Action:省去手動部署的流程
GitHub Action 是 Github 的 CI 功能,簡而言之就是把 commit 後的 Build、Test、Deploy 的流程全都自動化,不用手動另外執行( 就是做 Jenkins 的工作 )
這位前輩的文章有更完整的解釋:GitHub Actions 基本介紹 – 開始自動化 workflow 的第一步 – iT 邦幫忙
那麽 GitHub Action 對於要部署到 Cloud Run 的專案有什麼好處呢?透過設定 GitHub Action,你可以將這些過程全都自動化:
- 完成Google Cloud & Docker 登入驗證
- 建立程式的 Docker 容器
- 提交 Docker 容器到 Artifact Registry
- 將容器部署到 Cloud Run 服務
而且是在每次新的 commit 後就會自動完成,你只需專注做程式碼的開發即可,是不是超方便的?
不過補充一下,GitHub Actions 是有額度限制的,超過額度後要付費才能繼續用,以下是 GitHub Action 的免費使用額度,收費標準以執行時間為單位:
- GitHub 免費版:每個月 2,000 分鐘
- GitHub Pro:每個月 3,000 分鐘
- GitHub 公開 Repo: 不限次數免費使用
開始之前,你應該要先 …
在進到教學正文之前,會需要你先做以下三件事:
- 略懂 Docker 跟 GCP Cloud Run 的用途
- 寫好專案的 Dockerfile
- 在 GCP 建立好自己的專案,並取得專案編號
如果做好前置作業,就照著下文設定你的 GitHub Action 吧!整個過程大約花費 10 分鐘。
步驟一:設定 Google Cloud 專案的 Identity federation
本篇文章會教學用 Google 官方的 YAML,而針對 Auth 部分,會需要用到專案的 Workload Identity Federation 來進行 GitHub Action 的 OIDC 驗證,因此,這段會先教學如何建立 GCP 專案的 Identity federation。
下文會用 gcloud 指令進行操作,如果你的電腦還沒有裝 Google Cloud SDK,或之前都是用 GUI 網頁來部署的話,可以照著這篇文章的教學安裝 SDK 並完成設定:如何安裝 Google Cloud SDK 命令行工具?macOS 就是那麼簡單 – Python 編程.圖表
雖然上篇文章是 MacOS 版本的,但安裝過程跟 Windows 類似 ~
安裝好 SDK 並登入管理 GCP 的 Google 帳號後,打開 Terminal 先設定一個環境變數,省去重複打編號的過程:
export PROJECT_ID="你的專案 ID"
接著創建一個專案服務帳戶,你可以修改引號內的帳戶 ID( 如果你已經有一個專案服務帳戶,可以略過這步,並記下你現有專案服務帳戶的 email 位置 ):
gcloud iam service-accounts create "github-service-account" \
--project "${PROJECT_ID}"
再來透過這個指令,新增一個 Workload Identity 集區( Workload Identity Pool )你可以自訂 “github-pool” 跟 display-name 的名稱:
gcloud iam workload-identity-pools create "github-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="GitHub Deployment Poll"
接著輸入這段指令取得集區的編號:
gcloud iam workload-identity-pools describe "github-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)"
應該會得到類似 projects/111111111/locations/global/workloadIdentityPools/github-pool
的輸出結果,將這組集區編號設定成環境變數,方便等等重複使用:
export WORKLOAD_IDENTITY_POOL_ID="..."
再來為集區新增一個 Provider:
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github-pool" \
--display-name="Github Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
p.s. 如果你要建立全部 repo 權限的 Provider,attribute-mapping 要改成這個:
--attribute-mapping="google.subject=assertion.sub,attribute.repository_owner=assertion.repository_owner"
再來為服務帳號綁定工作集區的使用者 IAM 權限,先設定你的 Repo 名稱作為環境變數,將引號改成你的 GitHub username 和 repo 英文代號:
export REPO="github_username/repo_name"
再輸入這段指令:
gcloud iam service-accounts add-iam-policy-binding "github-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
如果你要套用於全部 repo 的 GitHub Action,先將你的 GitHub name 設為環境變數:
export OWNER="username"
然後修改前兩個指令的 member 參數:
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository_owner/${OWNER}"
最後輸入以下指令,拿到集區 Provider 的資源名稱並記下來:
gcloud iam workload-identity-pools providers describe "github-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github-pool" \
--format="value(name)"
你應該會得到類似以下的名稱 projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider
,稍後建立 GitHub secret 時會用到。
步驟二:設定 GitHub Repo Secret
由於上文設定的 Google Cloud 資源名稱跟服務帳戶都是機密資訊,無論 repo 是否為 public 還是 private,都不建議直接寫在 GitHub Action 的 YAML 檔上面。
而針對不想公開在網路上,但又需要用在 GitHub Action 內的敏感資訊( 像是 GCP 集區名稱、密鑰、資料庫網址 )可以設定成 repo 的 secret,讓 GitHub Action 可以用類似環境變數的方式存取,同時讓敏感資訊不會直接暴露在 YAML 上。
所以接下來要新增 Cloud Run 自動部署所需的 secret。先打開你的 GitHub Repository 頁面,進入 Setting,點選左側選單 Secrets and variables → Action:
點選 New repository secret:
新增兩個 secret:
WIF_PROVIDER
: 步驟一最後取得的 Identity federation 資源名稱WIF_SERVICE_ACCOUNT
: 步驟一設定的 GCP 專案服務帳戶( 包含 @ 之後的網域 )
這樣就完成 secret 的設定了!
步驟三:建立 Cloud Run GitHub Action
最後,我們就能沿用 Google 官方寫好的 Cloud Run Deploy YAML 檔到 repo 內,回到你的 repo 頁面 → Actions:
搜尋 Cloud Run,並點選 “Build and Deploy to Cloud Run” :
修改 YAML 檔案第 51 ~ 55 行的環境變數,根據註解自訂成你的專案編號、Cloud Run 服務名稱跟地區,地區可以使用 asia-east1
也就是台灣的機房:
另外需要改一下 109 行的 Docker image 網址:
將第 109 行改成這句,新增一個 Docker image 名稱的參數:
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.SERVICE }}:${{ github.sha }}
筆者用官方的 YAML 部署時,就遇到了 image 網址少了一個 image name 參數的錯誤,上面的做法是參考這篇的討論:Docker push “Missing image name”-error when pushing to GCP Artifact Registry from Github Actions
完成所有修改後,按右上方的 Commit change、新增 GitHub Action 的 YAML 檔就大功告成:
之後每次 commit 到 repo 的 main 分支就會自動執行 GutHub Action,將程式打包成 Docker image 並部署到 Cloud Run上了!你可以在 repo 的 Actions 頁看到自動部署的進度跟結果:
總結 Wrap up
以上就是設定 Cloud Run 自動部署的 GitHub Action 操作教學了,再重新概述一下 3 個步驟:
- 設定 GCP 專案的 Identity federation
- 將集區的 Provider 名稱和服務帳戶新增到 Repo Action 的 secret
- 建立並自訂 GitHub Action YAML 檔案
透過以上 3 步,就能設定 Repo 的 Action 了,你也可以另外加入測試等其他步驟,完善你的 CI/CD 流程,不過使用時要注意 GitHub Action 的額度限制喔~
筆者會有寫這篇教學的靈感,是因為趁暑假自學 Web 開發的技術時,剛好碰到 Serverless 的部署,我希望能自動化 Cloud Run 部署的工作,也趁機學一下 GitHub Action 的原理跟實作,只是網路上的文章都是舊版的部署方法,便記錄新版 Google 官方的 Cloud Run Action 怎麼設定。
當然,筆者在這篇是直接用 Google 官方寫的 YAML 檔,也沒有加入 unit test 等項目,所以沒有發揮用 GitHub Actions 做 CI/CD 的功能,未來若有機會進一步學到這塊的話,會再撰寫文章跟大家分享我的淺見所學。
Reference
本篇教學主要是受到下文的啟發與幫助,感謝 Robby 前輩寫的筆記文:
- GCP – 使用 Github Actions 部署 React 到 Cloud Run | Robby – 全端的 Front-End Engineer – 點部落
- GitHub – google-github-actions/auth: A GitHub Action for authenticating to Google Cloud.