Phase 8 CI/CD 藍圖: - GitHub Actions deploy-prod.yml (沿用 AIOPS 成熟模式) - Signal Worker K8s Deployment - Telegram Notify 閉環 - Bootstrap 自動化腳本 架構鐵律: - Build: 110 金庫 (Harbor + Self-Hosted Runner) - Deploy: 120 K3s Master - 嚴禁 Docker Compose,K8s 唯一合法部署 Co-Authored-By: Claude <noreply@anthropic.com>
215 lines
7.4 KiB
Bash
Executable File
215 lines
7.4 KiB
Bash
Executable File
#!/bin/bash
|
||
# =============================================================================
|
||
# AWOOOI Production Bootstrap Script
|
||
# =============================================================================
|
||
# Phase 8: 全自動化初始腳本
|
||
#
|
||
# 功能:
|
||
# A. 讀取本地 .env 中的機密
|
||
# B. 產出 03-secrets.yaml 並 kubectl apply
|
||
# C. 自動 git add, commit, push
|
||
#
|
||
# 用法:
|
||
# ./scripts/bootstrap_prod.sh
|
||
#
|
||
# 前置條件:
|
||
# - kubectl 已配置 (KUBECONFIG 指向 120 K3s)
|
||
# - .env 檔案已填寫機密
|
||
# =============================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
# 顏色定義
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${BLUE}║ AWOOOI Production Bootstrap Script (Phase 8) ║${NC}"
|
||
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
|
||
# =============================================================================
|
||
# 配置
|
||
# =============================================================================
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||
ENV_FILE="${PROJECT_ROOT}/.env"
|
||
SECRETS_TEMPLATE="${PROJECT_ROOT}/k8s/awoooi-prod/03-secrets.example.yaml"
|
||
SECRETS_OUTPUT="${PROJECT_ROOT}/k8s/awoooi-prod/03-secrets.yaml"
|
||
K8S_NAMESPACE="awoooi-prod"
|
||
|
||
# =============================================================================
|
||
# Step 1: 檢查前置條件
|
||
# =============================================================================
|
||
echo -e "${YELLOW}[1/5] 檢查前置條件...${NC}"
|
||
|
||
# 檢查 .env 檔案
|
||
if [ ! -f "$ENV_FILE" ]; then
|
||
echo -e "${RED}❌ 錯誤: .env 檔案不存在${NC}"
|
||
echo " 請複製 .env.example 並填入機密:"
|
||
echo " cp .env.example .env"
|
||
exit 1
|
||
fi
|
||
echo -e "${GREEN} ✓ .env 檔案存在${NC}"
|
||
|
||
# 檢查 kubectl
|
||
if ! command -v kubectl &> /dev/null; then
|
||
echo -e "${RED}❌ 錯誤: kubectl 未安裝${NC}"
|
||
exit 1
|
||
fi
|
||
echo -e "${GREEN} ✓ kubectl 已安裝${NC}"
|
||
|
||
# 檢查 K8s 連線
|
||
if ! kubectl cluster-info &> /dev/null; then
|
||
echo -e "${RED}❌ 錯誤: 無法連接 K8s 叢集${NC}"
|
||
echo " 請確認 KUBECONFIG 設定正確"
|
||
exit 1
|
||
fi
|
||
echo -e "${GREEN} ✓ K8s 叢集連線正常${NC}"
|
||
|
||
# =============================================================================
|
||
# Step 2: 讀取 .env 並產生 secrets.yaml
|
||
# =============================================================================
|
||
echo ""
|
||
echo -e "${YELLOW}[2/5] 讀取 .env 並產生 K8s Secrets...${NC}"
|
||
|
||
# 載入 .env
|
||
set -a
|
||
source "$ENV_FILE"
|
||
set +a
|
||
|
||
# 檢查必要的環境變數
|
||
REQUIRED_VARS=(
|
||
"DATABASE_URL"
|
||
"REDIS_URL"
|
||
"OPENCLAW_TG_BOT_TOKEN"
|
||
"OPENCLAW_TG_CHAT_ID"
|
||
)
|
||
|
||
for var in "${REQUIRED_VARS[@]}"; do
|
||
if [ -z "${!var:-}" ]; then
|
||
echo -e "${RED}❌ 錯誤: 環境變數 $var 未設定${NC}"
|
||
exit 1
|
||
fi
|
||
done
|
||
echo -e "${GREEN} ✓ 所有必要環境變數已設定${NC}"
|
||
|
||
# 產生 secrets.yaml
|
||
cat > "$SECRETS_OUTPUT" << EOF
|
||
# AWOOOI Production Secrets
|
||
# 自動產生於: $(date -Iseconds)
|
||
# ⚠️ 此檔案包含機密,請勿提交至 Git
|
||
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: awoooi-secrets
|
||
namespace: ${K8S_NAMESPACE}
|
||
type: Opaque
|
||
stringData:
|
||
# 資料庫
|
||
DATABASE_URL: "${DATABASE_URL:-postgresql+asyncpg://awoooi:changeme@192.168.0.188:5432/awoooi_prod}"
|
||
|
||
# Redis
|
||
REDIS_URL: "${REDIS_URL:-redis://192.168.0.188:6380/10}"
|
||
|
||
# AI 服務
|
||
GEMINI_API_KEY: "${GEMINI_API_KEY:-}"
|
||
CLAUDE_API_KEY: "${CLAUDE_API_KEY:-}"
|
||
|
||
# Telegram Gateway
|
||
OPENCLAW_TG_BOT_TOKEN: "${OPENCLAW_TG_BOT_TOKEN}"
|
||
OPENCLAW_TG_CHAT_ID: "${OPENCLAW_TG_CHAT_ID}"
|
||
OPENCLAW_TG_USER_WHITELIST: "${OPENCLAW_TG_USER_WHITELIST:-${OPENCLAW_TG_CHAT_ID}}"
|
||
|
||
# Webhook 安全
|
||
WEBHOOK_HMAC_SECRET: "${WEBHOOK_HMAC_SECRET:-$(openssl rand -hex 32)}"
|
||
|
||
# JWT (未來擴展)
|
||
JWT_SECRET: "${JWT_SECRET:-$(openssl rand -hex 32)}"
|
||
JWT_ALGORITHM: "HS256"
|
||
EOF
|
||
|
||
echo -e "${GREEN} ✓ 已產生 k8s/awoooi-prod/03-secrets.yaml${NC}"
|
||
|
||
# =============================================================================
|
||
# Step 3: 套用 K8s Secrets
|
||
# =============================================================================
|
||
echo ""
|
||
echo -e "${YELLOW}[3/5] 套用 K8s Secrets 至 ${K8S_NAMESPACE}...${NC}"
|
||
|
||
# 確保 namespace 存在
|
||
kubectl create namespace "$K8S_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - 2>/dev/null || true
|
||
|
||
# 套用 secrets
|
||
kubectl apply -f "$SECRETS_OUTPUT" --namespace="$K8S_NAMESPACE"
|
||
echo -e "${GREEN} ✓ K8s Secrets 已套用${NC}"
|
||
|
||
# 驗證
|
||
echo ""
|
||
echo -e "${BLUE} 驗證 Secrets:${NC}"
|
||
kubectl get secret awoooi-secrets -n "$K8S_NAMESPACE" -o jsonpath='{.metadata.name}' && echo " exists"
|
||
|
||
# =============================================================================
|
||
# Step 4: 清理敏感檔案 (不提交到 Git)
|
||
# =============================================================================
|
||
echo ""
|
||
echo -e "${YELLOW}[4/5] 清理敏感檔案...${NC}"
|
||
|
||
# 確保 secrets.yaml 在 .gitignore
|
||
if ! grep -q "03-secrets.yaml" "${PROJECT_ROOT}/.gitignore" 2>/dev/null; then
|
||
echo "k8s/awoooi-prod/03-secrets.yaml" >> "${PROJECT_ROOT}/.gitignore"
|
||
echo -e "${GREEN} ✓ 已將 03-secrets.yaml 加入 .gitignore${NC}"
|
||
fi
|
||
|
||
# 刪除敏感檔案
|
||
rm -f "$SECRETS_OUTPUT"
|
||
echo -e "${GREEN} ✓ 已刪除本地 secrets.yaml (僅保留在 K8s)${NC}"
|
||
|
||
# =============================================================================
|
||
# Step 5: Git Commit & Push
|
||
# =============================================================================
|
||
echo ""
|
||
echo -e "${YELLOW}[5/5] Git Commit & Push...${NC}"
|
||
|
||
cd "$PROJECT_ROOT"
|
||
|
||
# 檢查是否有變更
|
||
if git diff --quiet && git diff --cached --quiet; then
|
||
echo -e "${BLUE} ℹ 沒有變更需要提交${NC}"
|
||
else
|
||
git add .
|
||
git commit -m "chore: Phase 8 CI/CD bootstrap
|
||
|
||
- Add deploy-prod.yml GitHub Actions workflow
|
||
- Add Signal Worker K8s deployment
|
||
- Update Harbor image paths
|
||
- Configure Telegram notification
|
||
|
||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||
|
||
echo -e "${GREEN} ✓ Git commit 完成${NC}"
|
||
|
||
# Push
|
||
git push origin main
|
||
echo -e "${GREEN} ✓ Git push 完成${NC}"
|
||
fi
|
||
|
||
# =============================================================================
|
||
# 完成
|
||
# =============================================================================
|
||
echo ""
|
||
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${GREEN}║ Bootstrap 完成! ║${NC}"
|
||
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
echo -e "下一步:"
|
||
echo -e " 1. 確認 110 主機 GitHub Runner 已啟動"
|
||
echo -e " 2. 前往 GitHub Actions 查看部署狀態"
|
||
echo -e " 3. 監控 Telegram 接收部署通知"
|
||
echo ""
|
||
echo -e "${BLUE}🔗 GitHub Actions: https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/actions${NC}"
|