GitHub Action
GitHub Actions 是 GitHub 提供的 CI/CD 解決方案。
Tutorials
Building Docker Image (workflow)
- Your Repo ➞ Settings ➞ Security ➞ Secrets and variables ➞ Actions
- Repository secrets
- Name: DOCKERHUB_TOKEN
- Value: <YOUR-TOKEN>
- Repository variables
- Name: DOCKERHUB_USERNAME
- Value: <YOUR-USERNAME>
- Repository secrets
- 其他 Docker Registry 平台登入方式:Docker Login · Actions · GitHub Marketplace
.github/workflows/deploy.yml:yml :
name: Build and Push Docker Image
# ============================================================================
# 【觸發條件】
# ============================================================================
# - push: 當代碼推送到 master 分支時自動觸發
# - workflow_dispatch: 允許在 GitHub Actions 頁面手動觸發部署
# ============================================================================
on:
#push:
# branches:
# - main
workflow_dispatch:
# ============================================================================
# 【環境變數】
# ============================================================================
env:
IMAGE_NAME: gemini-ocr-fastapi
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
# ----------------------------------------------------------------------
# Step : 檢出代碼倉庫
# ----------------------------------------------------------------------
# 將 GitHub 倉庫的代碼下載到 runner 的工作目錄
# 這是後續構建步驟的基礎
# ----------------------------------------------------------------------
- name: Checkout
uses: actions/checkout@v4
# ----------------------------------------------------------------------
# Step : 釋放磁盤空間
# ----------------------------------------------------------------------
# GitHub Actions runner 的磁盤空間有限(約 14GB),為了確保構建過程順利進行,
# 需要清理不必要的文件。此步驟會:
# - 刪除 .NET SDK(如果不需要)
# - 刪除 Android SDK(如果不需要)
# - 刪除 GHC(Haskell 編譯器,如果不需要)
# - 清理 Docker 系統(鏡像、容器、卷等)
# - 顯示磁盤使用情況
#
# 注意:docker system prune 有時可能導致不穩定,如果空間足夠可以註解掉
# ----------------------------------------------------------------------
- name: Free GitHub Actions Disk Space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
# 建議:prune 有時會導致不穩,如果空間還夠,可以先註解掉下面這行測試
sudo docker system prune -af || true
df -h
# ----------------------------------------------------------------------
# Step : 設置 Docker Buildx
# ----------------------------------------------------------------------
# Docker Buildx 是 Docker 的擴展構建工具,支持:
# - 多平台構建(如 linux/amd64, linux/arm64)
# - 構建緩存優化
# - 並行構建
#
# 配置說明:
# - image=moby/buildkit:latest: 使用最新版本的 buildkit 作為構建引擎
# - platforms: 聲明支持的平台(雖然這裡只構建 arm64,但保留 amd64 以備未來擴展)
# ----------------------------------------------------------------------
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: |
image=moby/buildkit:latest
platforms: linux/amd64,linux/arm64
# ----------------------------------------------------------------------
# Step : 登錄到 Docker Hub Registry
# ----------------------------------------------------------------------
# 在推送鏡像之前,必須先通過身份驗證登錄到 Docker Hub
#
# 認證方式:
# # - username/password: 從 GitHub Secrets 中讀取,確保敏感信息不會暴露在代碼中
#
# 安全提示:Docker Hub 憑證存儲在 GitHub Variables 與 Secrets 中,名稱為:
# - DOCKERHUB_USERNAME (Var)
# - DOCKERHUB_TOKEN (Secret) 註: 使用 Personal Access Token
# ----------------------------------------------------------------------
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# ----------------------------------------------------------------------
# Step 5: 構建並推送 Docker 鏡像到 ACR
# ----------------------------------------------------------------------
# 這是核心構建步驟,負責:
# 1. 使用 ./docker/Dockerfile 構建鏡像
# 2. 將構建好的鏡像推送到 ACR
#
# 配置說明:
# - context: 構建上下文目錄(整個倉庫根目錄)
# - file: Dockerfile 的路徑
# - push: true 表示構建完成後自動推送到 registry
# - platforms: linux/arm64 表示構建 ARM64 架構的鏡像(適用於 Apple Silicon 或 ARM 服務器)
# - tags: 鏡像標籤,使用 commit SHA 作為版本號,確保每次構建都有唯一標識
#
# 緩存策略:
# - cache-from: 從 registry 拉取之前的構建緩存,加速構建過程
# - cache-to: 將構建緩存推送到 registry,供下次構建使用
# - mode=max: 使用最大緩存模式,保存所有構建層
#
# 鏡像標籤格式:stktrade.azurecr.io/stk-jixun-model:<commit-sha>
# 例如:stktrade.azurecr.io/stk-jixun-model:abc123def456
# ----------------------------------------------------------------------
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ github.workspace }}
file: ./Dockerfile
push: true
platforms: linux/amd64
tags: ${{ vars.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=registry,ref=${{ vars.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ vars.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
# ----------------------------------------------------------------------
# Step 6: 生成鏡像構建摘要
# ----------------------------------------------------------------------
# 在 GitHub Actions 的 Summary 頁面生成一個美觀的 Markdown 報告,
# 包含:
# - 鏡像的完整信息(registry、名稱、標籤)
# - 如何手動拉取和運行鏡像的說明
# - 本次構建的元數據(commit SHA、workflow run ID)
#
# 這個摘要對於:
# - 快速查看構建結果
# - 手動測試特定版本的鏡像
# - 問題排查和版本追蹤
# 非常有用
# ----------------------------------------------------------------------
- name: Image Pull Summary
run: |
DOCKERHUB_NAME="${{ vars.DOCKERHUB_USERNAME }}"
IMAGE_NAME="${{ env.IMAGE_NAME }}"
IMAGE_TAG="${DOCKERHUB_NAME}/${IMAGE_NAME}:${{ github.sha }}"
COMMIT_SHA="${{ github.sha }}"
RUN_ID="${{ github.run_id }}"
echo "## 🐳 Image Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Image Information" >> $GITHUB_STEP_SUMMARY
echo "- **Registry:** docker.io/\`${DOCKERHUB_NAME}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Image Name:** \`${IMAGE_NAME}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Tag:** \`${COMMIT_SHA}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Full Image:** \`${IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### How to Pull This Image" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. **Login to Docker Hub:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker login -u" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "2. **Pull the image:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${DOCKERHUB_NAME}/${IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "3. **Run the container:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker run -d -e \"GOOGLE_API_KEY=你的金鑰\" -p 8000:8000 ${IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "**Commit SHA:** \`${COMMIT_SHA}\` | **Workflow Run:** \`${RUN_ID}\`" >> $GITHUB_STEP_SUMMARY
K8s deployment with Helm
.github/workflows/deploy.yml :
jobs:
# ==========================================================================
# Job 2: 使用 Helm 部署到 Kubernetes 集群
# ==========================================================================
# 此 job 負責:
# 1. 等待 build-and-deploy job 完成(確保鏡像已構建並推送)
# 2. 通過 SSH 連接到 Azure Bastion 主機
# 3. 在 Bastion 主機上執行 Helm 部署命令
# 4. 更新 Kubernetes 集群中的應用程序
#
# 為什麼需要通過 Bastion?
# - 安全考慮:Kubernetes 集群不直接暴露在公網
# - 網絡隔離:只有通過 Bastion 才能訪問集群
# - 權限控制:Bastion 作為跳板機,集中管理訪問權限
#
# 部署流程:
# GitHub Actions → SSH to Bastion → Execute Helm Upgrade → K8s Cluster Updated
# ==========================================================================
helm-deploy:
# 確保在 build-and-push job 成功完成後才執行
needs: build-and-push
# 使用可重用的 Helm 部署 workflow
# 這個 workflow 定義在 ./.github/workflows/helm-deploy-reusable.yml
# 採用可重用 workflow 的好處:
# - 代碼復用:多個項目可以共享相同的部署邏輯
# - 易於維護:部署邏輯集中管理,修改一處即可影響所有使用它的 workflow
# - 標準化:確保所有項目的部署流程一致
uses: ./.github/workflows/helm-deploy-reusable.yml
# ========================================================================
# 【輸入參數】
# ========================================================================
# 這些參數會傳遞給可重用 workflow,用於配置部署行為
#
# - repo_path: 在 Bastion 主機上的倉庫路徑(用於拉取最新代碼或配置)
# - helm_release: Helm release 名稱,用於標識和管理部署的應用
# - helm_namespace: Kubernetes namespace,用於隔離不同環境的資源
# (stktrade-prod 表示生產環境)
# - helm_chart_path: Helm chart 的本地路徑(在 Bastion 主機上)
# - helm_values_file: Helm values 文件路徑,包含部署配置(如資源限制、環境變數等)
# - kubeconfig_path: Kubernetes 配置文件路徑,用於認證和連接到集群
# - helm_set_values: 動態設置的 Helm values
# image.tag=${{ github.sha }} 表示使用本次構建的鏡像版本(commit SHA)
# 這確保部署的是剛剛構建好的鏡像
# ========================================================================
with:
repo_path: /home/alang/gemini-ocr-fastapi
helm_release: gemini-ocr
helm_namespace: my-devops-prod
helm_chart_path: ~/gemini-ocr-fastapi/k8s/chart
helm_values_file: ~/gemini-ocr-fastapi/k8s/chart/values.yaml
kubeconfig_path: ~/my.kubeconfig
helm_set_values: image.tag=${{ github.sha }}
# ========================================================================
# 【SSH 認證信息】
# ========================================================================
# 這些 secrets 存儲在 GitHub Secrets 中,用於 SSH 連接到 Bastion 主機
#
# - SSH_PRIVATE_KEY: SSH 私鑰,用於身份驗證
# - SSH_HOST: Bastion 主機的 IP 地址或域名
# - SSH_USER: SSH 登錄用戶名
#
# 安全提示:
# - 所有敏感信息都存儲在 GitHub Secrets 中,不會暴露在代碼中
# ========================================================================
secrets:
SSH_PRIVATE_KEY: ${{ secrets.MY_BASTION_KEY }}
SSH_HOST: ${{ secrets.MY_BASTION_HOST }}
SSH_USER: ${{ secrets.MY_BASTION_USERNAME }}
.github/workflows/helm-deploy-reusable.yml :