| @@ -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 判斷延遲<br>Failover 速度下降 | | |||||
| | **網路抖動** | 誤判節點故障<br>不必要的 Failover | | |||||
| | **故障排查** | 需跨節點檢查<br>定位問題困難 | | |||||
| | **依賴增加** | 網路成為關鍵依賴<br>單點故障風險上升 | | |||||
| **詳細方案差異:** | |||||
| - 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 隔離配置。 | |||||
| --- | |||||
| @@ -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)<br>Port `12390` (Peer) | `/var/lib/postgresql` (DB)<br>`/var/lib/etcd-patroni` (Etcd) | | |||||
| | **doris-f02** | Primary / Replica (動態) | Port `8008` | Port `12389` (Client)<br>Port `12390` (Peer) | `/var/lib/postgresql` (DB)<br>`/var/lib/etcd-patroni` (Etcd) | | |||||
| | **doris-f03** | Primary / Replica (動態) | Port `8008` | Port `12389` (Client)<br>Port `12390` (Peer) | `/var/lib/postgresql` (DB)<br>`/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 權重較高)。 | |||||
| @@ -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 <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 <<EOF | sudo tee /etc/modules-load.d/k8s.conf | |||||
| overlay | |||||
| br_netfilter | |||||
| EOF | |||||
| sudo modprobe overlay | |||||
| sudo modprobe br_netfilter | |||||
| ``` | |||||
| ### 🔹 sysctl 設定 | |||||
| 1. net.ipv4.ip_forward=1:啟用 IPv4 轉發 | |||||
| 2. net.bridge.bridge-nf-call-iptables=1:啟用橋接流量的 iptables 處理 | |||||
| ```shell | |||||
| cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf | |||||
| net.bridge.bridge-nf-call-iptables=1 | |||||
| net.ipv4.ip_forward=1 | |||||
| EOF | |||||
| sudo sysctl --system | |||||
| ``` | |||||
| --- | |||||
| ## 📌 2. 安裝 containerd(所有節點) | |||||
| 1. Containerd 是一個標準化的、核心的Container Runtime | |||||
| 2. 負責管理容器生命週期、並讓容器「跑起來」的軟體 | |||||
| ### 🔹 安裝 containerd | |||||
| ```shell | |||||
| sudo apt update | |||||
| sudo apt install -y containerd | |||||
| ``` | |||||
| ### 🔹 建立預設設定: | |||||
| ```shell | |||||
| sudo mkdir -p /etc/containerd | |||||
| sudo containerd config default | sudo tee /etc/containerd/config.toml | |||||
| ``` | |||||
| ### 🔹 啟用 SystemdCgroup: | |||||
| 1. Cgroup : Linux用來限制及分配資源的工具 | |||||
| 2. Kubelet 預設使用 systemd 作為 Cgroup driver。 | |||||
| 3. 需確保 Containerd 也使用 systemd,否則會導致不穩定。 | |||||
| ```shell | |||||
| sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml | |||||
| ``` | |||||
| ### 🔹 載入設定&設定開機啟動: | |||||
| ```shell | |||||
| sudo systemctl restart containerd | |||||
| sudo systemctl enable containerd | |||||
| ``` | |||||
| --- | |||||
| ## 📌 3. 安裝 Kubernetes(所有主機) | |||||
| ### 🔹 新增 repository | |||||
| ```shell | |||||
| sudo apt-get update | |||||
| sudo apt-get install -y apt-transport-https ca-certificates curl | |||||
| curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo apt-key add - | |||||
| echo 'deb https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list | |||||
| sudo apt-get update | |||||
| ``` | |||||
| ### 🔹 安裝 kubeadm / kubectl / kubelet | |||||
| 1. **Kubeadm**:官方提供的 集群快速啟動工具 (只在建置時用)。 | |||||
| 1. 證書管理 (PKI Certificates):Kubernetes 的組件之間通訊都需要加密(HTTPS)。Kubeadm 會自動生成並分發 CA 根證書、API Server 證書、Kubelet 證書等。這在以前手動做是非常痛苦且容易出錯的。 | |||||
| 2. 生成核心組件配置 (Manifests):它會自動產生 API Server, Controller Manager, Scheduler 和 Etcd 的 YAML 檔案,並以 Static Pod 的形式在 Master 節點上運行。 | |||||
| 3. 節點加入 (Bootstrap Tokens):它提供了一套簡單的 Token 機制,讓 Worker 節點只需要執行一行指令就能加入集群,並自動完成 TLS 認證。 | |||||
| 4. kubeadm 主要負責最後這兩個關鍵步驟: | |||||
| 1. kubeadm init (只在 Master / Control Plane 執行) | |||||
| - 檢查系統環境(Pre-flight check)。 | |||||
| - 生成證書 (CA, API server certs...)。 | |||||
| - 生成 kubeconfig 文件 (/etc/kubernetes/admin.conf)。 | |||||
| - 啟動 Control Plane 組件 (Etcd, API Server...)。 | |||||
| - 產出: 最後會吐出一行 kubeadm join ... 的指令給您。 | |||||
| 2. kubeadm join (在所有 Worker Node 執行) | |||||
| - Worker 節點拿著 Token 向 Master 報到。 | |||||
| - Master 驗證後,發給 Worker 專屬的證書。 | |||||
| - Worker 節點正式納入管理,準備接客(跑 Pod)。 | |||||
| 5. Kubeadm 不做的事: | |||||
| 1. 不負責安裝環境依賴:它不會裝 Docker/Containerd、也不會關 Swap等等。 | |||||
| 2. 不負責安裝 CNI 網絡插件:kubeadm init 跑完後,集群雖然起來了,但在安裝 CNI (如 Calico, Flannel) 之前,CoreDNS 都不會運作,節點狀態會是 NotReady。 | |||||
| 2. **Kubectl**:給管理員用的「指令工具」,用來對集群下達命令 | |||||
| 1. 發號施令:輸入指令(如 kubectl get pods, kubectl apply -f ...)。 | |||||
| 2. 翻譯官:它會把輸入的指令,轉換成標準的 REST API 請求,發送給 Kubernetes 的大腦 (API Server)。 | |||||
| 3. **Kublet**:運行在所有節點上的「代理人」,負責指揮 Containerd 啟動容器,並向 Master 匯報狀態 | |||||
| 1. 接單:它會一直監聽 Master (API Server) 發來的指令。 | |||||
| 2. 執行:收到指令後,命令自己節點上的Containerd去下載鏡像、啟動容器。 | |||||
| 3. 匯報:它會定期向 Master 匯報:「我還活著,容器也都健康」。 | |||||
| ```shell | |||||
| sudo apt-get install -y kubelet kubeadm kubectl | |||||
| ``` | |||||
| ### 🔹鎖定版本: | |||||
| 1. apt-mark hold : 防止在執行 `apt-get upgrade` 更新系統時,不小心自動升級了 K8s 元件。 | |||||
| 2. K8s 的升級通常需要特定的流程(先升級 Master 再升級 Node),自動升級會導致集群崩潰。 | |||||
| ```shell | |||||
| sudo apt-mark hold kubelet kubeadm kubectl | |||||
| ``` | |||||
| ### 🔹設定開機啟動: | |||||
| ```shell | |||||
| sudo systemctl enable kubelet | |||||
| ``` | |||||
| --- | |||||
| ## 📌 4. 初始化 Control Plane(第一台master) | |||||
| 初始化整個cluster的第一台master | |||||
| ### 🔹建立設定檔 | |||||
| ```shell | |||||
| sudo vi /kubeadm-config.yaml | |||||
| ``` | |||||
| ```yaml | |||||
| apiVersion: kubeadm.k8s.io/v1beta3 | |||||
| kind: ClusterConfiguration | |||||
| # ==================== 1. 集群基本資訊 ==================== | |||||
| kubernetesVersion: v1.30.14 # 請確保與安裝的 kubeadm 版本一致 | |||||
| controlPlaneEndpoint: "10.10.0.83:6444" # VIP:HAProxy端口 (所有節點透過此溝通) | |||||
| # ==================== 2. 網路設定 ==================== | |||||
| networking: | |||||
| podSubnet: "10.244.0.0/16" # Pod 網段 (Flannel 預設) | |||||
| serviceSubnet: "10.96.0.0/12" # Service 網段 (ClusterIP) default值 | |||||
| dnsDomain: cluster.local # default值 | |||||
| # ==================== 3. API Server 設定 ==================== | |||||
| apiServer: | |||||
| certSANs: # 憑證需包含的所有 IP/域名 | |||||
| - "10.10.0.83" # VIP (最重要!) | |||||
| - "10.10.0.85" # F01 IP | |||||
| - "10.10.0.87" # F02 IP | |||||
| - "10.10.0.89" # F03 IP | |||||
| - "127.0.0.1" | |||||
| extraArgs: | |||||
| authorization-mode: "Node,RBAC" # default值 | |||||
| --- | |||||
| # ==================== 4. 本機初始化設定 ==================== | |||||
| apiVersion: kubeadm.k8s.io/v1beta3 | |||||
| kind: InitConfiguration | |||||
| localAPIEndpoint: | |||||
| advertiseAddress: "10.10.0.85" # **當前節點 (F01) 的 IP** | |||||
| bindPort: 6443 # API Server 本機監聽 Port (default值) | |||||
| nodeRegistration: | |||||
| criSocket: unix:///var/run/containerd/containerd.sock # default值 建議保留 | |||||
| name: doris-f01 # 當前節點 Hostname 前面步驟已設定 保險起見這裡可以再設定一次 | |||||
| taints: # Master 污點 (不讓應用跑在 Master) default值 | |||||
| - effect: NoSchedule | |||||
| key: node-role.kubernetes.io/control-plane | |||||
| --- | |||||
| # ==================== 5. Kubelet 全域設定 ==================== | |||||
| apiVersion: kubelet.config.k8s.io/v1beta1 | |||||
| kind: KubeletConfiguration | |||||
| cgroupDriver: systemd # 關鍵!確保與 Containerd 一致 (default值 建議保留) | |||||
| ``` | |||||
| ```yaml | |||||
| apiVersion: kubeadm.k8s.io/v1beta3 | |||||
| kind: ClusterConfiguration | |||||
| # ==================== 基本信息 ==================== | |||||
| kubernetesVersion: v1.30.14 # K8s 版本,建議與 kubeadm 版本一致 | |||||
| # ==================== 控制平面 HA 配置 ==================== | |||||
| controlPlaneEndpoint: "10.10.0.83:6444" # VIP:HAProxy端口 | |||||
| # 所有節點將通過這個地址訪問 API Server | |||||
| # 這是 HA 的關鍵配置 | |||||
| # ==================== 網路配置 ==================== | |||||
| networking: | |||||
| podSubnet: "10.244.0.0/16" # Pod 網段,給 CNI 使用 | |||||
| # Calico/Flannel 會從這個範圍分配 Pod IP | |||||
| # 不要與現有網路衝突! | |||||
| serviceSubnet: "10.96.0.0/12" # Service 網段 (ClusterIP) | |||||
| # K8s 內部服務的虛擬 IP 範圍 | |||||
| # 預設值,一般不需要改 | |||||
| # ==================== API Server 配置 ==================== | |||||
| apiServer: | |||||
| certSANs: # 證書 Subject Alternative Names | |||||
| - "10.10.0.83" # VIP - 必須加入! | |||||
| - "10.10.0.85" # F01 IP | |||||
| - "10.10.0.87" # F02 IP | |||||
| - "10.10.0.89" # F03 IP | |||||
| # - "k8s-api.yourdomain.com" # 如果有 DNS 也可以加 | |||||
| extraArgs: # API Server 額外參數 | |||||
| bind-address: "0.0.0.0" # 監聽所有 IP (預設是 0.0.0.0) | |||||
| advertise-address: "10.10.0.85" # **重要**: 此節點對外宣告的 IP | |||||
| # F01 用 .85, F02 用 .87, F03 用 .89 | |||||
| secure-port: "6443" # API Server 實際監聽端口 | |||||
| # 避免與 HAProxy 的 6443 衝突 | |||||
| # ==================== etcd 配置 ==================== | |||||
| #etcd: | |||||
| # external: # 使用外部 etcd cluster | |||||
| # endpoints: # etcd 節點列表 | |||||
| # - 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 # etcd CA 證書 | |||||
| # certFile: /etc/kubernetes/pki/etcd/client.crt # etcd 客戶端證書 | |||||
| # keyFile: /etc/kubernetes/pki/etcd/client.key # etcd 客戶端私鑰 | |||||
| --- | |||||
| # ==================== 初始化配置 (僅第一個 master 需要) ==================== | |||||
| apiVersion: kubeadm.k8s.io/v1beta3 | |||||
| kind: InitConfiguration | |||||
| localAPIEndpoint: | |||||
| advertiseAddress: "10.10.0.85" # **此節點的 IP** (F01) | |||||
| bindPort: 6443 # API Server 監聽端口 | |||||
| nodeRegistration: | |||||
| criSocket: unix:///var/run/containerd/containerd.sock # 容器運行時 | |||||
| name: doris-f01 # 節點名稱 | |||||
| taints: # 污點,防止 Pod 調度到 master | |||||
| - effect: NoSchedule | |||||
| key: node-role.kubernetes.io/control-plane | |||||
| --- | |||||
| # ==================== Join 配置 (其他 master 加入時使用) ==================== | |||||
| apiVersion: kubeadm.k8s.io/v1beta3 | |||||
| kind: JoinConfiguration | |||||
| discovery: | |||||
| bootstrapToken: | |||||
| apiServerEndpoint: "10.10.0.83:6444" # VIP 地址 | |||||
| token: <token> # 從 kubeadm init 輸出獲取 | |||||
| caCertHashes: | |||||
| - "sha256:<hash>" # CA 證書 hash | |||||
| controlPlane: # 標記為 control plane 節點 | |||||
| localAPIEndpoint: | |||||
| advertiseAddress: "10.10.0.87" # **F02 的 IP** (F03 用 .89) | |||||
| bindPort: 6443 | |||||
| certificateKey: <key> # 證書加密 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 <token> \ | |||||
| --discovery-token-ca-cert-hash sha256:<hash> \ | |||||
| --control-plane --certificate-key <key> \ | |||||
| --apiserver-advertise-address=<F02或F03的IP> \ | |||||
| --apiserver-bind-port=6443 | |||||
| ``` | |||||
| add worker node: | |||||
| ```shell | |||||
| sudo kubeadm join 10.10.0.83:6444 --token <token> \ | |||||
| --discovery-token-ca-cert-hash sha256:<hash> | |||||
| ``` | |||||
| ### 🔹 設定 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 <token> \ | |||||
| --discovery-token-ca-cert-hash sha256:<hash> \ | |||||
| --control-plane --certificate-key <key> \ | |||||
| --apiserver-advertise-address=<F02或F03的IP> \ | |||||
| --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 <TOKEN> --discovery-token-ca-cert-hash sha256:<HASH> | |||||
| ``` | |||||
| 到master node上檢查節點: | |||||
| ```shell | |||||
| kubectl get nodes -o wide | |||||
| ``` | |||||
| @@ -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 | |||||
| ``` | |||||
| @@ -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<br>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 的運作: | |||||
| - 可自動容錯 | |||||
| - 可長期穩定運行 | |||||