| @@ -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 的運作: | |||
| - 可自動容錯 | |||
| - 可長期穩定運行 | |||