iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0

昨天用 Helm 部署了 dev 和 staging,但每次改程式都要手動 build image、push、helm upgrade。今天用 GitHub Actions 把 build 和 push 自動化,Push 到 GitHub 就產生新版 image,並把版本號寫回 Git。


CI/CD 是什麼

CI(Continuous Integration):每次 Push 程式碼,自動 build image(有測試的話也一起跑),確認這次的改動可以產出新版本。

CD(Continuous Deployment):把新版本自動部署到環境上。

沒有 CI/CD 之前,部署流程是:

  1. 本機 build image
  2. 手動 push 到 Docker Hub
  3. 手動 helm upgrade 更新 K8s

為什麼今天的 CI 不直接部署

GitHub Actions 預設的 runner(ubuntu-latest)是 GitHub 雲端的臨時機器,它連不到你本機的 minikube:kubeconfig 裡的位址是 127.0.0.1,在那台機器上指的是它自己。

就算叢集在雲端連得到,讓 CI 直接持有叢集權限也有風險。業界常見的做法是把 CI 和 CD 分開:

  • CI:build、push image,再把新的 image tag 寫回 Git
  • CD:由叢集裡的工具去讀 Git,自己部署

今天先完成 CI,部署暫時手動做;明天用 ArgoCD 接手 CD。


Pipeline 設計

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 確認新版本。

Step1: 確認 repo 結構

今天開始要用 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 要跟著改。

Step2: 設定 GitHub Secrets

  1. Docker Hub → Account settings → Personal access tokens,建立一個 Read & Write 權限的 token。
  2. GitHub repo → Settings → Secrets and variables → Actions,新增:
    • DOCKERHUB_USERNAME:Docker Hub 帳號
    • DOCKERHUB_TOKEN:剛剛建立的 token

不需要 kubeconfig,CI 不會碰叢集。

Step3: 建立 Workflow

建立 .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。
  • CI 自己 push 回 main 不會再觸發一次 workflow,GitHub 內建 token 做的 push 不會觸發新的 workflow,不會無限循環。

Step4: Push 觸發 CI

git add .
git commit -m "add CI workflow"
git push

到 GitHub repo 的 Actions 頁面看執行狀態,每個步驟都有 log,出錯時從這裡找原因。

Step5: 確認結果

  1. Docker Hub 上兩個 image 都多了一個 commit SHA 的 tag。
  2. 把 CI 的 commit 拉回本機:
git pull
git log --oneline -3

會看到一筆 ci: update staging image to ...,values-staging.yaml 的 tag 已經變成 commit SHA。

⚠️ CI 會 commit 回 main,之後本機要 push 前都先 git pull,否則會被拒絕。

Step6: 手動部署到 staging

在 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 換行要把 \ 改成反引號 `,或寫成一行。


小結

  • CI:Push 到 main → 自動 build、push image → 把新 tag 寫回 values-staging.yaml
  • commit SHA 當 image tag:每個版本唯一,可追溯
  • GitHub Secrets:憑證不寫進程式碼
  • CI 不碰叢集:只負責產出 image 和更新 Git

現在每次部署還是要手動 git pull 和 helm upgrade。明天學 ArgoCD,讓叢集自己盯著 Git,values-staging.yaml 一改就自動部署。


上一篇
Day 24|Helm 多環境部署實戰
系列文
從零學 K8s|30 天核心概念 × 實作,新手也能真正掌握 Kubernetes 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言