Project

General

Profile

CR #201 » SAD-006_部署架構與可觀測性.md

內容更新:內部稱謂去識別化(2026-10-18) - Redmine Admin, 10/18/2026 05:32 AM

 

SAD-006 部署架構與可觀測性

項目 內容
文件編號 SAD-006
版本 1.3
狀態 已核定
撰寫者 SA / SRE
審查者 TL / SEC
對應需求 SYS-2.9、SYS-2.10、SYS-2.11、B.1 基礎設施、B.3 雲原生原則、POC-17

1. 雲原生原則落實

原則 落實方式
容器化 所有服務以容器映像交付,映像不可變
宣告式組態 以 manifest 宣告期望狀態,由編排器收斂
組態外部化 組態由環境變數或組態中心注入,不打包進映像
無狀態服務 服務不保存本機狀態,狀態存於資料庫或快取
健康檢查 每服務提供 liveness 與 readiness 端點
優雅關閉 收到終止訊號後停止接收新請求並完成進行中請求
可拋棄 任何實例可隨時被替換而不影響服務
水平擴充 以增加實例數擴充,非加大單機
可觀測 內建日誌、指標、追蹤
自動化 建置、測試、部署、回復皆自動化

2. 環境規劃

環境 用途 資料 規模
DEV 開發自測 合成測試資料 最小
SIT 整合測試 合成測試資料(含全流程) 1/4 生產
UAT 使用者驗收 去識別化之生產資料 1/2 生產
PERF 效能測試 合成測試資料(生產量級) 同生產
PROD 生產 真實資料 依容量規劃

2.1 環境隔離

面向 要求
網路 各環境獨立 VPC/命名空間,禁止跨環境連線
資料庫 各環境獨立實例
憑證 各環境獨立憑證與金鑰
組態 各環境獨立組態,不得共用生產憑證
外部系統 非生產環境一律指向沙箱,禁止連生產

3. 部署單元與編排

flowchart TD
  subgraph CLUSTER["Kubernetes 叢集(Active-Active 雙叢集)"]
    subgraph NS1["命名空間:edge"]
      IGW["Ingress / API 閘道"]
      BFFP["BFF"]
    end
    subgraph NS2["命名空間:domain"]
      D1["authorization ×N"]
      D2["limit ×N"]
      D3["posting ×N"]
      D4["其他領域服務 ×N"]
    end
    subgraph NS3["命名空間:support"]
      S1["statement / clearing / 批次"]
    end
    subgraph NS4["命名空間:platform"]
      CFG["組態中心"]
      OBS2["可觀測性收集器"]
      SEC2["密鑰管理"]
    end
  end
  subgraph DATA2["資料層"]
    ORA1["Oracle Primary<br/>權威 OLTP:CC_SERVICE 各 schema + CC_PLT"]
    ORA2["Oracle Standby<br/>Data Guard"]
    PGP["PostgreSQL Primary<br/>proj / evt / rpt"]
    PGR["PostgreSQL Replica ×N"]
    RDS["Redis Cluster"]
    KFK2["Kafka Cluster"]
  end
  IGW --> BFFP
  BFFP --> D1
  BFFP --> D2
  D1 --> ORA1
  D1 --> RDS
  D2 --> ORA1
  D3 --> ORA1
  ORA1 --> ORA2
  D1 --> PGP
  D1 --> KFK2
  PGP --> PGR
  S1 --> ORA1
  S1 --> PGR
  OBS2 --> KFK2

v1.1 變更:資料層原僅列 PostgreSQL,依客戶指定補入 Oracle 為權威 OLTP
(Primary + Data Guard Standby);PostgreSQL 轉為承擔 CQRS 讀模型、事件流存檔與報表。
詳細分工與 schema 落點見 SAD-003 §3 與 CSP-006 §2.4。

3.1 資源配置(單一服務之 Pod 規格基準)

