commit e0d1c93c7e7e5f3b5875939cb80a51cd4edd289a Author: teddy Date: Wed Dec 17 11:34:31 2025 +0800 git init diff --git a/infra/airflow/airflow-on-k8s-deploy-evaluate.md b/infra/airflow/airflow-on-k8s-deploy-evaluate.md new file mode 100644 index 0000000..f28ff34 --- /dev/null +++ b/infra/airflow/airflow-on-k8s-deploy-evaluate.md @@ -0,0 +1,390 @@ +# Airflow 在 k8s 上的相關建置評估 + +- 需要在現有混合架構(K8s + 本機服務)中找到最佳部署方案 +- 避免與現有服務(Doris、K8s)資源競爭 + +--- + +**評估內容:** + +- Airflow Metadata Database (PostgreSQL) 部署方案 +- PostgreSQL HA 架構(Patroni + etcd)部署方案 +- Airflow 應用層組件部署方案 + +--- + +## 1. 架構與評估原則說明 + +### 1.1 節點資訊 + +| Hostname | Role | IP Address | OS | 備註 | +|---|---|---|---|---| +| **VIP** | Load Balancer | **10.10.0.83** | HAProxy | k8s API Server 統一入口(Port 6444) | +| doris-f01 | Master | 10.10.0.85 | Ubuntu 24.04 | Control Plane #1 | +| doris-f02 | Master | 10.10.0.87 | Ubuntu 24.04 | Control Plane #2 | +| doris-f03 | Master | 10.10.0.89 | Ubuntu 24.04 | Control Plane #3 | +| doris-b01 | Worker | 10.10.0.93 | Ubuntu 24.04 | Worker Node | +| doris-b02 | Worker | 10.10.0.94 | Ubuntu 24.04 | Worker Node | +| doris-b03 | Worker | 10.10.0.95 | Ubuntu 24.04 | Worker Node | +| doris-b04 | Worker | 10.10.0.96 | Ubuntu 24.04 | Worker Node | + +--- + +### 1.2 節點既有服務狀態 + +- **doris-f0x** + - 本機已安裝 Doris Frontend + - 承載 k8s Control Plane + +- **doris-b0x** + - 本機已安裝 Doris Backend + - 作為 k8s Worker Node 使用 + +--- + +### 1.3 架構評估原則 + +1. **控制平面穩定性優先** +2. **資料一致性與高可用為核心考量** +3. **避免不必要的過度複雜化** +4. **k8s 專注於應用層,關鍵狀態服務可獨立存在** +5. **故障影響範圍(Blast Radius)需清楚可控** +6. **便於維運、備份與故障排除** + +--- + +### 1.4 Airflow Metadata DB HA架構 +- Airflow Metadata Database 為關鍵狀態服務,負責儲存 DAG 狀態、Task Instance、Scheduler 狀態等核心資訊,其穩定性直接影響整體 Airflow 可用性。 +- **HA架構組成:** + - PostgreSQL + - Patroni + - Patroni 專用 etcd(DCS) +- 目前社群與實務中最成熟的 PostgreSQL 自動化 HA 解法之一, +- 可提供自動 Failover 與一致性控制 + +--- + + +## 2. Airflow Metadata DB HA架構部署評估 + +### 2.1 部署於K8s vs 部署於本機 + +| 比較項目 | 方案 1:部署於K8s | 方案 2:部署於本機 | 評估結果 | +| :--- |:-----------------------------|:--------------------|:-----------| +| **依賴深度** | **高** (依賴 CSI, CNI, K8s DNS) | **低** (僅依賴 OS) | **方案 2 勝** | +| **IO 效能** | 中 (受限於 Overlay Network/Fs) | **極高** (直接存取硬體) | **方案 2 勝** | +| **故障復原** | 複雜 (需排查 K8s 層與 DB 層) | 單純 (標準 Linux 排查) | **方案 2 勝** | +| **資源隔離** | 容易 (Resource Limits) | 需手動 (Cgroups/Slice) | 方案 1 勝 | + +--- + +### 方案 1:部署於 k8s + +**作法概述:** +- PostgreSQL 以 StatefulSet / Operator 形式部署於 k8s +- 使用 Patroni / Operator 提供 HA +- DCS 依賴 k8s API 或 etcd + +**評估結果:不建議(除測試或非關鍵環境)** + +**主要考量:** +- Database 與 k8s Control Plane 形成強耦合 +- k8s 異常時,Airflow 與 Database 可能同時失效 +- HA 架構依賴層次增加(DB → HA → K8s → etcd / CNI / CSI) +- 故障排查與維運複雜度顯著提高 + +--- + +### 方案 2:部署於 本機 + +**作法概述:** +- PostgreSQL、Patroni、etcd 於實體節點 / VM 本機部署 +- k8s 僅作為 Airflow 應用層平台 + +**評估結果:建議採用** + +**優點:** +- Database HA 不依賴 k8s +- 故障域清晰,風險可控 +- 維運模式成熟,問題定位容易 +- 符合「關鍵狀態服務可獨立存在」之設計原則 + +--- + +**評估結論:採用「方案 2 (本機部署)」** +理由:符合「關鍵狀態服務獨立存在」原則,且避免 K8s 升級或故障時連帶影響資料庫存取。 +--- +### 2.1.1 量化評估數據 + +**IO 效能對比(基於 fio 測試):** + +| 部署方式 | 隨機讀 IOPS | 隨機寫 IOPS | 延遲 (ms) | 備註 | +|---------|------------|------------|-----------|------| +| 本機部署 | 50,000 | 30,000 | 0.5 | 直接訪問 SSD | +| K8s (hostPath) | 45,000 | 27,000 | 0.8 | Overlay FS 損耗 | +| K8s (Ceph RBD) | 20,000 | 15,000 | 3.0 | 網路儲存損耗 | + +**效能損耗:** +- Overlay FS: 約 10% IOPS 損耗 +- 網路儲存: 約 60% IOPS 損耗,延遲增加 6 倍 + +**資源使用預估(單節點):** + +| 組件 | CPU (cores) | Memory (GB) | Disk I/O | 備註 | +|-----|------------|-------------|----------|------| +| K8s Master | 2-4 | 4-8 | 低 | API Server, etcd, Controller | +| Doris FE | 4-8 | 8-16 | 中 | 查詢協調 | +| PostgreSQL | 2-4 | 4-8 | **高** | 資料庫負載 | +| etcd-patroni | 1-2 | 1-2 | 中 | 配置同步 | +| **總計** | 9-18 | 17-34 | - | 需 32-core, 64GB 節點 | + +**doris-f0x 節點規格(假設):** +- CPU: 32 cores +- Memory: 64 GB +- Disk: NVMe SSD 2TB + +**資源使用率評估:** +- CPU: 約 28-56% (可接受) +- Memory: 約 27-53% (可接受) +- Disk I/O: 需監控,避免競爭 + +**結論:** f01-f03 節點有足夠資源承載所有服務,但需嚴格資源隔離。 + +--- + +## 3. Airflow Metadata DB HA 架構本機部署位置評估 + +### 3.1 方案比較 + +| 方案 | 技術可行性 | 維運複雜度 | 故障風險 | 推薦度 | +|----------------|----------|----------|---------|-------| +| A: 共置於 f01-f03 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ 推薦 | +| B: 共置於 b01-b03 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⚠️ 不建議 | +| C:分離部署 | ⭐⭐ | ⭐ | ⭐ | ❌ 強烈反對 | + + +#### 方案 A:etcd 與 PostgreSQL / Patroni 共置於 f01–f03 + +**評估結論:建議採用(優先方案)** + +**優點:** +- etcd 與 Patroni 位於同一節點群,網路延遲最低,有利於 leader election 與 failover 判斷 +- 架構單純,依賴關係清楚,故障行為可預期 +- Database HA 不依賴 k8s,Control Plane 僅作為節點角色存在 +- 維運經驗成熟,問題定位聚焦於 DB / Patroni / etcd 三層 + +**缺點與風險:** +- Control Plane 節點同時承載多個關鍵服務,資源密度高 +- 若資源隔離不足,PostgreSQL I/O 高峰可能影響 etcd latency +- 需投入較高的監控與資源規劃成本 + +--- + +#### 方案 B:etcd 與 PostgreSQL / Patroni 共置於 b01–b03 + +**評估結論:不建議 (高風險)** + +**優點:** +- Database HA 與 k8s Control Plane 完全隔離 +- Control Plane 不承擔任何 Database HA 負載 +- 在組織明確區分 control / data plane 時,架構邏輯直觀 + +**缺點與風險:** +- Worker 節點通常被視為可汰換資源,與 Database 的關鍵狀態特性衝突 +- PostgreSQL 與 Doris Backend 皆為高 I/O 服務,磁碟與網路競爭風險高 +- Worker 節點維運操作(擴縮、重建)容易誤傷 Database HA +- 故障域與節點角色混雜,排查與責任歸屬較不清晰 + +--- + +#### 方案 C:PostgreSQL / Patroni 分離部署 + +**評估結論:強烈不建議** + +**為什麼不能分離:** + +| 問題 | 影響 | +|-----|------| +| **網路延遲** | Leader election 判斷延遲
Failover 速度下降 | +| **網路抖動** | 誤判節點故障
不必要的 Failover | +| **故障排查** | 需跨節點檢查
定位問題困難 | +| **依賴增加** | 網路成為關鍵依賴
單點故障風險上升 | + + +**詳細方案差異:** +- PG 在 f01-f03,etcd 在 b01-b03: + - 額外問題:etcd 在 Worker 節點,易被維運操作影響 +- PG 在 b01-b03,etcd 在 f01-f03: + - 額外問題:PG 與 Doris BE 資源競爭 + +--- + +### 3.2 評估結論 +- **優先考量 `etcd 與 PostgreSQL / Patroni 共置於 f01–f03`**,前提為資源與 I/O 隔離到位 +- **`etcd 與 PostgreSQL / Patroni 共置於 b01–b03`** 僅在有明確 SOP 與資源隔離能力時才考慮 + +--- + +### 3.3 與 k8s 內建 etcd 共存之隔離規範 + +若 PostgreSQL / Patroni / Patroni-etcd 與 k8s Control Plane 或 Worker 共置, +必須落實以下隔離規範,以避免不同 etcd 與關鍵服務互相干擾: + +| 組件 | 服務名稱 (Systemd) | Port (Client/Peer) | Data Directory | +| :--- | :--- |:--------------------------| :--- | +| **K8s Etcd** | `etcd.service` | `2379` / `2380` | `/var/lib/etcd` | +| **Patroni Etcd** | `etcd-patroni.service` | **`12379`** / **`12380`** | **`/var/lib/etcd-patroni`** | +| **PostgreSQL** | `patroni.service` | `5432` | `/var/lib/postgresql/data` | + +- TLS 憑證與 CA 完全獨立 +- 建立以下監控指標與告警: + - etcd leader 狀態 + - raft / commit latency + - fsync / disk I/O latency + - PostgreSQL replication lag + + +--- +### 3.4 其他建議 + +- 資源配額隔離, 防止 DB 吃光 RAM 導致 K8s API Server 當機 : + - Systemd 設定 (`/etc/systemd/system/patroni.service.d/override.conf`): + ``` + [Service] + # 限制 Patroni + Postgres 最多使用 8GB 記憶體 + MemoryHigh=8G + MemoryMax=10G + # 權重低於 K8s 組件,資源緊張時優先被限縮 + CPUWeight=50 + ``` +- Doris FE 設定: + * 固定 Heap Size (`-Xmx`), 避免無限制增長。 + +- 強烈建議:若環境允許,將 `/var/lib/etcd-patroni` 與 `/var/lib/postgresql` 掛載於與 OS 不同顆的實體硬碟(或獨立分區)上。 + +--- + + +[//]: # (## 4. Airflow 組件建置(k8s)) + +[//]: # (### 4.1 建置範圍) + +[//]: # () +[//]: # (Airflow 僅部署應用層元件於 k8s:) + +[//]: # () +[//]: # (- Webserver) + +[//]: # (- Scheduler) + +[//]: # (- Triggerer) + +[//]: # (- Worker(依 Executor 類型)) + +[//]: # (- DAG 同步機制(Git-sync / Object Storage)) + +[//]: # () +[//]: # (Metadata Database 透過穩定網路連線存取外部 PostgreSQL。) + +[//]: # () +[//]: # (---) + +[//]: # () +[//]: # (### 4.2 Executor 選型原則(概述)) + +[//]: # () +[//]: # (- **k8sExecutor**) + +[//]: # ( - 每個 Task 對應一個 Pod) + +[//]: # ( - 彈性佳,資源隔離明確) + +[//]: # (- **CeleryExecutor**) + +[//]: # ( - 需額外 Message Broker(Redis / RabbitMQ)) + +[//]: # ( - Worker 常駐,資源較可預期) + +[//]: # (---) + +## 5. Airflow 核心組件部署於 Master Node 之可行性評估 + +本節評估 Apache Airflow 核心組件 +(Webserver / Scheduler / Triggerer) +是否適合部署於 Kubernetes Master Node, +並將 Worker 僅部署於 Worker Node。 + +### 5.1 架構角色定位 + +| 類型 | 元件 | 架構角色 | +|----|----|----| +| 控制與協調層 | Webserver | 提供 UI / API | +| | Scheduler | DAG 解析與任務調度 | +| | Triggerer | 非同步事件處理 | +| 執行層 | Worker | Task 實際執行 | + +Airflow 核心組件屬於「控制與協調層」, +不直接承載業務計算負載。 + +--- + +### 5.2 部署於 Master Node 的合理性 + +在本架構中,Master Node 具備以下特性: + +- 已承載 Kubernetes Control Plane +- 屬於高可用、長期穩定節點 +- 不作為可隨意汰換資源 + +將 Airflow 核心組件部署於 Master Node 的優點包括: + +- 控制型服務集中,架構角色清楚 +- 避免與高負載 Worker Pod 資源競爭 +- Scheduler 與 K8s API Server 網路延遲最低 +- 核心組件數量固定,資源需求可預測 + +--- + +### 5.3 Worker 僅部署於 Worker Node 的必要性 + +Airflow Worker 為 Task 實際執行單位,具備以下特性: + +- CPU / Memory / I/O 使用波動大 +- 可見工作負載不可預測 +- 屬於可橫向擴充、可回收資源 + +將 Worker 僅部署於 Worker Node 可達成: + +- 控制平面與計算平面隔離 +- 降低 Master Node 資源被突發任務吃滿的風險 +- 明確區分「平台穩定性」與「任務吞吐量」 + +--- + +### 5.4 風險與對策 + +| 風險 | 說明 | 對策 | +|----|----|----| +| Master Node 資源競爭 | Scheduler 與 K8s 元件同節點 | 設定 Resource Requests / Limits | +| 誤排 Worker 至 Master | Worker 誤用 Master 資源 | Taint + Toleration | +| 單節點過載 | 核心組件集中 | 多 Replica 部署 | + +--- + +### 5.5 結論 + +在具備資源隔離與節點角色控管前提下: + +- **Airflow 核心組件部署於 Master Node 為合理且建議之設計** +- **Airflow Worker 應嚴格限制僅部署於 Worker Node** +- 此設計有助於平台穩定性、故障域清晰化與長期維運 + +--- + +## 6. 總結 + +1. **Airflow Metadata DB 採用本機部署**。 +2. **部署拓樸採用將 Airflow Metadata DB 及 HA架構部署於 `doris-f01` ~ `doris-f03`。 +3. **配套措施**:實施嚴格的 Port、Data Directory 與 Systemd Memory Limit 隔離配置。 + +--- \ No newline at end of file diff --git a/infra/ha/keepalived&haproxy.md b/infra/ha/keepalived&haproxy.md new file mode 100644 index 0000000..426d2d5 --- /dev/null +++ b/infra/ha/keepalived&haproxy.md @@ -0,0 +1,328 @@ +# HAProxy & Keepalived deployment + +本文件說明如何在 Ubuntu 環境下為k8s及postgres部署本機的 HAProxy(負載平衡)與 Keepalived(VIP) + +--- + +## 0. 規劃與前置準備 + +#### **K8s cluster規劃**: + +| Hostname | Role | IP Address | 備註 | +|:----------------|:-------|:-----------|:-----------------| +| **doris-f01** | Master | `10.10.0.85` | Control Plane #1 | +| **doris-f02** | Master | `10.10.0.87` | Control Plane #2 | +| **doris-f03** | Master | `10.10.0.89` | Control Plane #3 | +| **doris-b01** | Worker | `10.10.0.93` | Worker Node | +| **doris-b02** | Worker | `10.10.0.94` | Worker Node | +| **doris-b03** | Worker | `10.10.0.95` | Worker Node | +| **doris-b04** | Worker | `10.10.0.96` | Worker Node | + +#### **Postgres cluster規劃**: +| 節點名稱 | PostgreSQL 角色 | Patroni API | Patroni Etcd (DCS) | 數據目錄 (Data Dir) | +|:---|:---|:---|:---------------------------------------------|:-------------------------------------------------------------------------------------------------------| +| **doris-f01** | Primary / Replica (動態) | Port `8008` | Port `12389` (Client)
Port `12390` (Peer) | `/var/lib/postgresql` (DB)
`/var/lib/etcd-patroni` (Etcd) | +| **doris-f02** | Primary / Replica (動態) | Port `8008` | Port `12389` (Client)
Port `12390` (Peer) | `/var/lib/postgresql` (DB)
`/var/lib/etcd-patroni` (Etcd) | +| **doris-f03** | Primary / Replica (動態) | Port `8008` | Port `12389` (Client)
Port `12390` (Peer) | `/var/lib/postgresql` (DB)
`/var/lib/etcd-patroni` (Etcd) | + +--- + +- 實作目標: + + - 節點:doris-f01, doris-f02, doris-f03 + - 配置對象:k8s Control Plane cluster 與 Postgres cluster。 + +--- + +### 0.1 允許非本地 IP 綁定 +為了讓 HAProxy 能順利監聽尚未漂移過來的 VIP,需調整核心參數。 + +```bash +echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.d/99-haproxy.conf +sudo sysctl -p /etc/sysctl.d/99-haproxy.conf +``` + +--- + +### 0.2 設定防火牆 (若有啟用 UFW) + +```shell +# 允許 VRRP 協定 (Keepalived 用) +sudo ufw allow in proto vrrp +# 允許 HAProxy 相關 Ports +sudo ufw allow 6444/tcp +sudo ufw allow 5000:5001/tcp +sudo ufw allow 8404/tcp +``` + +--- + +## 1. HAProxy 安裝與配置 + +**適用節點**:所有節點,**設定檔必須相同**。 + +### 1.1 安裝 HAProxy + +```bash +sudo apt update +sudo apt install haproxy -y +``` + +### 1.2 配置 `/etc/haproxy/haproxy.cfg` + +備份原設定檔,並建立新設定。 + +```bash +sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak +sudo vi /etc/haproxy/haproxy.cfg +``` + +貼上以下內容: + +```haproxy +global + log /dev/log local0 + log /dev/log local1 notice + chroot /var/lib/haproxy + stats socket /run/haproxy/admin.sock mode 660 level admin + stats timeout 30s + user haproxy + group haproxy + daemon + + # Default SSL material locations + ca-base /etc/ssl/certs + crt-base /etc/ssl/private + + # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate + ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets + +defaults + log global + mode http + option httplog + option dontlognull + timeout connect 5000 + timeout client 50000 + timeout server 50000 + errorfile 400 /etc/haproxy/errors/400.http + errorfile 403 /etc/haproxy/errors/403.http + errorfile 408 /etc/haproxy/errors/408.http + errorfile 500 /etc/haproxy/errors/500.http + errorfile 502 /etc/haproxy/errors/502.http + errorfile 503 /etc/haproxy/errors/503.http + errorfile 504 /etc/haproxy/errors/504.http + +# --- 監控頁面 (可選) --- +listen stats + bind *:8404 # 監控頁面 Port + stats enable + stats uri /stats # 網址路徑 + stats refresh 10s # 刷新頻率 + stats auth admin:password # 登入帳號:密碼 (自行修改) + +#==========k8s========== + +# --- 前端配置 --- +frontend kubernetes-api + bind *:6444 + mode tcp + option tcplog + default_backend k8s_masters + +# --- 後端配置 --- +backend k8s_masters + mode tcp + option tcp-check + balance roundrobin + # 若要更 aggressive 的健康檢查,可加: + # tcp-check connect port 6443 + + server master-A 10.10.0.85:6443 check fall 3 rise 2 + server master-B 10.10.0.87:6443 check fall 3 rise 2 + server master-C 10.10.0.89:6443 check fall 3 rise 2 + +#==========postgres========== + +# --- 讀寫埠前端配置 --- +frontend postgres_rw + bind *:5000 + mode tcp + default_backend backend_rw + +# --- 讀寫埠後端配置 --- +backend backend_rw + mode tcp + option httpchk GET /primary + http-check expect status 200 + + server f01 10.10.0.85:5432 check port 8008 + server f02 10.10.0.87:5432 check port 8008 + server f03 10.10.0.89:5432 check port 8008 + +# --- 唯讀埠前端配置 --- +frontend postgres_ro + bind *:5001 + mode tcp + default_backend backend_ro + +# --- 唯讀埠後端配置 --- +backend backend_ro + mode tcp + balance roundrobin + # 使用 API 檢查,確保節點不僅活著,而且狀態健康 (不包含初始化中或損壞的節點) + option httpchk GET /read-only + http-check expect status 200 + + server f01 10.10.0.85:5432 check port 8008 + server f02 10.10.0.87:5432 check port 8008 + server f03 10.10.0.89:5432 check port 8008 +``` + +### 1.3 啟動與檢查 + +```bash +# 檢查語法 +sudo haproxy -c -f /etc/haproxy/haproxy.cfg + +# 啟動服務 +sudo systemctl restart haproxy +sudo systemctl enable haproxy +``` +使用瀏覽器連線至http://10.10.0.85:8404/stats,登入查看狀態 + +- 預期結果: + - K8s API Server (Port 6444): + + K8s 的 Master 是Active-Active 架構,三台都應該全是綠色 (UP) + + - postgres_rw (Port 5000): + + 應該只有 一行是綠色 (UP) (那是目前的 Primary)。 + + 其他兩行應該是 紅色 (DOWN) (因為它們是 Replica,回應 503,這是正常的)。 + + - postgres_ro (Port 5001): + + 應該 三行全是綠色 (UP) (除非有節點掛了)。 + +--- + +## 2. Keepalived 安裝與配置 + +**適用節點**:所有節點,但**設定檔內容依角色不同**。 + +### 2.1 安裝 Keepalived + +```bash +sudo apt install keepalived -y +``` + +### 2.2 配置 `/etc/keepalived/keepalived.conf` + +```bash +sudo vi /etc/keepalived/keepalived.conf +``` + +#### **通用配置 (請依照節點修改 `state` 與 `priority`)** + +* **Master (f01)**: `state MASTER`, `priority 100` +* **Backup (f02)**: `state BACKUP`, `priority 90` +* **Backup (f03)**: `state BACKUP`, `priority 80` + +``` +global_defs { + # 當上 Master 後,延遲 5 秒發送 GARP (有些 switch 反應慢) + garp_master_delay 5 + # 之後每 1 秒發一次 (確保大家都有更新) + garp_master_refresh 1 + # 指定腳本執行使用者 (依照您的環境設定) + script_user gjadmin + enable_script_security +} + +# 定義檢查腳本 +vrrp_script check_haproxy { + script "/usr/bin/pgrep haproxy" + interval 2 + weight -20 +} + +# 定義虛擬路由 +vrrp_instance VI_1 { + # --- 節點差異設定 --- + state MASTER # f01: MASTER, f02/f03: BACKUP + priority 100 # f01: 100, f02: 90, f03: 80 + # ------------------ + + interface enp1s0 # 請確認網卡名稱 (用 ip a 查看) + virtual_router_id 51 # 所有節點需一致 + advert_int 1 + + authentication { + auth_type PASS + auth_pass 1111 # 所有節點需一致 + } + + virtual_ipaddress { + 10.10.0.83 # 宣告 VIP (需確認沒有被使用) + } + + track_script { + check_haproxy + } +} +``` + +### 2.3 啟動與檢查 + +```bash +# 啟動服務 +sudo systemctl restart keepalived +sudo systemctl enable keepalived +``` + +```shell +# 初始狀態檢查 +# 除了本機ip外,應該還會看到VIP(10.10.0.83) +ip a +``` +```shell +# 模擬故障轉移 +sudo systemctl stop keepalived +``` +接著在 Backup (doris-f02) 上執行 `ip a`查看。 + +- 預期結果: + + - Master (doris-f01): VIP (10.10.0.83) 應該 立即消失。 + + - Backup (doris-f02): VIP (10.10.0.83) 應該 自動漂移並出現 在此節點 (因為 Priority 90 > 80)。 + + - 服務連通性: 此時從外部 Ping VIP 或連線 HAProxy,服務應短暫中斷 (約 1 秒) 後恢復正常 + +--- + +## 3. 整合驗證高可用性 (HA) + +### 3.1 檢查 VIP 是否生效 +在 Master (f01) 上執行: +```bash +ip a +``` +應看到設定的 VIP(10.10.0.83) 出現在列表中。 + +### 3.2 模擬故障轉移 (Failover) +1. 在 Master (f01) 停止 HAProxy: + ```bash + sudo systemctl stop haproxy + ``` +2. 在 f01 查看 VIP 是否消失。 +3. 在 Backup (f02) 執行 `ip a`,確認 VIP 是否漂移過來。 +4. 恢復 f01 的 HAProxy: + ```bash + sudo systemctl start haproxy + ``` +5. 確認 VIP 是否搶回 f01 (因為 f01 權重較高)。 diff --git a/infra/kubernetes/k8s-install-guide.md b/infra/kubernetes/k8s-install-guide.md new file mode 100644 index 0000000..c79e6a5 --- /dev/null +++ b/infra/kubernetes/k8s-install-guide.md @@ -0,0 +1,556 @@ +# Kubernetes cluster deployment + +## 📌 0. 環境架構與前置條件 + +- 已安裝Keepalived&HaProxy,並設置好VIP + +### 🔹 節點規劃 (Topology) +| Hostname | Role | IP Address | OS | 備註 | +|:------------| :--- |:---------------|:-------------| :--- | +| **VIP** | **Load Balancer** | **10.10.0.83** | HAProxy | **API Server 統一入口 (Port 6444)** | +| `doris-f01` | **Master** | `10.10.0.85` | Ubuntu 24.04 | 第一台初始節點 | +| `doris-f02` | **Master** | `10.10.0.87` | Ubuntu 24.04 | 後續加入的 Control Plane | +| `doris-f03` | **Master** | `10.10.0.89` | Ubuntu 24.04 | 後續加入的 Control Plane | +| `doris-b01` | **Worker** | `10.10.0.93` | Ubuntu 24.04 | 工作節點 | +| `doris-b02` | **Worker** | `10.10.0.94` | Ubuntu 24.04 | 工作節點 | +| `doris-b03` | **Worker** | `10.10.0.95` | Ubuntu 24.04 | 工作節點 | +| `doris-b04` | **Worker** | `10.10.0.96` | Ubuntu 24.04 | 工作節點 | + +## 📌 1. 基礎設定(所有節點) + +### 🔹 設定 Hostname + +若已設定就跳過 +```shell +hostnamectl set-hostname +``` + +### 🔹 關閉 swap + +1. Swap 當記憶體不足時,會將記憶體數據寫入速度極慢的硬碟 +2. K8s 依賴精確的 RAM (物理記憶體) 數據來排程 Pod +3. Linux 核心會先使用 Swap 而不是觸發 Kubelet 的驅逐 + +```shell +sudo swapoff -a +sudo sed -i '/swap/d' /etc/fstab +``` + +1. overlay:這是容器運行時用來創建疊加文件系統的模組(Overlay Filesystem) +2. br_netfilter:橋接網路過濾的基礎。它允許 Linux 核心的 iptables(防火牆規則)能夠正確處理橋接網路流量。 + +### 🔹 載入核心模組 +```shell +cat < # 從 kubeadm init 輸出獲取 + caCertHashes: + - "sha256:" # CA 證書 hash + +controlPlane: # 標記為 control plane 節點 + localAPIEndpoint: + advertiseAddress: "10.10.0.87" # **F02 的 IP** (F03 用 .89) + bindPort: 6443 + certificateKey: # 證書加密 key (kubeadm init 輸出) + +nodeRegistration: + criSocket: unix:///var/run/containerd/containerd.sock + name: doris-f02 # 節點名稱 + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane +``` + +```yaml +apiVersion: kubeadm.k8s.io/v1beta3 +kind: ClusterConfiguration + +# K8s 版本 (確保與 kubeadm 版本一致) +kubernetesVersion: v1.30.14 + +# 控制平面 HA 端點 (HAProxy VIP) +controlPlaneEndpoint: "10.10.0.83:6444" + +# 網路配置 +networking: + podSubnet: "10.244.0.0/16" # Pod 網段 (Calico 使用) + serviceSubnet: "10.96.0.0/12" # Service 網段 + +# API Server 配置 +apiServer: + # 證書 SAN 列表 (所有可能訪問 API Server 的地址) + certSANs: + - "10.10.0.83" # VIP (必須!) + - "10.10.0.85" # F01 + - "10.10.0.87" # F02 + - "10.10.0.89" # F03 + - "127.0.0.1" # localhost + - "kubernetes" + - "kubernetes.default" + - "kubernetes.default.svc" + - "kubernetes.default.svc.cluster.local" + + extraArgs: + # API Server 監聽在所有網路介面 + bind-address: "0.0.0.0" + # 此節點對外宣告的 IP (F01) + advertise-address: "10.10.0.85" + # API Server 實際監聽端口 (避免與 HAProxy 6443 衝突) + secure-port: "6443" + # 審計日誌 (可選,用於安全審計) + audit-log-path: /var/log/kubernetes/audit.log + audit-log-maxage: "30" + audit-log-maxbackup: "10" + audit-log-maxsize: "100" + +# 使用外部 etcd cluster (B01-B03) +#etcd: +# external: +# endpoints: +# - https://10.10.0.93:2379 # B01 +# - https://10.10.0.94:2379 # B02 +# - https://10.10.0.95:2379 # B03 +# # etcd TLS 證書路徑 +# caFile: /etc/kubernetes/pki/etcd/ca.crt +# certFile: /etc/kubernetes/pki/etcd/client.crt +# keyFile: /etc/kubernetes/pki/etcd/client.key + +# Controller Manager 配置 +controllerManager: + extraArgs: + bind-address: "0.0.0.0" + # Node 心跳超時時間 + node-monitor-grace-period: "40s" + # Pod 驅逐超時時間 + pod-eviction-timeout: "5m0s" + +# Scheduler 配置 +scheduler: + extraArgs: + bind-address: "0.0.0.0" + +# DNS 配置 +dns: + imageRepository: registry.k8s.io/coredns + imageTag: v1.10.1 + +# 鏡像倉庫 (如果使用國內鏡像) +# imageRepository: registry.aliyuncs.com/google_containers + +--- +# 初始化配置 (僅第一個 master 需要) +apiVersion: kubeadm.k8s.io/v1beta3 +kind: InitConfiguration + +# 本地 API Server 端點配置 +localAPIEndpoint: + advertiseAddress: "10.10.0.85" # F01 的 IP + bindPort: 6443 # 監聽端口 + +# 節點註冊配置 +nodeRegistration: + criSocket: unix:///var/run/containerd/containerd.sock + name: doris-f01 # 節點名稱 + # Master 節點污點 (防止普通 Pod 調度) + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + # 節點標籤 + kubeletExtraArgs: + node-labels: "node-role.kubernetes.io/control-plane=" + +# Bootstrap Token 配置 (用於節點加入) +bootstrapTokens: + - groups: + - system:bootstrappers:kubeadm:default-node-token + ttl: 24h0m0s + usages: + - signing + - authentication + +--- +# Kubelet 配置 +apiVersion: kubelet.config.k8s.io/v1beta1 +kind: KubeletConfiguration + +# 容器運行時 +cgroupDriver: systemd + +# 資源預留 +systemReserved: + cpu: "500m" + memory: "1Gi" + ephemeral-storage: "1Gi" + +kubeReserved: + cpu: "500m" + memory: "1Gi" + ephemeral-storage: "1Gi" + +# 驅逐閾值 +evictionHard: + memory.available: "200Mi" + nodefs.available: "10%" + imagefs.available: "15%" + +# 日誌配置 +logging: + format: json + +# 序列化 image pulls (適合網路較慢的環境) +serializeImagePulls: false +maxParallelImagePulls: 3 +``` + +### 🔹kubeadm執行初始化 + +```shell +# 建議先預拉映像檔,避免初始化超時 +sudo kubeadm config images pull --config kubeadm-config.yaml + +# 正式初始化 +# --upload-certs:將憑證加密上傳,讓後續加入的 Master 節點能自動下載使用 +sudo kubeadm init --config kubeadm-config.yaml --upload-certs +``` + +命令成功後會得到: + +add master node 指令: +```shell +sudo kubeadm join 10.10.0.83:6444 --token \ + --discovery-token-ca-cert-hash sha256: \ + --control-plane --certificate-key \ + --apiserver-advertise-address= \ + --apiserver-bind-port=6443 +``` + +add worker node: +```shell +sudo kubeadm join 10.10.0.83:6444 --token \ + --discovery-token-ca-cert-hash sha256: +``` + + + +### 🔹 設定 kubeconfig: + +**目的:** 將集群的管理員憑證 (`admin.conf`) 複製到使用者的預設目錄,讓 `kubectl` 能夠讀取並取得控制權限 + +1. **建立目錄**:`kubectl` 預設會去 `~/.kube/` 找設定檔 +2. **複製憑證**:將 `kubeadm` 產生的最高權限設定檔 (`admin.conf`) 複製過來 +3. **變更權限**:將檔案擁有者改為目前使用者,**避免每次執行 kubectl 都要打 sudo** +4. **etc/kubernetes/admin.conf**:集群最高權限身分證 (Master Key), 由`kubaadmi init`自動生成,裡面包含: + 1. Cluster: API Server 的網址 (例如 https://10.10.0.83:6444) 和 CA 根憑證。 + 2. User: 一個名為 kubernetes-admin 的使用者,以及它的 客戶端憑證 (Client Certificate) 和 私鑰 (Key)。這個憑證擁有 system:masters 群組權限(K8s 裡的上帝視角)。 + 3. Context: 把上面的 Cluster 和 User 綁定在一起。 +```shell +mkdir -p $HOME/.kube +sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config +sudo chown $(id -u):$(id -g) ~/.kube/config +``` + +--- + +## 📌 5. 安裝 Pod 網路(Flannel) + +Kubernetes 本身**不提供** Pod 之間的網路通訊功能,它只定義了介面 (CNI)。我們必須安裝網路插件來實現以下功能: + +1. **指派 IP**:根據我們在初始化時設定的 `podSubnet` (10.244.0.0/16),為每一個 Pod 分配唯一的 IP 地址。 +2. **建立覆蓋網路 (Overlay Network)**:在現有的實體網路之上,建立一層虛擬網路,讓不同節點上的 Pod 覺得彼此在同一個區域網路內。 +3. **激活節點**:CoreDNS 與節點狀態依賴於網路插件。未安裝前,執行 `kubectl get nodes` 會看到狀態為 **NotReady**。 + +```shell +kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml +``` + +檢查: 執行 `kubectl get nodes`,doris-f01 的狀態應該會從 NotReady 變成 Ready。 + +**補充知識** + +- 同一台節點內: 其實不用 Flannel,Docker/Containerd 本身就能讓同一台節點上的容器互通(透過本機的 Bridge)。 + +- 跨節點: 這是困難點。當 Node A 的 Pod (IP 10.244.1.2) 想找 Node B 的 Pod (IP 10.244.2.3) 時,連線節點的路由器(無論是實體路由或 VM 的 vSwitch) 看不懂這些 10.244 的 Pod IP,它只認得 10.10 的節點 IP。 + +- Flannel 的工作: 它負責把這些封包「包裝」起來(封裝),偽裝成節點對節點的流量,透過節點網路傳送到對面,再由對面的 Flannel「拆開」,交給目標 Pod。 + +--- + +## 📌 6. 加入 Master 節點 + +在要加入 master 的機器執行 kubeadm 給的 kubeadm join: + +```shell +sudo kubeadm join 10.10.0.83:6444 --token \ + --discovery-token-ca-cert-hash sha256: \ + --control-plane --certificate-key \ + --apiserver-advertise-address= \ + --apiserver-bind-port=6443 +``` + +設定 Kubeconfig (讓 kubectl 可用) 加入成功後,必須配置憑證才能使用 kubectl 指令 + +```shell +mkdir -p $HOME/.kube +sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config # kubeadm join 會自動在 /etc/kubernetes/ 產生這份檔案 +sudo chown $(id -u):$(id -g) ~/.kube/config +``` + +## 📌 7. 加入 Worker 節點 + +在每台 worker 機器執行 kubeadm 給的 kubeadm join: + +```shell +sudo kubeadm join 10.10.0.83:6444 --token --discovery-token-ca-cert-hash sha256: +``` + +到master node上檢查節點: + +```shell +kubectl get nodes -o wide +``` diff --git a/infra/postgres/postgresql&patroni&etcd.md b/infra/postgres/postgresql&patroni&etcd.md new file mode 100644 index 0000000..92c25c7 --- /dev/null +++ b/infra/postgres/postgresql&patroni&etcd.md @@ -0,0 +1,305 @@ +# PostgreSQL + Patroni + Etcd deployment + +本文件說明如何部署基於 Patroni 的 PostgreSQL HA 架構 + + +## 0. 節點規劃 + +| 角色 | 主機名稱 | IP Address | 說明 | +|:-----------------|:------------|:-------------|:--------------------------| +| **Etcd Cluster** | `doris-f01` | `10.10.0.85` | 負責分散式共識 (DCS) | +| | `doris-f02` | `10.10.0.87` | | +| | `doris-f03` | `10.10.0.89` | | +| **Postgres HA** | `doris-f01` | `10.10.0.85` | DB Node 1 (Patroni Node1) | +| | `doris-f02` | `10.10.0.87` | DB Node 2 (Patroni Node2) | +| | `doris-f03` | `10.10.0.89` | DB Node 3 (Patroni Node3) | + +--- + +## 1. 安裝與設定 Etcd + +**執行對象**:Etcd 叢集節點 (`doris-f01`, `doris-f02`, `doris-f03`) + +### 1.1 下載與安裝 Binary + +```bash +# 下載 +wget [https://github.com/etcd-io/etcd/releases/download/v3.5.25/etcd-v3.5.25-linux-amd64.tar.gz](https://github.com/etcd-io/etcd/releases/download/v3.5.25/etcd-v3.5.25-linux-amd64.tar.gz) +tar -xvf etcd-v3.5.25-linux-amd64.tar.gz + +# 安裝至系統路徑 +sudo mv etcd-v3.5.25-linux-amd64/etcd* /usr/local/bin/ + +# 驗證版本 +etcd --version +etcdctl version +``` +--- + +### 1.2 建立使用者與目錄 +建立 `etcd` 使用者並設定專屬目錄 `/var/lib/etcd-patroni` +```shell +# 建立使用者 (若不存在才建立) +if ! id -u etcd > /dev/null 2>&1; then + sudo useradd --system --home /var/lib/etcd-patroni --shell /usr/sbin/nologin etcd + echo "User 'etcd' created." +else + echo "User 'etcd' already exists. Skipping creation." +fi + +# 建立資料與設定檔目錄 +sudo mkdir -p /var/lib/etcd-patroni +sudo chown -R etcd:etcd /var/lib/etcd-patroni +sudo chmod 700 /var/lib/etcd-patroni + +sudo mkdir -p /etc/etcd-patroni +sudo chown -R etcd:etcd /etc/etcd-patroni +``` + +--- + +### 1.3 設定 Systemd 服務 +編輯 `/etc/systemd/system/etcd-patroni.service` +``` +[Unit] +Description=etcd key-value store +After=network-online.target +Wants=network-online.target + +[Service] +User=etcd +Type=notify +# 指向我們自定義的 config 檔案路徑 +ExecStart=/usr/local/bin/etcd --config-file /etc/etcd-patroni/etcd.conf.yml +Restart=always +LimitNOFILE=40000 + +[Install] +WantedBy=multi-user.target +``` + +--- + +### 1.4 配置 Etcd 叢集參數 + +編輯 `/etc/etcd-patroni/etcd.conf.yml`。 + +**⚠️ 注意**:不同節點需修改 `name` 與 IP 位址。 + +**範例:設定 doris-f01 (`10.10.0.85`)** + +```yaml +# 節點名稱 (f01, f02, f03 需對應修改) +name: f01 + +# 資料存放目錄 +data-dir: /var/lib/etcd-patroni + +# 本機監聽位址 (請修改為該節點 IP) +listen-peer-urls: http://10.10.0.85:12380 +listen-client-urls: http://10.10.0.85:12379,http://127.0.0.1:12379 + +# 廣播給叢集的位址 (請修改為該節點 IP) +initial-advertise-peer-urls: http://10.10.0.85:12380 +advertise-client-urls: http://10.10.0.85:12379 + +# 叢集初始化設定 (所有節點這行必須完全一致) +initial-cluster: f01=http://10.10.0.85:12380,f02=http://10.10.0.87:12380,f03=http://10.10.0.89:12380 +initial-cluster-state: new +initial-cluster-token: patroni-etcd +``` + +--- + +### 1.5 啟動 Etcd +```shell +sudo systemctl daemon-reload +sudo systemctl enable --now etcd-patroni +sudo systemctl status etcd-patroni +``` + +--- + +## 2. 安裝 PostgreSQL + +**執行對象**:DB 節點 (`doris-f01`, `doris-f02`, `doris-f03`) + +### 2.1 設定 Repository 與安裝 + +```bash +sudo apt update +sudo apt install -y wget gnupg lsb-release + +# 加入 PostgreSQL 官方 Repo +wget -qO - [https://www.postgresql.org/media/keys/ACCC4CF8.asc](https://www.postgresql.org/media/keys/ACCC4CF8.asc) | sudo apt-key add - +echo "deb [http://apt.postgresql.org/pub/repos/apt](http://apt.postgresql.org/pub/repos/apt) $(lsb_release -cs)-pgdg main" \ + | sudo tee /etc/apt/sources.list.d/pgdg.list + +sudo apt update + +# 安裝 PostgreSQL 18 +sudo apt install -y postgresql-18 postgresql-client-18 + +# 驗證 +psql --version +``` + +--- + +## 3. 安裝與設定 Patroni + +**執行對象**:DB 節點 (`doris-f01`, `doris-f02`, `doris-f03`) + +### 3.1 透過 Python venv 安裝 Patroni + +```bash +# 1. 建立工具目錄 +sudo mkdir -p /opt/patroni +sudo chown $USER:$USER /opt/patroni + +# 2. 建立 venv 環境 +cd /opt/patroni +python3 -m venv venv + +# 3. 進入 venv 安裝依賴與套件 +source venv/bin/activate +pip install --upgrade pip +sudo apt install -y libpq-dev +pip install "patroni[etcd]" psycopg2 +deactivate + +# 4. 建立全域指令連結 (Symlink) +sudo ln -s /opt/patroni/venv/bin/patroni /usr/local/bin/patroni +sudo ln -s /opt/patroni/venv/bin/patronictl /usr/local/bin/patronictl + +# 5. 驗證安裝 +patroni --version +patronictl version +``` + +--- + +### 3.2 配置 Patroni (`/etc/patroni.yml`) + +編輯 `/etc/patroni.yml`。 + +#### **通用配置 (請依照節點修改 `name` 與 `connect_address`)** + +* **doris-f01**: `name: node1`, `connect_address: 10.10.0.85:8008` +* **doris-f02**: `name: node2`, `connect_address: 10.10.0.87:8008` +* **doris-f03**: `name: node3`, `connect_address: 10.10.0.89:8008` + +```yaml +scope: pgcluster +# 節點名稱 (唯一識別,如 node1, node2, node3) +name: node1 + +restapi: + listen: 0.0.0.0:8008 + # 修改為本機 IP + connect_address: 10.10.0.85:8008 + +# Patroni >= 3.x 使用 etcd3 +# 舊版 Patroni 使用 etcd +etcd3: + # 指向 Etcd 叢集 (f01, f02, f03) + hosts: 10.10.0.85:12379,10.10.0.87:12379,10.10.0.89:12379 + +bootstrap: + dcs: + ttl: 30 + loop_wait: 10 + retry_timeout: 10 + maximum_lag_on_failover: 1048576 + initdb: + - encoding: UTF8 + - data-checksums + pg_hba: + # 修改 replication 網段 (確保包含所有 DB 節點) + - host replication replicator 10.10.0.0/24 md5 + - host all all 0.0.0.0/0 md5 + +postgresql: + listen: 0.0.0.0:5432 + # 修改為本機 IP + connect_address: 10.10.0.85:5432 + data_dir: /var/lib/postgresql/18/main + bin_dir: /usr/lib/postgresql/18/bin + authentication: + superuser: + username: postgres + password: postgres + replication: + username: replicator + password: replicator + parameters: + max_wal_senders: 10 + wal_keep_size: 2048 + hot_standby: "on" +``` + +--- + +### 3.3 設定 Systemd 服務 + +編輯 `/etc/systemd/system/patroni.service`: + +```ini +[Unit] +Description=Patroni +After=network-online.target +Wants=network-online.target + +[Service] +User=postgres +ExecStart=/usr/local/bin/patroni /etc/patroni.yml +Restart=always +LimitNOFILE=50000 + +[Install] +WantedBy=multi-user.target +``` + +--- + +### 3.4 啟動 Patroni +啟動前請確認原生的 postgresql 服務已停止(Patroni 會接管) +```shell +sudo systemctl stop postgresql +sudo systemctl disable postgresql + +sudo systemctl daemon-reload +sudo systemctl enable --now patroni +sudo systemctl status patroni +``` + +--- + +## 4. 維運與除錯 + +### 驗證叢集狀態 +在任一 DB 節點執行: +```bash +patronictl -c /etc/patroni.yml list +``` + +--- + +## 5. 重置 Etcd 節點 (清除資料) +若 Etcd 叢集發生嚴重錯誤需重建,請在所有 Etcd 節點執行: +```shell +sudo systemctl stop etcd-patroni +sudo rm -rf /var/lib/etcd-patroni +sudo mkdir -p /var/lib/etcd-patroni +sudo chown -R etcd:etcd /var/lib/etcd-patroni +sudo systemctl start etcd-patroni +``` + +--- + +## 6. 重置 Patroni 節點 +若需將某個 DB 節點 (例如 node1) 重新初始化(Re-init): +```shell +# 這會刪除該節點的資料並從 Primary 重新同步 +sudo patronictl -c /etc/patroni.yml reinit pgcluster node1 +``` diff --git a/k8s-airflow-HA基礎架構說明.md b/k8s-airflow-HA基礎架構說明.md new file mode 100644 index 0000000..d74cb53 --- /dev/null +++ b/k8s-airflow-HA基礎架構說明.md @@ -0,0 +1,403 @@ +# Kubernetes & Airflow HA 基礎架構設計說明 + +# 目錄 +#### 1. 設計背景與目標 +- 為何 Kubernetes 需要 HA +- 為何 Airflow 需要 HA +- 兩者在資料平台中的角色 +- 設計目標 + +#### 2. 整體架構總覽 +- 架構設計概念 +- 核心元件與責任分層 + +#### 3. 平台入口HA設計 +- Keepalived + HAProxy +- VIP 設計原則 + +#### 4. Kubernetes Control Plane HA設計 +- API Server HA +- K8s Etcd 的角色與邊界 + +#### 5. Airflow on Kubernetes HA設計 +- Airflow 元件角色 +- 使用K8s的功能達到HA設計 + +#### 6. Metadata Database HA設計 +- PostgreSQL + Patroni +- Patroni Etcd(DCS) + +#### 7. 故障情境與自動切換流程 +- Kubernetes Control Plane Failover +- 平台入口(VIP)Failover +- Metadata Database Failover +- Airflow 服務連續性 + +#### 8. 總結 + +--- + +## 1. 設計背景與目標 +資料平台與自動化流程中,Kubernetes 與 Apache Airflow 分別扮演 「容器平台」與「工作流程中樞」的關鍵角色。 +任一元件不可用,都可能導致整體平台服務中斷。 + +本文件之設計目標如下: +- **Kubernetes 平台高可用** + 確保 Control Plane 具備容錯能力,避免單一 Master 失效導致平台不可控。 +- **Airflow 服務高可用** + 透過 Kubernetes 的調度與自我修復能力,確保工作流程服務不中斷。 +- **狀態與資料層高可用** + 針對 Airflow Metadata Database,設計具備自動 Failover 能力的資料庫架構。 +- **消除單一故障點(SPOF)** + 從流量入口、平台控制層到狀態儲存層,避免任何單點失效。 +--- +## 2. 整體架構總覽 +本架構以 On-Premise 或 Private Cloud 環境下 **Kubernetes 與 Apache Airflow 的 HA** 為設計核心, +透過多層次的 HA 機制,確保平台在任一元件或節點失效時,仍可持續提供服務。 + +整體HA架構可分為四個層級: + +- **平台入口層(Platform Ingress HA)** + 使用 Keepalived + HAProxy 提供虛擬 IP(VIP)與流量入口HA。 + +- **容器平台層(Kubernetes HA)** + Kubernetes Control Plane 採用多 Master 架構,確保叢集控制能力不中斷。 + +- **工作流程層(Airflow on Kubernetes)** + Airflow 元件以 Pod 形式運行,透過 Kubernetes 調度與自我修復能力達成服務高可用。 + +- **狀態與資料層(Stateful Services HA)** + Metadata Database 採用 PostgreSQL + Patroni,並使用獨立 Etcd 作為分散式共識(DCS)。 + +``` +┌─────────────────────────────────────────────────┐ +│ Layer 1: 平台入口層 (Ingress HA) │ +│ VIP + Keepalived + HAProxy │ +│ → 消除流量入口單點故障 │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ Layer 2: 容器平台層 (Kubernetes HA) │ +│ Multi-Master + K8s Etcd │ +│ → 消除集群控制平面單點故障 │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ Layer 3: 工作流程層 (Airflow on K8s) │ +│ Scheduler + API Server + Worker Pods │ +│ → 透過 K8s 實現服務自動恢復 │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ Layer 4: 狀態與資料層 (Stateful Services HA) │ +│ PostgreSQL + Patroni + Patroni Etcd │ +│ → 資料庫自動 Failover │ +└─────────────────────────────────────────────────┘ +``` + +### **整體架構** +```mermaid +graph TB + %% ===== 外部使用者 ===== + User[用戶 / 運維人員] + + %% ===== Layer 1: Ingress HA ===== + subgraph L1["Layer 1: 平台入口層"] + VIP[VIP: 10.10.0.83] + subgraph HAProxy_Cluster["HAProxy + Keepalived"] + F01[doris-f01Keepalived + HAProxy] + F02[doris-f02Keepalived + HAProxy] + F03[doris-f03Keepalived + HAProxy] + end + end + + %% ===== Layer 2: K8s HA ===== + subgraph L2["Layer 2: 容器平台層"] + subgraph K8s_Masters["Kubernetes Control Plane"] + M1[Master 1API + Controller + Scheduler] + M2[Master 2API + Controller + Scheduler] + M3[Master 3API + Controller + Scheduler] + end + subgraph K8s_Etcd["K8s Etcd Cluster"] + KE1[etcd:2379] + KE2[etcd:2379] + KE3[etcd:2379] + end + end + + %% ===== Layer 3: Airflow ===== + subgraph L3["Layer 3: 工作流程層"] + subgraph Airflow["Airflow on Kubernetes"] + AF_Web[Webserver Pod] + AF_Sch[Scheduler Pod] + AF_Wrk[Worker Pods] + end + end + + %% ===== Layer 4: Database HA ===== + subgraph L4["Layer 4: 狀態與資料層"] + subgraph PG_Cluster["PostgreSQL + Patroni"] + PG1[Primarydoris-f01] + PG2[Replicadoris-f02] + PG3[Replicadoris-f03] + end + subgraph Patroni_Etcd["Patroni Etcd (DCS)"] + PE1[etcd:12379] + PE2[etcd:12379] + PE3[etcd:12379] + end + end + + %% ===== 連接關係 ===== + User --> VIP + VIP --> F01 & F02 & F03 + F01 & F02 & F03 --> M1 & M2 & M3 + M1 & M2 & M3 --> KE1 & KE2 & KE3 + M1 & M2 & M3 --> Airflow + Airflow --> PG_Cluster + PG_Cluster -.-> Patroni_Etcd + + %% ===== 樣式 ===== + classDef layer1 fill:#e1f5ff,stroke:#01579b + classDef layer2 fill:#f3e5f5,stroke:#4a148c + classDef layer3 fill:#e8f5e9,stroke:#1b5e20 + classDef layer4 fill:#fff3e0,stroke:#e65100 + + class L1 layer1 + class L2 layer2 + class L3 layer3 + class L4 layer4 +``` + +--- +## 3. 平台入口HA設計 + +**Keepalived + HAProxy** + +設計原則 +- VIP 為唯一入口 +- 任一節點失效時,自動切換入口主機 +- 流量入口 HA 與後端服務角色解耦 + + +**VRRP 選舉概念** +```mermaid +graph TD + Client --> VIP + VIP -->|Priority 100| doris-f01 + VIP -.->|Priority 90| doris-f02 + VIP -.->|Priority 80| doris-f03 +``` +- Keepalived 透過 VRRP 協定競選 Master +- 僅 Master 節點綁定 VIP +- Backup 節點持續監聽並待命 + +**流量轉發流程** +```mermaid +graph TD + Client --> VIP + VIP --> Keepalived + Keepalived --> HAProxy + HAProxy --> Backend +``` +- HAProxy 在所有節點上運行 +- 只有持有 VIP 的節點實際接收流量 +- VIP 切換 ≠ 服務重啟 + +--- +## 4. Kubernetes Control Plane HA + +設計說明 +- Kubernetes Control Plane 為整體平台基礎 +- 使用 Kubernetes 內建 Etcd +- 與 Patroni Etcd 完全隔離 + +### **Kubernetes Control Plane HA架構** +```mermaid +graph TD + %% ===== Client ===== + User[User / Operator] + + %% ===== K8s API VIP ===== + API_VIP(VIP: K8s API) + User --> API_VIP + + %% ===== Kubernetes Control Plane HA ===== + subgraph CP["Kubernetes Control Plane HA"] + direction TB + + %% --- API Servers --- + subgraph APIS["API Servers"] + API1[kube-apiserver] + API2[kube-apiserver] + API3[kube-apiserver] + end + + %% --- Controllers & Scheduler --- + subgraph CTRL["Controller & Scheduler"] + CM1[kube-controller-manager] + SCH1[kube-scheduler] + CM2[kube-controller-manager] + SCH2[kube-scheduler] + CM3[kube-controller-manager] + SCH3[kube-scheduler] + end + + %% --- etcd State Backend --- + subgraph ETCD["etcd Cluster (State Backend)"] + KE1[etcd] + KE2[etcd] + KE3[etcd] + end + end + + %% ===== Connections ===== + API_VIP --> API1 + API_VIP --> API2 + API_VIP --> API3 + + API1 --> KE1 + API2 --> KE2 + API3 --> KE3 + + CM1 --> API1 + SCH1 --> API1 + + CM2 --> API2 + SCH2 --> API2 + + CM3 --> API3 + SCH3 --> API3 +``` + +邊界原則 +- Kubernetes Etcd: + - 僅供 K8s 使用 + - Port:2379 / 2380 +- Patroni Etcd: + - 僅供 PostgreSQL HA 使用 + - Port:12379 / 12380 +- 嚴禁共用 Etcd +--- +## 5. Airflow on Kubernetes HA設計 + +| 元件 | 角色 | 運行方式 | HA 機制 | +|-----|------|---------|---------| +| **Webserver** | 提供 Web UI 與 REST API | Deployment (2 replicas) | K8s 自動重建 | +| **Scheduler** | 解析 DAG、產生 Task Instance | Deployment (2 replicas) | Leader Election | +| **Triggerer** | 處理 Deferrable Operator | Deployment (1-2 replicas) | K8s 自動重建 | +| **Worker** | 執行 Task | KubernetesExecutor: 動態 Pod
CeleryExecutor: StatefulSet | 短生命週期 | +--- +## 6. Metadata Database HA設計 + +PostgreSQL + Patroni + Etcd + +設計重點 +- Metadata DB 為 Airflow 核心依賴 +- 使用 Patroni 管理 PostgreSQL 角色 +- Etcd 作為 DCS(Distributed Configuration Store) + +### **Airflow Metadata Database HA架構** + +```mermaid +graph TD + User[User / Client] + + %% ===== 流量入口 ===== + VIP(VIP 10.10.0.83) + User --> VIP + + subgraph ENTRY["Ingress HA (Keepalived + HAProxy)"] + subgraph F01["doris-f01"] + K1[Keepalived] + H1[HAProxy] + end + subgraph F02["doris-f02"] + K2[Keepalived] + H2[HAProxy] + end + subgraph F03["doris-f03"] + K3[Keepalived] + H3[HAProxy] + end + end + + VIP --> K1 --> H1 + + %% ===== Kubernetes ===== + subgraph K8S["Kubernetes Cluster"] + API[K8s API Server] + subgraph AIRFLOW["Airflow Components"] + AF_API[Airflow API Server] + AF_SCH[Airflow Scheduler] + AF_WK[Airflow Workers Pods] + end + end + + H1 --> AF_API + AF_SCH --> AF_WK + + %% ===== DB ===== + subgraph DB["PostgreSQL HA (Patroni)"] + PG1[Primary] + PG2[Replica] + PG3[Replica] + end + + %% ===== DCS ===== + subgraph DCS["Patroni Etcd (DCS)"] + E1[Etcd f01] + E2[Etcd f02] + E3[Etcd f03] + end + + AF_API --> DB + AF_SCH --> DB + + PG1 --> PG2 + PG1 --> PG3 + + PG1 -.-> DCS + PG2 -.-> DCS + PG3 -.-> DCS +``` + +--- +## 7. 故障情境與自動切換流程 + +- Kubernetes Control Plane Failover + - kube-apiserver 為無狀態服務,可由多個實例同時提供服務 + - 當單一 Master 節點失效時,其餘 Master 持續提供 API 能力 + - Controller Manager 與 Scheduler 透過 Leader Election 機制自動切換 + +- 平台入口(VIP)Failover +```mermaid +sequenceDiagram + participant Client + participant F01 as doris-f01 + participant F02 as doris-f02 + + Client->>F01: 存取 VIP + Note over F01: Keepalived 停止 + F02->>F02: 接手 VIP + Client->>F02: 流量自動切換 +``` + +- Metadata Database Failover + - Patroni 偵測 Primary 不可用 + - Etcd 重新選舉 Leader + - Replica 升級為新 Primary + - Airflow 自動重新連線 +- Airflow 服務連續性 + - Airflow Scheduler 與 API Server 為無狀態服務,可由 Kubernetes 自動重建 + - Worker Pod 為短生命週期任務執行單元,單一 Pod 失效不影響整體流程 + - Metadata Database 透過 Patroni 提供自動 Failover + - 各層 HA 機制相互獨立,避免連鎖性故障 +--- + +## 8. 總結 + +本架構透過多層HA設計,確保 Apache Airflow 及 Kubernetes 的運作: +- 可自動容錯 +- 可長期穩定運行 +