Files
awoooi/docs/runbooks/HOST-ROLE-LOAD-BALANCING-ASSESSMENT.md

15 KiB
Raw Permalink Blame History

AWOOOI 主機角色與負載平衡評估

Version: v1.1 Last updated: 2026-06-13 Asia/Taipei Scope: 110 / 120 / 121 / 188112 是 Kali不納入本輪服務搬遷。


1. 結論

120 / 121 目前是 K3s control-plane AA不是傳統一主一從 AS。

但這只代表 Kubernetes 控制面雙節點可用,不代表業務 workload 已經 AA。2026-06-13 00:13 live check 顯示:

項目 120 mon 121 mon1 判讀
K3s unit k3s activek3s-agent inactive k3s activek3s-agent inactive 兩台都是 server / control-plane
Kubernetes role control-plane control-plane 控制面 AA
Taint / schedulable 無 taint、Unschedulable=false 無 taint、Unschedulable=false 120 可以排程
CPU / memory CPU 約 2%、Memory 約 8% CPU 約 3%、Memory 約 20% 兩台都有餘裕121 較高
Pod 實際落點 awoooi-api 2 顆、awoooi-web 1 顆、awoooi-worker 1 顆 awoooi-web 1 顆、auto-repair canary、部分 CronJob 歷史 Pod API 仍集中在 120Web 已分散

專業判定:

  • 控制面AA。
  • 業務 workloadWeb 已分散,但 API 兩個 replica 都在 120不算完整 workload AA。
  • 資料層:不可直接視為 AA若仍依賴 188 PostgreSQL 或 local-path PVC120/121 只是承載層,不是資料高可用層。
  • 下一步AWOOOI API / Web / Worker topology spread 已進 Gitea main 並由 ArgoCD 套用;後續才能規劃把 110 / 188 無狀態服務搬進 K3s不先搬核心資料庫。

2. 現況負載與角色

2.1 110

110 是目前最混合、最需要拆角色的主機。

