fix(cd): target k3s control plane for deploy
This commit is contained in:
@@ -42,6 +42,15 @@ env:
|
||||
OTEL_SERVICE_NAME: awoooi-cd
|
||||
OTEL_RESOURCE_ATTRIBUTES: service.version=${{ github.sha }},deployment.environment=production
|
||||
CI_IMAGE: 192.168.0.110:5000/awoooi/ci-runner:act-22.04
|
||||
# CD SSH still lands on 121 because that host has the deploy sudo path.
|
||||
# Its kubeconfig points to 127.0.0.1, so the deploy scripts rewrite a temp
|
||||
# kubeconfig to the 120 control-plane API server before running kubectl.
|
||||
K8S_SSH_HOST: 192.168.0.121
|
||||
K8S_API_SERVER: https://192.168.0.120:6443
|
||||
# NodePort is currently reachable on 121; keep health probes separate from
|
||||
# the kubectl control-plane host.
|
||||
API_HEALTH_URL: http://192.168.0.121:32334/api/v1/health
|
||||
ALERT_CHAIN_API_URL: http://192.168.0.121:32334
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
@@ -406,13 +415,14 @@ jobs:
|
||||
mkdir -p ~/.ssh
|
||||
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan 192.168.0.121 >> ~/.ssh/known_hosts 2>/dev/null
|
||||
ssh -i ~/.ssh/deploy_key wooo@192.168.0.121 << SECRETS
|
||||
ssh-keyscan "${{ env.K8S_SSH_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
|
||||
ssh -i ~/.ssh/deploy_key "wooo@${{ env.K8S_SSH_HOST }}" << SECRETS
|
||||
set -e
|
||||
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||
K8S_API_SERVER="${{ env.K8S_API_SERVER }}"
|
||||
KUBECTL="sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${K8S_API_SERVER}"
|
||||
|
||||
# 注入 Telegram Secrets (ADR-035 鐵律)
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/OPENCLAW_TG_BOT_TOKEN","value":"'$(echo -n "${TG_BOT_TOKEN}" | base64 -w 0)'"},
|
||||
{"op":"add","path":"/data/OPENCLAW_TG_CHAT_ID","value":"'$(echo -n "${TG_CHAT_ID}" | base64 -w 0)'"}
|
||||
]' || { echo "❌ Telegram Secrets patch 失敗 — ADR-035 鐵律"; exit 1; }
|
||||
@@ -421,7 +431,7 @@ jobs:
|
||||
# 2026-04-01 Claude Code: base64 -w 0 防止長 key 換行破壞 JSON
|
||||
# NVIDIA NIM (免費 tier)
|
||||
if [ -n "${NVIDIA_API_KEY}" ] && [ "${NVIDIA_API_KEY}" != "" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/NVIDIA_API_KEY","value":"'$(echo -n "${NVIDIA_API_KEY}" | base64 -w 0)'"}
|
||||
]' && echo "✅ NVIDIA_API_KEY 已注入" || echo "⚠️ NVIDIA_API_KEY patch 失敗"
|
||||
else
|
||||
@@ -430,7 +440,7 @@ jobs:
|
||||
|
||||
# Gemini (備援)
|
||||
if [ -n "${GEMINI_API_KEY}" ] && [ "${GEMINI_API_KEY}" != "" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/GEMINI_API_KEY","value":"'$(echo -n "${GEMINI_API_KEY}" | base64 -w 0)'"}
|
||||
]' && echo "✅ GEMINI_API_KEY 已注入" || echo "⚠️ GEMINI_API_KEY patch 失敗"
|
||||
else
|
||||
@@ -439,7 +449,7 @@ jobs:
|
||||
|
||||
# 2026-04-01 Claude Code: Langfuse LLMOps keys (補齊 CD 注入,之前只有手動設定)
|
||||
if [ -n "${LANGFUSE_PUBLIC_KEY}" ] && [ -n "${LANGFUSE_SECRET_KEY}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/LANGFUSE_PUBLIC_KEY","value":"'$(echo -n "${LANGFUSE_PUBLIC_KEY}" | base64 -w 0)'"},
|
||||
{"op":"add","path":"/data/LANGFUSE_SECRET_KEY","value":"'$(echo -n "${LANGFUSE_SECRET_KEY}" | base64 -w 0)'"}
|
||||
]' && echo "✅ LANGFUSE keys 已注入" || echo "⚠️ LANGFUSE keys patch 失敗"
|
||||
@@ -449,14 +459,14 @@ jobs:
|
||||
|
||||
# 2026-04-02 Claude Code: Telegram Whitelist (授權簽核用戶 ID)
|
||||
if [ -n "${TG_USER_WHITELIST}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/OPENCLAW_TG_USER_WHITELIST","value":"'$(echo -n "${TG_USER_WHITELIST}" | base64 -w 0)'"}
|
||||
]' && echo "✅ TG_USER_WHITELIST 已注入" || echo "⚠️ TG_USER_WHITELIST patch 失敗"
|
||||
fi
|
||||
|
||||
# Phase O-4.1 2026-04-02: Sentry Auth Token (Wave A.1 ADR-037)
|
||||
if [ -n "${SENTRY_AUTH_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SENTRY_AUTH_TOKEN","value":"'$(echo -n "${SENTRY_AUTH_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SENTRY_AUTH_TOKEN 已注入" || echo "⚠️ SENTRY_AUTH_TOKEN patch 失敗"
|
||||
else
|
||||
@@ -465,7 +475,7 @@ jobs:
|
||||
|
||||
# ADR-059 2026-04-05 Claude Code: Gitea Webhook Secret
|
||||
if [ -n "${GITEA_WEBHOOK_SECRET}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/GITEA_WEBHOOK_SECRET","value":"'$(echo -n "${GITEA_WEBHOOK_SECRET}" | base64 -w 0)'"}
|
||||
]' && echo "✅ GITEA_WEBHOOK_SECRET 已注入" || echo "⚠️ GITEA_WEBHOOK_SECRET patch 失敗"
|
||||
else
|
||||
@@ -474,7 +484,7 @@ jobs:
|
||||
|
||||
# MCP Phase 3: ArgoCD API Token (2026-04-11 Claude Sonnet 4.6)
|
||||
if [ -n "${ARGOCD_API_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/ARGOCD_API_TOKEN","value":"'$(echo -n "${ARGOCD_API_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ ARGOCD_API_TOKEN 已注入" || echo "⚠️ ARGOCD_API_TOKEN patch 失敗"
|
||||
else
|
||||
@@ -489,7 +499,7 @@ jobs:
|
||||
|
||||
# DATABASE_URL — PG 應用連線串(2026-04-18 輪替)
|
||||
if [ -n "${DATABASE_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/DATABASE_URL","value":"'$(echo -n "${DATABASE_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ DATABASE_URL 已注入" || echo "⚠️ DATABASE_URL patch 失敗"
|
||||
else
|
||||
@@ -498,14 +508,14 @@ jobs:
|
||||
|
||||
# MIGRATION_DATABASE_URL — CI migration 用 awoooi_migrator 限權帳號(ADR-090-B)
|
||||
if [ -n "${MIGRATION_DATABASE_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/MIGRATION_DATABASE_URL","value":"'$(echo -n "${MIGRATION_DATABASE_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ MIGRATION_DATABASE_URL 已注入" || echo "⚠️ MIGRATION_DATABASE_URL patch 失敗"
|
||||
fi
|
||||
|
||||
# REDIS_URL — Redis 連線(6380 on 188)
|
||||
if [ -n "${REDIS_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/REDIS_URL","value":"'$(echo -n "${REDIS_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ REDIS_URL 已注入" || echo "⚠️ REDIS_URL patch 失敗"
|
||||
else
|
||||
@@ -514,64 +524,64 @@ jobs:
|
||||
|
||||
# JWT_SECRET / JWT_ALGORITHM — API 認證
|
||||
if [ -n "${JWT_SECRET}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/JWT_SECRET","value":"'$(echo -n "${JWT_SECRET}" | base64 -w 0)'"}
|
||||
]' && echo "✅ JWT_SECRET 已注入" || echo "⚠️ JWT_SECRET patch 失敗"
|
||||
fi
|
||||
if [ -n "${JWT_ALGORITHM}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/JWT_ALGORITHM","value":"'$(echo -n "${JWT_ALGORITHM}" | base64 -w 0)'"}
|
||||
]' && echo "✅ JWT_ALGORITHM 已注入" || echo "⚠️ JWT_ALGORITHM patch 失敗"
|
||||
fi
|
||||
|
||||
# WEBHOOK_HMAC_SECRET — Alertmanager webhook HMAC 簽章
|
||||
if [ -n "${WEBHOOK_HMAC_SECRET}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/WEBHOOK_HMAC_SECRET","value":"'$(echo -n "${WEBHOOK_HMAC_SECRET}" | base64 -w 0)'"}
|
||||
]' && echo "✅ WEBHOOK_HMAC_SECRET 已注入" || echo "⚠️ WEBHOOK_HMAC_SECRET patch 失敗"
|
||||
fi
|
||||
|
||||
# SENTRY_DSN — Sentry 錯誤追蹤(不是 auth token)
|
||||
if [ -n "${SENTRY_DSN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SENTRY_DSN","value":"'$(echo -n "${SENTRY_DSN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SENTRY_DSN 已注入" || echo "⚠️ SENTRY_DSN patch 失敗"
|
||||
fi
|
||||
|
||||
# CLAUDE_API_KEY — Claude 備援 LLM
|
||||
if [ -n "${CLAUDE_API_KEY}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/CLAUDE_API_KEY","value":"'$(echo -n "${CLAUDE_API_KEY}" | base64 -w 0)'"}
|
||||
]' && echo "✅ CLAUDE_API_KEY 已注入" || echo "⚠️ CLAUDE_API_KEY patch 失敗"
|
||||
fi
|
||||
|
||||
# GITEA_API_TOKEN — Gitea API Token(從 AWOOOI_GITEA_API_TOKEN 映射)
|
||||
if [ -n "${GITEA_API_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/GITEA_API_TOKEN","value":"'$(echo -n "${GITEA_API_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ GITEA_API_TOKEN 已注入" || echo "⚠️ GITEA_API_TOKEN patch 失敗"
|
||||
fi
|
||||
|
||||
# NEMOTRON_BOT_TOKEN / OPENCLAW_BOT_TOKEN — 多 Bot 架構
|
||||
if [ -n "${NEMOTRON_BOT_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/NEMOTRON_BOT_TOKEN","value":"'$(echo -n "${NEMOTRON_BOT_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ NEMOTRON_BOT_TOKEN 已注入" || echo "⚠️ NEMOTRON_BOT_TOKEN patch 失敗"
|
||||
fi
|
||||
if [ -n "${OPENCLAW_BOT_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/OPENCLAW_BOT_TOKEN","value":"'$(echo -n "${OPENCLAW_BOT_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ OPENCLAW_BOT_TOKEN 已注入" || echo "⚠️ OPENCLAW_BOT_TOKEN patch 失敗"
|
||||
fi
|
||||
|
||||
# SMTP_HOST / SRE_GROUP_CHAT_ID
|
||||
if [ -n "${SMTP_HOST}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SMTP_HOST","value":"'$(echo -n "${SMTP_HOST}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SMTP_HOST 已注入" || echo "⚠️ SMTP_HOST patch 失敗"
|
||||
fi
|
||||
if [ -n "${SRE_GROUP_CHAT_ID}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
$KUBECTL patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SRE_GROUP_CHAT_ID","value":"'$(echo -n "${SRE_GROUP_CHAT_ID}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SRE_GROUP_CHAT_ID 已注入" || echo "⚠️ SRE_GROUP_CHAT_ID patch 失敗"
|
||||
fi
|
||||
@@ -597,13 +607,13 @@ jobs:
|
||||
fi
|
||||
done
|
||||
if [ "$PRESENT" -eq "$EXPECTED_HOSTS" ]; then
|
||||
sudo kubectl create secret generic awoooi-repair-known-hosts \
|
||||
$KUBECTL create secret generic awoooi-repair-known-hosts \
|
||||
-n awoooi-prod \
|
||||
--from-file=known_hosts=/tmp/known_hosts_repair \
|
||||
--dry-run=client -o yaml | sudo kubectl apply -f - \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f - \
|
||||
&& echo "✅ awoooi-repair-known-hosts Secret 已建立/更新" \
|
||||
|| echo "⚠️ awoooi-repair-known-hosts Secret 建立失敗 (非致命)"
|
||||
sudo kubectl patch secret ssh-mcp-key -n awoooi-prod --type=merge \
|
||||
$KUBECTL patch secret ssh-mcp-key -n awoooi-prod --type=merge \
|
||||
-p='{"data":{"known_hosts":"'$(base64 -w 0 /tmp/known_hosts_repair)'"}}' \
|
||||
&& echo "✅ ssh-mcp-key known_hosts 已更新(4 台主機完整)" \
|
||||
|| echo "⚠️ ssh-mcp-key known_hosts 更新失敗 (非致命)"
|
||||
@@ -634,20 +644,20 @@ jobs:
|
||||
mkdir -p ~/.ssh
|
||||
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan 192.168.0.121 >> ~/.ssh/known_hosts 2>/dev/null
|
||||
ssh-keyscan "${{ env.K8S_SSH_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
|
||||
|
||||
IMAGE_TAG="${{ github.sha }}"
|
||||
HARBOR=192.168.0.110:5000
|
||||
|
||||
# ─── Step 1: Apply ConfigMap + ServiceRegistry (ArgoCD 管的是 Deployment,ConfigMap 仍直接 apply) ───
|
||||
cat k8s/awoooi-prod/04-configmap.yaml | \
|
||||
ssh -i ~/.ssh/deploy_key wooo@192.168.0.121 \
|
||||
"export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && sudo kubectl apply -f -"
|
||||
ssh -i ~/.ssh/deploy_key "wooo@${{ env.K8S_SSH_HOST }}" \
|
||||
"KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL apply -f -"
|
||||
echo "✅ ConfigMap 已更新"
|
||||
|
||||
cat k8s/awoooi-prod/15-service-registry-configmap.yaml | \
|
||||
ssh -i ~/.ssh/deploy_key wooo@192.168.0.121 \
|
||||
"export KUBECONFIG=/etc/rancher/k3s/k3s.yaml && sudo kubectl apply -f -"
|
||||
ssh -i ~/.ssh/deploy_key "wooo@${{ env.K8S_SSH_HOST }}" \
|
||||
"KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL apply -f -"
|
||||
echo "✅ Service Registry ConfigMap 已更新"
|
||||
|
||||
# ─── Step 2: 更新 kustomization.yaml image tag ───
|
||||
@@ -688,23 +698,24 @@ jobs:
|
||||
}
|
||||
|
||||
# ─── Step 4: 等待 ArgoCD sync + rollout ───
|
||||
ssh -i ~/.ssh/deploy_key wooo@192.168.0.121 \
|
||||
ssh -i ~/.ssh/deploy_key "wooo@${{ env.K8S_SSH_HOST }}" \
|
||||
"EXPECTED_REVISION='${DEPLOY_REVISION}' bash -s" << 'ARGOCD_WAIT'
|
||||
set -e
|
||||
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||
K8S_API_SERVER="${{ env.K8S_API_SERVER }}"
|
||||
KUBECTL="sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${K8S_API_SERVER}"
|
||||
|
||||
# 等待 ArgoCD Application Synced(最多 180s)。只看
|
||||
# Synced/Healthy 可能誤判成上一個 revision 已同步,因此有
|
||||
# deploy commit 時必須同時確認 status.sync.revision。
|
||||
echo "⏳ 等待 ArgoCD sync..."
|
||||
sudo kubectl annotate application awoooi-prod -n argocd \
|
||||
$KUBECTL annotate application awoooi-prod -n argocd \
|
||||
argocd.argoproj.io/refresh=hard --overwrite >/dev/null 2>&1 || true
|
||||
for i in $(seq 1 36); do
|
||||
SYNC=$(sudo kubectl get application awoooi-prod -n argocd \
|
||||
SYNC=$($KUBECTL get application awoooi-prod -n argocd \
|
||||
-o jsonpath='{.status.sync.status}' 2>/dev/null || echo "Unknown")
|
||||
HEALTH=$(sudo kubectl get application awoooi-prod -n argocd \
|
||||
HEALTH=$($KUBECTL get application awoooi-prod -n argocd \
|
||||
-o jsonpath='{.status.health.status}' 2>/dev/null || echo "Unknown")
|
||||
REVISION=$(sudo kubectl get application awoooi-prod -n argocd \
|
||||
REVISION=$($KUBECTL get application awoooi-prod -n argocd \
|
||||
-o jsonpath='{.status.sync.revision}' 2>/dev/null || echo "Unknown")
|
||||
SHORT_REVISION=$(echo "$REVISION" | cut -c1-8)
|
||||
SHORT_EXPECTED=$(echo "$EXPECTED_REVISION" | cut -c1-8)
|
||||
@@ -723,15 +734,15 @@ jobs:
|
||||
done
|
||||
|
||||
# 確認 rollout 完成
|
||||
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
|
||||
$KUBECTL rollout status deployment/awoooi-api -n awoooi-prod --timeout=120s
|
||||
$KUBECTL rollout status deployment/awoooi-web -n awoooi-prod --timeout=120s
|
||||
$KUBECTL rollout status deployment/awoooi-worker -n awoooi-prod --timeout=120s
|
||||
echo "✅ 部署完成"
|
||||
|
||||
# Health Check
|
||||
HEALTH_PASS=0
|
||||
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")
|
||||
HTTP_CODE=$(curl -s -w "%{http_code}" -o /dev/null --connect-timeout 10 "${{ env.API_HEALTH_URL }}")
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
echo "✅ API 健康檢查通過"
|
||||
HEALTH_PASS=1
|
||||
@@ -814,7 +825,8 @@ jobs:
|
||||
- name: Alert Chain Smoke Test
|
||||
id: alert_chain_smoke
|
||||
run: |
|
||||
# 2026-04-05 Claude Code: 使用真實 API 地址(192.168.0.121:32334 NodePort)
|
||||
# 2026-05-05 Codex: kubectl 走 control-plane 120,但 NodePort health
|
||||
# 目前由 121 對外可達;兩者分開設定,避免 role drift 互相拖垮。
|
||||
# Host runner launches the CI image explicitly to avoid act RWLayer=nil.
|
||||
if docker run --rm \
|
||||
--name "awoooi-cd-${GITHUB_RUN_ID:-manual}-${GITHUB_RUN_ATTEMPT:-1}-alert-smoke" \
|
||||
@@ -824,7 +836,7 @@ jobs:
|
||||
-v awoooi-api-venv-cache:/opt/api-venv \
|
||||
-w /workspace \
|
||||
"${{ env.CI_IMAGE }}" \
|
||||
bash -lc 'source /opt/api-venv/bin/activate && python3 scripts/alert_chain_smoke_test.py --api-url http://192.168.0.121:32334 --json | tee /tmp/alert_chain_result.json'; then
|
||||
bash -lc 'source /opt/api-venv/bin/activate && python3 scripts/alert_chain_smoke_test.py --api-url ${{ env.ALERT_CHAIN_API_URL }} --json | tee /tmp/alert_chain_result.json'; then
|
||||
echo "alert_chain_status=pass" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "alert_chain_status=fail" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -21,10 +21,11 @@ data:
|
||||
# GCP-A(via 110:11435) → GCP-B(via 110:11436) → Local(via 110:11437) 統一走 nginx proxy
|
||||
# 110 nginx proxy 轉發:11435→GCP-A, 11436→GCP-B, 11437→192.168.0.111:11434
|
||||
# K8s pods 不可直連 GCP:11434(NetworkPolicy 外網 egress 只開 443)
|
||||
# 2026-05-05 ogt C2 修復:Local fallback 改走 110:11437 統一 nginx proxy,增強可觀測性
|
||||
# 2026-05-05 Codex: 110:11437 proxy 從 pod 內 connection refused,暫回直連 111;
|
||||
# 保持告警成本路由為 GCP-A → GCP-B → 111 → Gemini backup。
|
||||
OLLAMA_URL: "http://192.168.0.110:11435"
|
||||
OLLAMA_SECONDARY_URL: "http://192.168.0.110:11436"
|
||||
OLLAMA_FALLBACK_URL: "http://192.168.0.110:11437"
|
||||
OLLAMA_FALLBACK_URL: "http://192.168.0.111:11434"
|
||||
OPENCLAW_URL: "http://192.168.0.188:8088"
|
||||
KALI_SCANNER_URL: "http://192.168.0.112:8080"
|
||||
SIGNOZ_URL: "http://192.168.0.188:3301"
|
||||
|
||||
Reference in New Issue
Block a user