昨天用 Helm 部署了 dev 和 staging,但每次改程式都要手動 build image、push、helm upgrade。今天用 GitHub Actions 把 build 和 push 自動化,Push 到 GitHub 就產生新版 image,並把版本號寫回 Git。
CI(Continuous Integration):每次 Push 程式碼,自動 build image(有測試的話也一起跑),確認這次的改動可以產出新版本。
CD(Continuous Deployment):把新版本自動部署到環境上。
沒有 CI/CD 之前,部署流程是:
helm upgrade 更新 K8sGitHub Actions 預設的 runner(ubuntu-latest)是 GitHub 雲端的臨時機器,它連不到你本機的 minikube:kubeconfig 裡的位址是 127.0.0.1,在那台機器上指的是它自己。
就算叢集在雲端連得到,讓 CI 直接持有叢集權限也有風險。業界常見的做法是把 CI 和 CD 分開:
今天先完成 CI,部署暫時手動做;明天用 ArgoCD 接手 CD。
Push to main
│
▼
CI(GitHub Actions)
├── build API、frontend image
├── push 到 Docker Hub(tag 用 commit SHA)
└── 把新 tag 寫回 values-staging.yaml,commit 回 Git
│
▼
部署:今天手動 helm upgrade,明天交給 ArgoCD
用 commit SHA 當 tag,每個版本都是唯一的,也能對回是哪次 commit 的程式碼。
今天目標:建立 GitHub Actions CI,Push 後自動 build、push image 並更新 values-staging.yaml 的 tag,再手動部署到 staging 確認新版本。
今天開始要用 GitHub Actions,需要一個自己的 repo。到範例 repo 按 Use this template → Create a new repository 建立,再 clone 自己的 repo 來操作。
已經 clone 範例 repo 的話,在 GitHub 建一個空的 repo,執行
git remote set-url origin <你的 repo 網址>和git push -u origin main即可。
結構大致如下:
Todo-App/
├── backend/ # API 的 Dockerfile
├── frontend/ # frontend 的 Dockerfile
└── helm/
├── todo-app/
├── values-dev.yaml
└── values-staging.yaml
資料夾名稱不同的話,Step3 的
context要跟著改。
DOCKERHUB_USERNAME:Docker Hub 帳號DOCKERHUB_TOKEN:剛剛建立的 token不需要 kubeconfig,CI 不會碰叢集。
建立 .github/workflows/ci.yml:
name: CI
on:
push:
branches:
- main
paths-ignore:
- "helm/**" # 只改 helm 設定時不重新 build
permissions:
contents: write # 允許 commit 回 repo
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push API
uses: docker/build-push-action@v6
with:
context: ./backend
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/todo-app-api:${{ github.sha }}
${{ secrets.DOCKERHUB_USERNAME }}/todo-app-api:latest
- name: Build and push frontend
uses: docker/build-push-action@v6
with:
context: ./frontend
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/todo-frontend:${{ github.sha }}
${{ secrets.DOCKERHUB_USERNAME }}/todo-frontend:latest
- name: Update image tag in values-staging.yaml
run: |
yq -i '.api.image.tag = "${{ github.sha }}"' helm/values-staging.yaml
yq -i '.frontend.image.tag = "${{ github.sha }}"' helm/values-staging.yaml
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git commit -am "ci: update staging image to ${{ github.sha }}"
git push
paths-ignore:明天會直接改 values-staging.yaml 練習,這類變更不需要重新 build image。yq:GitHub runner 內建的 YAML 工具,用來改 tag。latest:同時推 latest,dev 用的就是這個 tag。git add .
git commit -m "add CI workflow"
git push
到 GitHub repo 的 Actions 頁面看執行狀態,每個步驟都有 log,出錯時從這裡找原因。
git pull
git log --oneline -3
會看到一筆 ci: update staging image to ...,values-staging.yaml 的 tag 已經變成 commit SHA。
⚠️ CI 會 commit 回 main,之後本機要 push 前都先
git pull,否則會被拒絕。
在 helm/ 執行:
helm upgrade todo-staging ./todo-app \
--reuse-values \
-f values-staging.yaml \
-n staging \
--wait
--reuse-values:沿用上次的密碼--wait:等 Pod Ready 才回報結果,失敗就會顯示錯誤確認 staging 跑的是新版本:
kubectl get deployment todo-staging-api -n staging -o jsonpath="{.spec.template.spec.containers[0].image}"
輸出的 tag 是 commit SHA,對回 GitHub 的 commit 記錄就知道跑的是哪次的程式碼。
PowerShell 換行要把
\改成反引號`,或寫成一行。
values-staging.yaml
現在每次部署還是要手動 git pull 和 helm upgrade。明天學 ArgoCD,讓叢集自己盯著 Git,values-staging.yaml 一改就自動部署。