類別 Live evidence 負載/風險
Public gateway / edge 80/443、多個 public route upstream 改 Nginx / firewall 影響面最大
Registry / image supply Harbor 5000、registry / portal / jobservice / db / redis K3s image pull 依賴它,不適合先搬
Source / CI Gitea 3001、runner / build 相關目錄 build / dump 期間會推高 CPU
Observability / incident tools Prometheus、Alertmanager、Sentry / Snuba / Kafka / ClickHouse 容器多、啟動順序複雜
Product services StockPlatform v2、agent-bounty、Tsenyang、VTuber、Bitan 等 多數可逐步轉 K3s但資料層需先分離
Backup control /backup/scripts/*、每日備份與 offsite sync 本輪恢復完成前不可搬

2026-06-12 15:19 live check110 RAM 62Gi、root disk 89%、load 約 2.79 / 3.01 / 3.25;正在跑 Gitea dump 時 top CPU 包含 gitea dump、ClickHouse、Docker、Kafka。

2026-06-13 00:14 live check110 systemctl is-system-running=running、failed units 0、load 約 4.45 / 3.28 / 2.89、Swap 166Mi/7.8GiBtop CPU 主要是 Gitea、ClickHouse、Kafka、Docker 與一個 prisma db push 工作。判讀110 不在服務故障狀態,但仍是高混合負載主機,第一批應先移走無狀態 app 層與 build/preview 類工作。

2.2 188

188 是資料、AI、觀測與自動化中心。

類別 Live evidence 負載/風險
Data layer PostgreSQL 5432、Redis 6379、momo DB、product DBs 多服務依賴,不可直接熱搬
momo momo-schedulermomo-pro-system、Telegram bot 有資料一致性與匯入流程風險
AI / workflow OpenClaw、LiteLLM、Open WebUI、n8n 可拆,但需 provider route / secrets / queue 邊界
Observability SignOz、ClickHouse、Zookeeper、Grafana、Prometheus、Alertmanager、Loki stateful 且啟動重,不適合第一批
Product services VibeWork、Tsenyang、agent-bounty 等 可按 stateless / stateful 拆分

2026-06-12 15:19 live check188 RAM 62Gi、root disk 52%、Swap 約 2Gi/8Gitop CPU 包含 momo-scheduler、Next.js、ClickHouse。

2026-06-13 00:14 live check188 systemctl is-system-running=degradedfailed units 是 certbot.servicesnap.certbot.renew.servicecold-start 仍確認 PostgreSQL、Redis、momo、SignOz、Docker services 綠。判讀:這是 TLS 自動續期治理債,不是本輪 K3s workload balancing 的業務服務阻斷。

2.3 120 / 121

120 / 121 是 K3s control-plane pair目前最適合承接標準化容器 workload。

類別 目前狀態 判讀
K3s control-plane 120 / 121 都 Ready control-plane 控制面 AA
Workload placement API / Web 已分散在 120 / 121Worker 單副本在 121 AWOOOI core workload 已完成第一階段均衡
記憶體餘裕 120 約 29Gi available121 約 27Gi available 有承接空間
Storage root 各約 490G本輪 120 剛做 root fsck 後恢復 不應立刻承接核心 stateful
Network VIP 192.168.0.125 / NodePort 已用於 AWOOOI 適合承接 ingress 後方 app

3. 可以搬、暫緩搬、禁止直接搬

3.1 第一批:可優先搬到 K3s 的服務

條件:無狀態、可重新 build、已有容器 image、資料庫可先留在原 host、health endpoint 清楚。

優先序 候選 來源主機 建議策略 原因
P1-A Tsenyang website 110 / 188 都有部署痕跡 先做單一 canonical deployment再進 K3s 靜態/Next 類服務,資料風險低
P1-A VTuber web/admin/api 110 app 先搬DB 留 110備份通過後再評估 DB 可降低 110 Docker container 數
P1-A Bitan app / PostgREST edge 110 app edge 先搬PostgreSQL 暫留 110 public route 可用 K3s NodePort / ingress
P1-B StockPlatform web/admin/api/edge 110 app 層先搬Postgres/Redis 暫留 110 目前 110 服務多,拆 app 有效
P1-B agent-bounty web / worker 110 / 188 先統一來源與 port再搬 appDB/Redis 暫留 兩台都有部署痕跡,需先消除重複角色
P1-B 輕量內部工具 / preview 188 容器標準化後搬 對核心資料面影響小

第一批完成標準:

  • 每個 deployment 有 requests / limits
  • replicas >= 2 的服務必須有 pod anti-affinity 或 topology spread。
  • 120 / 121 上 Pod 落點 max skew <= 1。
  • public route、internal VIP、health endpoint、Alertmanager visibility、備份矩陣都通過。

3.2 第二批:可以規劃,但不能在恢復期直接搬

候選 來源主機 需要先完成
Product-specific PostgreSQL / Redis 110 / 188 backup / restore drill、RPO/RTO、PVC 策略、回滾路徑
Langfuse / analytics 類服務 110 DB / object storage / secret route 梳理
n8n / workflow 188 workflow export、credential escrow evidence、callback URL 切換
Open WebUI / AI 工具 188 model provider route、volume backup、外部 endpoint fallback
Docker registry mirror / cache 110 / 188 image retention、auth、K3s pull secret、Harbor 分工

3.3 不建議直接搬的核心

對象 原因 正確路徑
Harbor K3s image supply 依賴它;搬壞會反過來讓 K3s deploy 失敗 先做 replica / mirror / restore 演練
Gitea source-of-truth / CI 影響大dump / runner / SSH / webhook 邊界多 先獨立備份與 restore drill
Sentry / Snuba / Kafka / ClickHouse stateful、容器多、啟動順序敏感 先拆 consumer load再評估專用 observability host
SignOz ClickHouse / Zookeeper stateful 且重 IO 需要獨立 storage 與 retention plan
AWOOOI / momo 主 PostgreSQL 多系統依賴且資料一致性要求高 先建立 replica / tested restore不做熱搬
/backup 控制面 本輪恢復與 DR 證據中心 等 DR scorecard complete 後另開遷移案

4. 新資料庫能不能放 120 / 121

可以,但要分等級。

等級 是否可放 條件
Dev / staging / demo DB 可以 明確標示非 production每日備份可接受重建
新產品的低風險 production DB 可以試點 必須先完成 backup、restore drill、PVC 保留策略、監控與 offsite sync
核心 production DB 暫不建議 目前 120/121 只有兩節點 control-plane若使用 local-path PVCPod 可重建不代表資料可 failover
高可用 production DB 需要另案 需要 PostgreSQL operator、replica、storage replication 或外部 DB HA不是單純 kubectl apply postgres

判定原則:

Kubernetes 可以重排 Pod不等於資料會跟著安全重排。
沒有 restore drill 的 DB不算可遷移完成。
沒有 storage replication 的 stateful workload不算 AA。

5. 120 / 121 Workload 均衡修正

目前不是 taint 或 cordon 問題,因為 120 / 121 都 schedulable。主要原因是 120 長時間不可用後,既有 Running Pod 不會自動搬回來live deployment 也尚未帶 topologySpreadConstraints,所以 scheduler 只有 soft anti-affinity仍可能把同一服務副本放在同一台。

5.1 立即可做的只讀檢查

ssh wooo@192.168.0.120 '
sudo kubectl get nodes -o wide
sudo kubectl get pods -A -o wide
sudo kubectl top nodes
sudo kubectl top pods -A --sort-by=cpu
'

5.2 受控修正順序

  1. 等 P0 備份鏈、offsite verifier、cold-start scorecard 通過。
  2. 在 AWOOOI awoooi-prod API / Web / Worker 補 topologySpreadConstraints
  3. replicas >= 2 的服務使用 topologyKey: kubernetes.io/hostname,目標 120 / 121 分散。
  4. 單副本服務先不強制搬,除非有明確重啟窗口。
  5. 以 rolling restart 或下一次 deploy 觸發重排,不用暴力 delete 全部 Pod。
  6. 觀察 kubectl get pods -A -o wide、public route、Alertmanager、cold-start scorecard。

5.3 2026-06-13 Gitea / ArgoCD Live 狀態

已在 Gitea main commit acaae999 fix(k8s): add prod workload topology spread 補上:

  • k8s/awoooi-prod/05-deployment-web.yaml
  • k8s/awoooi-prod/06-deployment-api.yaml
  • k8s/awoooi-prod/08-deployment-worker.yaml

2026-06-13 12:43 live refresh 發現 ScheduleAnyway 仍可能讓 awoooi-api 兩顆副本合法同落 120cold-start 仍綠,但不能宣稱 API workload balanced。

修正策略改為 maxSkew: 1minDomains: 2topologyKey: kubernetes.io/hostnamewhenUnsatisfiable: DoNotSchedule。120 / 121 都 Ready 時API / Web replicas=2 必須跨節點Worker 單副本仍可跑,未來擴副本時也必須分散。

2026-06-13 13:00 追加判讀:只把 spread 改硬仍不夠。API rollout 時舊 Pod 仍在 120 terminating新 ReplicaSet 兩顆都排到 121scheduler 當下因舊 Pod 尚在而視為不違反 skew舊 Pod 消失後 live API 反而變成 121 集中。因此 API / Web 也必須使用 maxSurge: 0maxUnavailable: 1,讓 rollout 先釋出一格再排新 Pod避免新舊 ReplicaSet 交錯造成最終偏斜。

2026-06-13 12:59 live verificationArgoCD revision 60f653a0 syncedAPI / Web 均 ready=2/2strategy maxSurge=0 / maxUnavailable=1spread minDomains=2 / DoNotScheduleawoooi-api pod 分別在 mon / mon1awoooi-web pod 分別在 mon / mon1。完整 cold-start rerun PASS=83 WARN=0 BLOCKED=0

驗證:

  • kubectl kustomize k8s/awoooi-prod 可渲染三個 topologySpreadConstraints
  • git diff --check 通過。
  • ArgoCD awoooi-prod 已同步到 revision acaae99986aee2e1f5630984981ccb0f2b676bb8operation Succeeded
  • Live deployment 的 API / Web / Worker 均需有 topologySpreadConstraints
  • awoooi-api replicas=2120 / 121 各一顆,否則是 SERVICE_OK_PLACEMENT_DRIFT
  • awoooi-web replicas=2120 / 121 各一顆。
  • awoooi-worker replicas=1可在任一節點若 replicas > 1必須跨 120 / 121 分散。
  • Rollout 後冷啟動2026-06-13 00:34 final scorecard PASS=83 WARN=0 BLOCKED=0。00:33 曾因 110 known_hosts 對 120 / 188 過期而短暫 blocked已在備份後刷新 host key trust。

補充rolling update 當下 API 新 Pod 先集中到 121因為舊 Pod 正在 120 Terminating後續以單顆 stateless API Pod 受控重排,最終達到 120 / 121 各一顆。沒有執行全 namespace delete、Docker restart、Nginx reload 或 firewall 變更。

建議的分散目標:

Workload 目標
awoooi-api replicas=2 120 / 121 各一個,whenUnsatisfiable=DoNotSchedule
awoooi-web replicas=2 120 / 121 各一個,whenUnsatisfiable=DoNotSchedule
awoooi-worker replicas=1 可留任一節點;多副本時 whenUnsatisfiable=DoNotSchedule
ArgoCD / Velero / kube-system 單副本 不急搬;先保持穩定
DaemonSet 120 / 121 各一個,已符合

6. 遷移階段與完成度

階段 狀態 完成度 說明
A. 角色判定 DONE 100% 120/121 已確認是 K3s control-plane AAworkload 尚未均衡
B. 服務盤點 DONE 100% 110 / 188 主要服務、port、container 類型已盤點
C. 遷移分層 DONE 100% 分為可優先搬、可規劃、禁止直接搬
D. 實際 workload 均衡 LIVE_VERIFIED 100% API / Web hard topology spread 與 no-surge rollout 已進 Gitea main / ArgoCD liveAPI/Web 皆 120 / 121 各一顆
E. 第一批無狀態服務遷移 NOT_STARTED 0% 需另開變更窗口與 rollback plan
F. Stateful 遷移 BLOCKED_BY_DESIGN 0% 需要 storage / backup / restore / HA 設計

目前總結:評估完成 100%AWOOOI core workload 均衡實作 100%;第一批服務遷移實作 0%。下一階段仍只應先搬無狀態 app 層,不搬核心資料服務。


7. 建議優先順序

優先序 工作 目的
P0 完成 120 回復後備份鏈與 cold-start scorecard 先證明平台回到可恢復基線
P1 保持 AWOOOI prod topology spread觀察後續 deploy 是否維持 120 / 121 分散 防止 API/Web 再度單邊集中
P1 建立「第一批無狀態服務」K3s 遷移清單與 rollback plan 安全釋放 110 Docker 壓力
P2 先搬 app 層,不搬 DBDB 仍走既有備份與連線 降低變更風險
P2 對新 DB 建立 backup / restore drill 模板 讓未來新資料庫可安全落 K3s
P3 評估 Harbor / Gitea / Sentry / SignOz 的專用節點或 HA 架構 不把重 stateful 混進恢復期

8. 禁止事項

  • 不在 P0 恢復鏈未完成時搬資料庫。
  • 不用 kubectl delete pod --all 當成重平衡手段。
  • 不把 local-path PVC 的 Pod 重建誤認為資料高可用。
  • 不把 Harbor / Gitea / Sentry / SignOz 直接丟進 120 / 121 來「平均負載」。
  • 不在未補 backup / restore drill 前宣稱新 DB production ready。
  • 不因為 120 / 121 是 control-plane AA就宣稱整體服務 AA。