服務類型 CPU 請求/上限 記憶體請求/上限 副本數(生產)
閘道 / BFF 1 / 2 核 1 / 2 GiB 4
授權服務 2 / 4 核 2 / 4 GiB 6
額度服務 1 / 2 核 1 / 2 GiB 4
帳務服務 2 / 4 核 2 / 4 GiB 4
繳款服務 1 / 2 核 1 / 2 GiB 3
其他領域服務 1 / 2 核 1 / 2 GiB 2
批次服務 2 / 8 核 4 / 8 GiB 1(可水平擴充)

3.2 物件儲存:正式方案與本地替代方案(2026-10-01 補建,HANDOVER #A-106)

用途:帳單 PDF(SCS-011 §10)/報表輸出(SCS-017 §5.4)/爭議舉證附件。
正式方案:客戶之企業物件儲存(本專案不自建)。
本地替代方案:Garage(S3 相容),見下。

3.2.1 ⚠️ 為何不是 MinIO(查證後之更正)

本案既有文件(CR-017 §8.1、§3.E W-5)原載「本地已有 MinIO(見鐵則)」。
經 2026-10-01 查證,此記載不成立,且 MinIO 已不可用:

查證項 結果
官方下載站 https://dl.min.io/server/minio/release/ HTTP 410 Gone
站方原文 「The open-source MinIO Server, MinIO Client (mc) and MinIO KES projects are archived and no longer maintained. MinIO does not provide product support, security updates, or security advisories for them… These files are no longer served from this site.」
ops/local/docker-compose.yml 實測 從來就沒有 MinIO service(11 個服務中無)
→ 判定 違反本案硬性要求「不要 EOL 的東西」(客戶資安審查必擋)→ 不採用

⚠️ 併更正:CR-017 §8.1 之「MinIO 可落地」與專案鐵則中「物件儲存→MinIO(compose 早已內含)」
皆為誤——compose 從未內含 MinIO。SCS-017 §5.4 已於 2026-09-22 更正過一次,
本次補上選型層之更正。

3.2.2 選型:Garage

項目 值 依據
映像 dxflrs/garage:v2.4.1 Docker Hub 標籤實查:有語意化版本標籤(v2.4.1 最新)且近期仍更新
為何不選 SeaweedFS Docker Hub 僅有 latest/dev/sha,無語意化版本標籤 違反「不鎖 latest」之交付要求
為何不選 LocalStack 為 AWS 模擬器而非物件儲存本體 本案要的是「物件儲存」之替代,非「模擬 AWS」
為何不選 RustFS 最新標籤為 1.0.1-preview.*(尚未 GA) 銀行案不宜採 preview
授權 AGPLv3 本地開發用;正式環境為客戶之企業儲存,不涉及散布

3.2.3 本地部署定義(ops/local/docker-compose.yml)

項目 值
Compose profile storage(與 obs/iam/tools/oracle 並列,不併入 obs——物件儲存非可觀測性)
容器名 cc-garage
S3 API 埠 3900(本案服務所使用)
管理 API 埠 3903(維運查詢;程式不使用)
RPC 3901/靜態網站 3902 刻意不對外映射(單節點下無外部用途,徒增攻擊面)
region cardcore(由 config/garage.toml 之 s3_region 自行決定,非 AWS 固定值)
Bucket cardcore-artifacts(由 GARAGE_DEFAULT_BUCKET 自動建立)
認證 靜態 access key/secret key(GARAGE_ACCESS_KEY/GARAGE_SECRET_KEY,置於 ops/local/.env,不入版控)
持久化 named volume garage-data → /var/lib/garage(metadata_dir/data_dir 皆在其下)
自動初始化 啟動參數 --single-node --default-bucket(Garage v2.3.0 起支援)

⚠️ --default-bucket 之靜默陷阱:GARAGE_DEFAULT_ACCESS_KEY/GARAGE_DEFAULT_SECRET_KEY/
GARAGE_DEFAULT_BUCKET 三者缺一即不自動建立,且 Garage 不報錯(靜默略過)。
故 compose 對前兩者用 ${VAR:?訊息} 強制必填(缺則 compose 直接失敗)。

⚠️ Healthcheck 之陷阱(實測踩過):Garage 映像沒有 /bin/sh(精簡映像)→
不可用 CMD-SHELL 形式:Docker 會 exec /bin/sh 失敗,容器恆顯示 unhealthy,
而服務完全正常(實測 3903/health → 200)——這是健康檢查本身壞掉
(false negative),比沒有 healthcheck 更危險:會讓
depends_on: condition: service_healthy 永遠不滿足。
正解:用 exec 形式 test: ["CMD", "/garage", "status"]——它會實際連 RPC,
是真正的就緒檢查(實測改後 2 個週期內轉 healthy)。

3.2.4 ⚠️ 契約是 S3 API,故本地後端可換

本案程式只依賴 S3 API(s3_region + endpoint + 靜態憑證),
不依賴任何 Garage 專屬特性。因此:

  • 換本地後端(Garage → 其他 S3 相容)= 改 compose + 組態,程式不動
  • 接正式環境(客戶企業物件儲存)= 只換 endpoint 與憑證
  • 此即「埠(port)」之價值——與 KeyProvider/ServiceClientHttpClient 同一思路

3.2.5 ⚠️ 未竟(誠實揭露)

  1. 接線進度:report-service 已接、statement-service 尚未(2026-10-01 更新,HANDOVER #A-107):
    report-service 之報表輸出已改走物件儲存並真機驗證(SCS-017 §8.1)。
    ⚠️ statement-service 之帳單 PDF 仍未接——因其 PDF 產生器本身尚未實作
    (需額外函式庫,SCS-011 §10)→ 不是「忘了接」,是「沒有東西可接」;
    該項另立任務處理。
  2. Java SDK 已 spike 驗證:AWS SDK v2 for Java 2.55.9
    (:s3 與 :bom 於 Maven Central 實查存在;編譯 + 執行期皆通過,見 §3.2.6)。
    ⚠️ 併載兩個 S3 相容性地雷(實測踩到並修除,SCS-017 §8.1.7):
    ① SDK 2.30 起預設校驗+aws-chunked 會被 S3 相容實作拒絕(400 Invalid payload signature);
    ② 校驗設定只能在一處,兩處並設會啟動期失敗。
  3. 本地為單節點、無冗餘(replication_factor = 1)——嚴禁用於 SIT 以上。
  4. config/garage.toml 之 rpc_secret/admin_token 為本地開發專用,
    與 config/keycloak-realm.json 之 dev secret 同一政策(本地單機、非生產憑證);
    SIT/UAT/PROD 一律由密鑰管理提供(§2.1)。
  5. 下載呈現方式尚未實作(SCS-017 §8.1.4):DOWNLOAD_URL 現存物件鍵,
    但「如何下載」(動態 presigned vs 代理端點)待 BEAM PMO 裁定 → 目前前端只顯示鍵值。

3.2.6 驗證範圍(誠實揭露)

已驗證 未驗證
映像 dxflrs/garage:v2.4.1 可拉取 多節點/冗餘行為(本地刻意單節點)
garage status → HEALTHY NODES、v2.4.1 正式環境之企業物件儲存互通性
bucket cardcore-artifacts 自動建立、access key 自動建立 大檔/分段上傳(multipart)行為
S3 API PUT/GET 往返(HANDOVER #A-106) statement-service 之帳單 PDF 接線(產生器未實作)
✅ Java SDK(awssdk:s3:2.55.9)之編譯與執行期相容——report-service 啟動成功、作業 COMPLETED、物件可自 Garage 取回(#A-107) 下載呈現方式(presigned/代理端點)尚未實作

4. 擴縮容

4.1 自動擴容(對應 POC-17)

觸發條件 動作 範圍
CPU 使用率 > 60% 持續 1 分鐘 增加副本 最大 3 倍
記憶體使用率 > 60% 持續 1 分鐘 增加副本 最大 3 倍
請求佇列深度 > 門檻 增加副本 最大 3 倍
CPU 使用率 < 25% 持續 10 分鐘 減少副本 最小基準副本

驗收要求(POC-17)

情境 要求
平常 200 TPS(使用率 20%)
尖峰觸發 使用率達 60% 自動擴容,最大達 2,000 TPS
擴容生效時間 ≤ 3 分鐘
尖峰期間其他交易 P99 劣化 ≤ 20%
授權成功率 100%(不含正常拒絕)

4.2 限流與削峰

層次 機制
閘道 依用戶/端點限流(見 SAD-004 §3.4)
服務 併發上限、佇列上限
外部呼叫 節流控管(依對方容量)
非即時工作 佇列削峰,離峰處理

5. 高可用與備援

5.1 架構

層次 設計
應用 多副本跨節點、跨可用區
資料庫 Primary + Sync Replica + Async Replica
快取 Redis Cluster(多主)
訊息 Kafka 多副本(replication factor ≥ 3)
負載平衡 多層(DNS → LB → Ingress → Service)
機房 Active-Active 雙活

5.2 目標值

指標 目標
系統可用率 ≥ 99.99%
RTO(復原時間目標) ≤ 30 分鐘
RPO(復原點目標) ≤ 5 分鐘
單一節點失效 服務不中斷
單一可用區失效 服務不中斷(降容量)
單一機房失效 切換至另一機房,RTO ≤ 30 分鐘

5.3 故障處理

故障 處理
服務實例失效 編排器自動重建;健康檢查摘除
資料庫 Primary 失效 自動切換至 Sync Replica
Kafka 節點失效 分區 leader 自動轉移
快取失效 回退直查資料庫(降級)
外部系統失效 斷路器 + 降級(如 Stand-in)
發卡主機失效 Stand-in 代授權(見 SAD-004 §4.2)

5.4 消除單點故障(SPOF)

檢查項 要求
應用實例 ≥ 2 副本,且跨節點
資料庫 具備自動切換能力
訊息 replication factor ≥ 3
快取 多主或具備故障轉移
網路 雙線路、雙交換器
DNS 多重解析
憑證 自動輪替,不依賴單一管理員

6. 部署策略(7×24 不中斷)

6.1 藍綠部署

flowchart LR
  LB["負載平衡器"] -->|"100% 流量"| BLUE["藍色環境<br/>v1.0"]
  LB -.->|"0% 流量"| GREEN["綠色環境<br/>v1.1"]
  GREEN --> VER["驗證"]
  VER -->|"通過"| SW["切換流量"]
  SW -->|"100% 流量"| GREEN2["綠色環境<br/>v1.1"]
  SW -.->|"0% 流量"| BLUE2["藍色環境<br/>v1.0(待命)"]
  VER -->|"不通過"| RB["維持藍色"]

6.2 部署能力(對應 POC-12)

能力 要求
視覺化介面部署 提供部署介面,可檢視版本與狀態
部分進版 可僅更新部分服務
部分退版 可僅回復部分服務
一鍵進版 單一操作完成部署
一鍵退版 單一操作完成回復
業務連續性 腳本執行期間不影響業務訪問
封閉驗證 支援部署前之封閉環境驗證
回退時間 ≤ 1 分鐘(分流回退)

6.3 CI/CD 管線

flowchart LR
  A["提交"] --> B["建置"]
  B --> C["靜態分析"]
  C --> D["單元測試"]
  D --> E["映像建置"]
  E --> F["映像掃描"]
  F --> G["部署 DEV"]
  G --> H["整合測試"]
  H --> I["部署 SIT"]
  I --> J["效能與安全測試"]
  J --> K["部署 UAT"]
  K --> L["驗收"]
  L --> M["部署 PROD<br/>藍綠"]

品質閘門

階段 閘門
建置 編譯成功
靜態分析 0 Critical/High
單元測試 全數通過、覆蓋率達標
映像掃描 0 High 漏洞
整合測試 全數通過
效能測試 達標
驗收 通過

目標值:自動構建成功率 ≥ 99%、構建時間 ≤ 10 分鐘、Rollback ≤ 5 分鐘、Zero Downtime 部署成功率 ≥ 99.9%。


7. 可觀測性

7.1 三大支柱

flowchart TD
  subgraph SVC2["服務"]
    LOG["結構化日誌"]
    MET["指標 Metrics"]
    TRC["分散式追蹤 Traces"]
  end
  subgraph COL["收集"]
    C1["日誌收集器"]
    C2["指標收集器"]
    C3["追蹤收集器"]
  end
  subgraph STORE["儲存"]
    S1["日誌儲存"]
    S2["時序資料庫"]
    S3["追蹤儲存"]
  end
  subgraph USE["使用"]
    U1["儀表板"]
    U2["告警"]
    U3["問題追查"]
  end
  LOG --> C1 --> S1 --> U1
  MET --> C2 --> S2 --> U2
  TRC --> C3 --> S3 --> U3
  S1 --> U3
  S2 --> U1

7.2 結構化日誌

欄位 必填 說明
timestamp 是 ISO 8601(UTC,毫秒)
level 是 debug / info / warn / error / fatal
service 是 服務名稱
trace_id 是 追蹤識別碼
span_id 是 區段識別碼
message 是 訊息
actor_id 否 操作者(不得為個資)
resource 否 資源標的
duration_ms 否 耗時
error_code 否 錯誤碼
stack 否 堆疊(僅非生產或去識別化)

日誌規則

  • 一律 JSON 格式(結構化)。
  • 個資一律遮罩(見 SAD-005 §5.3)。
  • 禁止以字串拼接方式記錄請求內容。
  • 錯誤須記錄 error_code 與 trace_id 以便追查。

7.3 指標

類別 指標 目標/告警
業務 授權筆數、核准率、拒絕率 異常波動告警
業務 授權 P99 延遲 ≤ 200 ms
業務 路由 P99 延遲 ≤ 5 ms
業務 入帳筆數與金額 對帳一致
業務 投影延遲(P95) ≤ 1 秒
系統 CPU/記憶體使用率 > 60% 告警(觸發擴容)
系統 請求速率、錯誤率 錯誤率 > 1% 告警
系統 連線池使用率 > 80% 告警
系統 資料庫連線數與慢查詢 慢查詢 > 1 秒告警
訊息 Kafka 消費者延遲 > 10,000 告警
外部 外部系統呼叫成功率與延遲 失敗率 > 1% 告警
安全 登入失敗次數、權限拒絕次數 異常告警

7.4 分散式追蹤

項目 設計
追蹤識別碼 由閘道產生,貫穿所有服務與事件
傳遞方式 HTTP 標頭 X-Trace-Id;事件信封 traceId
區段 每個外部呼叫、資料庫查詢、事件發布產生一個 span
取樣 生產 10% 取樣;錯誤 100% 取樣
關聯 事件之 causationId 可回溯至觸發命令

驗收要求(POC-14 步驟 8):AP log、Kafka log、Listener log 三者須可依 trace_id 串接為完整鏈路。

7.5 告警分級

級別 條件 通知 回應
P1 服務不可用、授權成功率 < 95% 電話 + 即時通訊 立即
P2 效能劣化、錯誤率 > 1% 即時通訊 15 分鐘內
P3 單一實例異常、容量告警 即時通訊 1 小時內
P4 趨勢告警 郵件 當日

8. 容量規劃

元件 規劃基準 擴充方式
授權服務 1,000 TPS(未分庫分表);尖峰 2,000 TPS 水平擴充副本
閘道 3,000 TPS 水平擴充
資料庫 1,000 萬客戶、2,000 萬卡號 讀寫分離 → 分表 → 分庫
Kafka 尖峰 5,000 訊息/秒 增加分區與 broker
快取 熱資料集(額度、參數) 增加節點
批次 1,000 萬筆交易/小時(POC-16) 多工參數調整、水平擴充

POC-16 要求:帳單日批次於 1 小時內完成;批次期間 ONLINE 至少維持 200 TPS。


9. 維運手冊(Runbook)要項

情境 處置
服務異常 確認健康檢查 → 檢視日誌與追蹤 → 必要時重啟或回退
授權延遲升高 檢視資料庫與快取 → 確認擴容 → 必要時限流
事件延遲 檢視 Kafka 消費者延遲 → 擴充消費者
資料庫切換 依 Runbook 執行主從切換 → 驗證一致性
批次異常 定位異常資料 → 排除 → 自 Checkpoint 續跑
外部系統異常 確認斷路器狀態 → 切換備援或降級
回退 執行分流回退(≤ 1 分鐘)或版本回退
災難復原 依 DR 程序切換機房,驗證 RTO/RPO

10. 檢核

檢核項 標準
所有服務有健康檢查端點 100%
所有服務有結構化日誌 100%
所有服務有指標輸出 100%
追蹤可貫穿服務與事件 100%(POC-14 步驟 8)
無單點故障 SPOF 檢查 0 項
部署可零停機 藍綠/灰度演練通過
回退可達標 ≤ 1 分鐘(分流)、≤ 5 分鐘(版本)
自動擴容可達標 POC-17 通過
批次效能可達標 POC-16 通過

11. 修訂記錄

版本 日期 修訂者 說明
1.3 2026-10-01 WorkBuddy AI §3.2 更新:物件儲存程式接線完成(HANDOVER #A-107)——report-service 之報表輸出已改走物件儲存並真機驗證(SCS-017 §8.1);Java SDK awssdk:s3:2.55.9 由「未驗證」改列「已驗證」(編譯+執行期皆通過)。★ 併載兩個 S3 相容性地雷(實測踩到並修除):① SDK 2.30 起預設校驗+aws-chunked 會被 S3 相容實作拒絕(400 Invalid payload signature);② 校驗設定只能在一處,兩處並設會啟動期失敗。⚠️ 併更正:statement-service 之帳單 PDF 仍未接——因其 PDF 產生器本身尚未實作(不是忘了接,是沒東西可接)
1.2 2026-10-01 WorkBuddy AI 新增 §3.2「物件儲存:正式方案與本地替代方案」(HANDOVER #A-106)。★ 選型更正:既有文件(CR-017 §8.1)原載「本地已有 MinIO」——經查證不成立且已不可用:MinIO 開源版(Server/mc/KES)已封存不再維護,官方下載站 dl.min.io 回 410 Gone,明載不提供安全更新→ 違反硬性要求「不要 EOL 的東西」。改採 Garage v2.4.1(Docker Hub 有語意化版本標籤且活躍;SeaweedFS 僅 latest、RustFS 為 preview、LocalStack 為 AWS 模擬器,皆不採)。本地部署:profile storage、S3 API 埠 3900、region cardcore、bucket cardcore-artifacts、憑證置 ops/local/.env(不入版控)。已實測:映像可拉取/garage status HEALTHY/bucket 與 key 自動建立/S3 PUT-GET 往返位元組一致/負樣本(錯誤 secret → 403)
1.0 2026-09-17 SA / SRE 初版
1.1 2026-09-18 SA / SRE §3 部署單元與編排之「資料層」原僅列 PostgreSQL Primary/Replica、Redis、Kafka;依客戶指定「Oracle 為主」補入 Oracle Primary(權威 OLTP:CC_* 各服務 schema + CC_PLT) 與 Oracle Standby(Data Guard),並調整服務至資料層之連線關係。PostgreSQL 轉為承擔 CQRS 讀模型(proj)、事件流存檔(evt)與報表(rpt)。分工依據見 SAD-003 §3 與 CSP-006 §2.4
(31-31/67)