2026-03-30 ogt: 更安全的方案 - 已在 192.168.0.121 設定 sudoers NOPASSWD - /etc/sudoers.d/kubectl-deploy - 完全移除 SUDO_PASSWORD 環境變數 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
155 lines
6.4 KiB
YAML
155 lines
6.4 KiB
YAML
# =============================================================================
|
||
# AWOOOI CD Pipeline (Gitea Actions - 方案 B)
|
||
# =============================================================================
|
||
# 流程: Build → Push to Harbor → Deploy to K8s
|
||
# 加速措施:
|
||
# 1. Docker Layer Cache → Harbor registry cache
|
||
# 2. 內部 Mirror → 192.168.0.110:5001 (Harbor Proxy Cache for DockerHub)
|
||
# 2026-03-29 Claude Code (ADR-039) - Retry after creating Harbor project
|
||
|
||
name: CD Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
workflow_dispatch:
|
||
|
||
# 2026-03-30 ogt: 佇列模式 - 等待前一個 run 完成,不取消
|
||
concurrency:
|
||
group: cd-deploy-${{ github.ref }}
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
HARBOR: 192.168.0.110:5000
|
||
# Harbor Proxy Cache (指向 DockerHub 的內部 Mirror,避免拉取限額)
|
||
HARBOR_MIRROR: 192.168.0.110:5001
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Notify Pipeline Start
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="🚀 [AWOOOI CI/CD] Pipeline Started by ${{ github.actor }} (Commit: ${{ github.sha }})"
|
||
|
||
|
||
|
||
- name: Login to Harbor
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.HARBOR }}
|
||
username: ${{ secrets.HARBOR_USERNAME }}
|
||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||
|
||
# ── API 鏡像建置(含 Layer Cache 加速)──────────────────────────────
|
||
- name: Build and Push API
|
||
run: |
|
||
docker build -f apps/api/Dockerfile \
|
||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||
--cache-from ${{ env.HARBOR }}/awoooi/api:latest \
|
||
-t ${{ env.HARBOR }}/awoooi/api:${{ github.sha }} \
|
||
-t ${{ env.HARBOR }}/awoooi/api:latest \
|
||
.
|
||
docker push ${{ env.HARBOR }}/awoooi/api:${{ github.sha }}
|
||
docker push ${{ env.HARBOR }}/awoooi/api:latest
|
||
|
||
- name: Notify API Build
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="📦 [AWOOOI CI/CD] API Image Built & Pushed"
|
||
|
||
# ── Web 鏡像建置(含 Layer Cache 加速)──────────────────────────────
|
||
# 2026-03-30 ogt: NEXT_PUBLIC_* 必須用公網域名 (build-time 寫死)
|
||
# 內網 IP 會觸發瀏覽器「存取區域網路」權限對話框
|
||
- name: Build and Push Web
|
||
run: |
|
||
docker build -f apps/web/Dockerfile \
|
||
--build-arg NEXT_PUBLIC_API_URL=https://awoooi.wooo.work \
|
||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||
--cache-from ${{ env.HARBOR }}/awoooi/web:latest \
|
||
-t ${{ env.HARBOR }}/awoooi/web:${{ github.sha }} \
|
||
-t ${{ env.HARBOR }}/awoooi/web:latest \
|
||
.
|
||
docker push ${{ env.HARBOR }}/awoooi/web:${{ github.sha }}
|
||
docker push ${{ env.HARBOR }}/awoooi/web:latest
|
||
|
||
- name: Notify Web Build
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="📦 [AWOOOI CI/CD] Web Image Built & Pushed"
|
||
|
||
- name: Deploy to K8s
|
||
env:
|
||
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
run: |
|
||
mkdir -p ~/.ssh
|
||
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
|
||
chmod 600 ~/.ssh/deploy_key
|
||
ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key wooo@192.168.0.121 << 'DEPLOY'
|
||
set -e
|
||
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||
|
||
# 2026-03-30 ogt: sudoers NOPASSWD 已設定,無需密碼
|
||
sudo kubectl set image deployment/awoooi-api \
|
||
api=192.168.0.110:5000/awoooi/api:${{ github.sha }} \
|
||
-n awoooi-prod
|
||
|
||
sudo kubectl set image deployment/awoooi-web \
|
||
web=192.168.0.110:5000/awoooi/web:${{ github.sha }} \
|
||
-n awoooi-prod
|
||
|
||
sudo kubectl set image deployment/awoooi-worker \
|
||
worker=192.168.0.110:5000/awoooi/api:${{ github.sha }} \
|
||
-n awoooi-prod
|
||
|
||
sudo kubectl rollout status deployment/awoooi-api -n awoooi-prod --timeout=120s
|
||
sudo kubectl rollout status deployment/awoooi-web -n awoooi-prod --timeout=120s
|
||
sudo kubectl rollout status deployment/awoooi-worker -n awoooi-prod --timeout=120s
|
||
echo "✅ 部署完成"
|
||
DEPLOY
|
||
|
||
- name: Notify K8s Deploy
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="🚢 [AWOOOI CI/CD] K8s Deployment Triggered"
|
||
|
||
# ── Health Check ─────────────────────────────────────────────────────
|
||
- name: Health Check
|
||
env:
|
||
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
run: |
|
||
ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key wooo@192.168.0.121 << 'CHECK'
|
||
sleep 10
|
||
for i in 1 2 3; do
|
||
HTTP_CODE=$(curl -s -w "%{http_code}" -o /dev/null --connect-timeout 10 "http://localhost:32334/api/v1/health")
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
echo "✅ API 健康檢查通過"
|
||
exit 0
|
||
fi
|
||
echo "⏳ 嘗試 #$i: HTTP $HTTP_CODE,等待 10s..."
|
||
sleep 10
|
||
done
|
||
echo "❌ API 健康檢查失敗"
|
||
exit 1
|
||
CHECK
|
||
|
||
- name: Notify Health Check Success
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="✅ [AWOOOI CI/CD] Health Check Passed! Pipeline Complete."
|
||
|
||
- name: Notify Pipeline Failure
|
||
if: failure()
|
||
run: |
|
||
curl -fS -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
||
-d text="❌ [AWOOOI CI/CD] Pipeline Failed! Please check Gitea Actions logs."
|