iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
IT Operation

地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理系列 第 15 篇

Day 15|Proxmox VE 雙節點 HA:Virtualization Station 上的 QDevice

  • 分享至 

  • xImage
  •  

PVE 雙節點 QDevice 架構圖

前言:高可用性(HA)是一場講究過半的投票機制

在現代虛擬化架構中,多數人對「高可用性(High Availability, HA)」的直覺是,只要有兩台伺服器,一台倒了另一台接手就好。但實際在分散式叢集裡,雙節點是天生存在結構性缺陷的設定。

本篇記錄了在真實場域中,如何將原本隱含隱患的雙節點 Proxmox VE 叢集,透過 QNAP NAS Virtualization Station 上的輕量 Debian VM 引入第三票(QDevice / QNetd),並透過四場實兵演練(混沌測試),驗證「共用儲存與仲裁者同在一台 NAS」架構下的真實行為與 RTO。

今天的完整開源程式碼位於:pve-qdevice-on-qnap。


一、動手加票前:先盤點叢集裡的三顆隱形地雷

動手建置 QDevice 前,依照慣例進行基礎盤點。執行 pvecm nodes 列出兩台節點,畫面看起來是個健康的雙節點叢集,但查看 pvecm status 卻發現了矛盾:

  • Expected votes: 3
  • Total votes: 2

原來叢集原本有第三台節點(N150 小主機),先前已被手動關機,但仍留在 corosync.conf 的清單中。

三票要過半(Quorum)需要兩票。兩台在線時剛好過半,一旦掉任何一台,剩下的一台只有 1 票,立刻失去法定人數。這個叢集表面看起來亮綠燈,實質上完全沒有任何容錯餘裕。 而 pvecm nodes 只列出在線節點,完全掩蓋了這個風險。

深入檢查後,一共排查出三件「不會在 Web UI 首頁跳警告,卻會讓 HA 在關鍵時刻癱瘓」的問題:

檢查項目 觀察到的現象 實質影響與風險
票數一致性pvecm status vs pvecm nodes Expected votes: 3在線節點僅 2 台 一台已關機節點仍在算票。叢集無任何容錯空間,掉任一台即全毀。
HA 服務狀態ha-manager status 某常開節點標註 old timestamp - dead?時間停在三個月前 該節點的 pve-ha-lrm 與 pve-ha-crm 曾被手動 mask。節點看似在線,但不參與 HA 投票與 Fence,上面跑的 HA 資源被徹底凍結。
磁碟放置位置檢查 VM 的虛擬磁碟 Storage 某 HA VM 系統碟在 NFS,但 EFI 磁碟留在另一台節點的 local-lvm 該 VM 無論在哪一台節點都無法正常漂移或開機,觸發搬移兩次失敗後直接進入 error 狀態。

排雷處置

  1. 清理無效節點:已關機的 N150 小主機是刻意離線的低功耗機器。使用 pvecm delnode 將其正式移出叢集。(注意:未來若該機器要重回叢集,必須先清空它本機的 Corosync 設定再加回,否則開機會嘗試與舊叢集同步而產生衝突)。
  2. 解除 HA Mask:解除該節點的 service mask 後,pve-ha-crm 與 watchdog 即刻載入,重新參與 Fencing 機制,凍結的資源也順利解凍。
  3. 收攏虛擬磁碟:將遺落在 local-lvm 的 EFI 磁碟搬移至 NFS 共用儲存。HA 資源的每一顆磁碟(包含 EFI 與 TPM 狀態碟)都必須在共用儲存上。

二、票數如何計算:仲裁者與儲存同在一台 NAS 的架構抉擇

雙節點的本質問題

兩票要過半就是兩票。一旦任一節點斷線,剩下的一台只有 1 票,無法取得過半法定人數(Quorum),PVE 的 HA 守護進程為了避免發生腦裂(Split-Brain),會透過 Watchdog 直接將存活節點重開機(Self-Fence),導致全叢集服務中斷。

解法:QDevice 第三票

PVE 支援外部仲裁裝置(QDevice)。在叢集外的第三方主機上運行 corosync-qnetd,叢集內各節點運行 corosync-qdevice 與其通訊獲取選票。

將 QDevice 部署在 QNAP TS-464(Virtualization Station)上一台 1 vCPU / 1 GiB RAM 的極輕量 Debian VM,這台 NAS 同時也是叢集 NFS 共用儲存(Day 13/14 所述架構)。

仲裁矩陣與失效情境分析

情境 存活選票 法定人數(Quorum) 叢集行為與結果
全數正常 節點 A、節點 B、QDevice(3 票) 2 叢集正常運作
NAS 重開機(QDevice 暫時離線) 節點 A、節點 B(2 票) 2 仍具備法定人數,HA 正常(VM 暫時卡在 NFS I/O)
節點 A 故障(QDevice 在線) 節點 B、QDevice(2 票) 2 仍具備法定人數,節點 A 遭 Fence 後,其 VM 於節點 B 重新拉起
節點 A 故障 + NAS 同時重開 節點 B(僅剩 1 票) 2 失去法定人數。 節點 B 觸發 Watchdog 自行重開 Fence,全數停擺
兩台節點正常,手動停用 QDevice 節點 A、節點 B(2 票) 2 正常運作,證明平日 QDevice 為備用輔助票

📌 核心架構思考:為什麼把第三票放在 NAS 上?

第四列顯示了此架構的致命弱點:NAS 維護窗口等同於「單節點故障即全倒」的脆弱窗口。
但在許多場域的實務配置中,幾乎所有 VM 都依賴 NAS 提供的 NFS 儲存或儲存設備。當 NAS 重開時,所有 VM 本來就會因為 I/O 阻塞而凍結。將仲裁者綁定在 NAS 上,是讓第三票與叢集本來就依賴的單點「共用同一個失效網域」,而不是在架構中徒增另一台隨時可能單獨故障的小實體機。

PVE Fencing 機制補充

當運行 HA 資源的節點失去法定人數時,pve-ha-lrm 會失去資源鎖(Lock)。系統預設的軟體 Watchdog(softdog,若有伺服器 BMC 則可使用硬體 watchdog)會在約 60 秒後強制重啟節點。這是保護資料一致性的刻意設計,確保共用儲存不會被兩台節點同時寫入而造成損壞。


三、QDevice 虛擬機規格與生命週期設計

規格定義檔可參考 qnetd-vm.md,重點配置如下:

  1. 靜態 IP 與橋接網路:
    直接橋接到 PVE 節點所處的私有管理網段,配置靜態 IP。節點設定檔僅認 IP,嚴禁依賴 DHCP 或 DNS 解析,避免 NAS 重開時因本機 DNS 尚未就緒而無法通訊。
  2. 自動啟動原則設為「永遠啟動(Always Run)」,延遲設為 0:
    QNAP Virtualization Station 預設為「保持前次狀態」。若維護前 QDevice 曾被手動暫停,重開後將無法自動上線。QDevice 必須比叢集節點更早(或同時)回來。
  3. 不建立快照、不排程備份:
    此 VM 為完全的「無狀態(Stateless)」機器。其核心只是轉發證書與票數,損毀時只需 10 分鐘重新建立一台並執行 pvecm qdevice setup 即可,不應占用備份資源。
  4. 校正硬體時鐘與 RTC:
    Virtualization Station 提供給 VM 的硬體時鐘為 Host 本地時間(Local Time),而 Debian 預設將 RTC 視為 UTC,開機會造成時鐘快 8 小時,需待 NTP 校正。NAS 重開時外網或本機 NTP 往往尚未連通,因此需設定:
    timedatectl set-local-rtc 1
    
  5. 安全與連線最小化:
    corosync-qnetd 監聽 TCP 5403,配置 nftables 防火牆僅允許兩台 PVE 節點連入。金鑰交換時需短暫開啟 root SSH 登入,初始化完畢後立刻關閉。

四、自動化腳本架構

為了簡化部署、平日監控與演練觀測,編寫了三支核心 Shell Script:

pve-qdevice-on-qnap/
├── setup.sh     # 叢集自動化加入 QDevice(含相依套件安裝與防呆檢查)
├── check.sh     # 叢集健康度與法定人數巡檢腳本(回傳標準 Exit Code)
└── record.sh    # 演練黑盒子紀錄工具(配合 systemd-run 收集觀測數據)

1. setup.sh:具備冪等性(Idempotent)的初始化工具

初期版本單純以 pvecm nodes 計算節點數,在先前的故障環境下誤判為 2 節點而繼續執行。新版改為直接解析 /etc/pve/corosync.conf:

  • 安全防呆:設定檔節點數與在線節點數不一致時立即中斷,非雙節點狀態拒絕執行。
  • 解決 SSH Known Hosts 驗證錯誤:腳本跨節點安裝 corosync-qdevice 時,改用 PVE 自帶的 /etc/pve/nodes/<node>/ssh_known_hosts 與 HostKeyAlias 避免主機金鑰報錯。
  • 排除 Node ID 0 誤判:掛載 QDevice 後,pvecm nodes 會出現一筆 ID 為 0 的虛擬節點,避免二次重跑時將其誤計為第 3 台實體節點。

2. check.sh:監控與告警的核心哨兵

將繁複的 pvecm status 與 ha-manager status 濃縮為監控系統可理解的單一指標。定義三種 Exit Code:

  • rc=0 (Healthy):三票到齊,HA 運作正常。
  • rc=1 (Degraded):具有 Quorum,但已失去冗餘能力。涵蓋四種亞健康狀態:
    1. 丟失任一票數(2/3 票)。
    2. 尚未配置 QDevice。
    3. 任一節點的 HA LRM Timestamp 過舊(服務被 mask 或無回應)。
    4. 存在處於 error 狀態的 HA VM。
  • rc=2 (Critical):失去 Quorum,叢集面臨自毀風險。

💡 維運策略:監控告警在指標為 1(Degraded)時就必須即刻通知工程師,絕不能等到 2(全倒)才響鈴。

3. record.sh:演練時的黑盒子紀錄器

演練故障時往往伴隨 SSH 中斷與連線跳脫。透過 systemd-run 將 record.sh 丟入背景執行,每 2 秒記錄時間戳記、check.sh 回傳碼、當前票數與特定 HA VM 狀態,以精準量測 RTO。


五、四場實戰測試演練

在一台專用的測試用小 VM(512 MiB RAM,磁碟掛載於 NFS)內執行每秒一次的 dsync 磁碟寫入,以精確捕捉磁碟 I/O 凍結與故障轉移時間窗。

詳細紀錄請見 drills.md。

演練項目 實施方式 預期反應 實測觀測紀錄
1. NAS 重開 透過 QuTS hero 介面重新開機儲存兼仲裁者 NAS Quorum 維持 Yes,check.sh 轉為 rc=1,NFS 上的 VM 寫入暫停,待 NFS 恢復後自動解凍,本機磁碟 VM 不受影響。 Quorum 全程維持 Yes。NFS 中斷 8 分 07 秒,VM 寫入空窗共 593 秒(含 NFSv4.1 Grace Period)。QDevice 在 NFS 恢復 2 分 39 秒後上線。
2. 節點 A 斷電 於節點 A 執行 sysrq o 強制硬關機(非正常 Shutdown) 節點 B 維持 Quorum,節點 A 上的 HA 資源經 Watchdog Fence 後於節點 B 重新開機,耗時約 2 分鐘。 Quorum 維持 Yes。測試 VM 於 3 分鐘後在節點 B 成功啟動,VM 內磁碟寫入空窗共 205.8 秒(含開機自身耗時 26 秒)。
3. 節點 A 斷電+ NAS 重開 觸發 NAS 重開,確認 NFS 斷線瞬間立刻對節點 A 執行斷電 節點 B 失去 Quorum,約 60 秒後節點 B 觸發 Watchdog 自行重開,全域停擺直到 NAS 與 QDevice 復原。 符合預期。節點 A 斷電後 51 秒,節點 B 因失去 Quorum 遭 Watchdog 強制重啟。直到 NAS 與 QDevice 開機完成,節點 B 重新獲得 Quorum 並拉起 VM,整體中斷時間 11 分 15 秒。
4. 手動關閉 QDevice 在 QDevice VM 內部執行 poweroff,隨後由 QuTS hero 重新啟動 Quorum 維持 Yes,check.sh 轉為 rc=1,測試 VM 運作完全不受影響。 關機 5 秒內 check.sh 轉為 1(票數 2/3)。重開後 VM 核心載入 9 秒 qnetd 就緒,再過 9 秒狀態完全復原(rc=0)。

關鍵深潛分析

1. 故障移轉為什麼需要 3 分鐘?(演練 2 時間軸拆解)

原本預期 2 分鐘的切換時間,實測延長到了 3 分鐘,時間花在兩把鎖的釋放:

[00:00] 節點 A 斷電 (sysrq o)
   │
[00:03] 節點 B 的 corosync 宣告 token 逾時
   │
[00:08] 節點 B 與 QDevice 組成新 Quorum(法定人數從未中斷)
   │
[01:57] 節點 B 的 pve-ha-crm 取得 Master 鎖(因 A 剛好是 Master,需等過期)
   │
[02:57] 節點 B 取得 節點 A 的 Agent 鎖(確認節點 A 徹底被 Fence)
   │
[03:00] 測試 VM 於節點 B 開始 Booting
   │
[03:26] VM 內部產生第一筆 dsync 寫入

📌 維運提醒:規劃 HA 業務的 RTO 時,若故障節點恰巧為 HA Master,必須將「Master 鎖過期」加上「Agent 鎖過期」時間算入,基準線應設為 3 分鐘 + VM 自身開機時間。此外,sysrq o 斷電後主機無法以 WoL 喚醒,演練前務必確保現場有專人可手動按下電源按鈕。

2. NAS 維護重開的真實細節(演練 1 與 3 總結)

  • VM 暫停 vs 冷重啟:重開 NAS 時若直接在 QuTS hero 確認,Virtualization Station 會預設將 VM 暫停(Suspend),復原後 VM 時鐘會大幅落後。最佳作法是先在管理介面正常關閉 QDevice VM 再重開 NAS,開機時依賴 Local RTC 與自動開機機制冷啟動。
  • 儲存好了,仲裁還沒好:NFS 服務約 8 分鐘復原,但 Virtualization Station 需再過 2~3 分鐘才會將 VM 帶起。在這幾分鐘內,雖然儲存可用,但因缺少法定人數,PVE 仍無法啟動服務。
  • NFS Grace Period:NFSv4.1 伺服器重啟後,客戶端需等待約 105 秒的保留恢復期(Grace Period)才能重新寫入,這段時間必須排入維護窗口預估中。

⚠️ 絕對禁忌:pvecm expected 1

在演練 3 的情境下,單節點失去 Quorum 時,輸入 pvecm expected 1 可強行解除節點凍結。但除非你親自在機房拔掉另一台節點的電源線,否則嚴禁使用! 若另一台節點其實還活著,兩台節點各自獨立掛載 NFS 寫入同一顆虛擬磁碟,將造成毀滅性的資料損壞(腦裂)。


六、儲存架構與整體佈局

PVE 實踐 HA 的基石是共用儲存或快速複寫。原本設想採取雙層儲存:

  • 關鍵 HA 服務:放在 NAS NFS 上,實現節點無縫接管。
  • 極致效能服務:放在節點本機 ZFS,透過 pvesr 定期非同步複寫。

但盤點後發現兩台節點安裝時均採用了預設的 LVM-thin,而 pvesr 只支援 ZFS。在不進行節點重灌的前提下,目前全數 VM 均運行於 NAS NFS 上。這也讓的架構更具單一性:NAS 本身就是所有 VM 的 SPOF(單一故障點),因此將 QDevice 放在同台 NAS 上並不會創造新的單點脆弱性。


快速實作指南

1. 部署 QDevice

在 QNAP Virtualization Station 建立輕量 Debian VM 並安裝 corosync-qnetd 後,登入節點 A 執行:

git clone https://github.com/ivanusto/pve-qdevice-on-qnap && cd pve-qdevice-on-qnap
./setup.sh 192.168.x.<QDevice_IP>

# 驗證狀態(預期 rc=0, votes=3/3, quorate=Yes)
./check.sh; echo "Exit Code: $?"

2. 演練時記錄

在存活節點(節點 B)透過 systemd-run 啟動背景紀錄:

systemd-run --unit=drill2 /root/pve-qdevice-on-qnap/record.sh drill2 vm:<Test_VM_ID>

# 演練結束後停止並查看完整數據日誌
systemctl stop drill2
cat /root/drills/drill2.log

3. 解除 QDevice

若未來節點架構變更,可隨時在任一 PVE 節點優雅移除第三票:

pvecm qdevice remove

結語與下集預告

高可用性不只是把叢集串起來看著儀表板亮綠燈。透過深層盤點與四場實戰故障演練,應該對於雙節點搭配 QDevice 的極限有更多的了解,也能夠知道失效窗口以及真實切換時鐘延遲(RTO)大概是怎樣的情形。

當確認了所有核心 VM 均座落於 NAS NFS 共用儲存並加固後,接下來最核心的防線,就是老生常談的備份與還原機制囉。

Day 16 將探討:Proxmox VE 備份與還原實戰,利用 HDP for Business beta 建立多版本排程、保留原則與全災難還原演練。


專案索引與參考資料


上一篇
Day 14|儲存規劃與路徑實測:RAID 60 與 RAIDZ2 試算,SSD、NFS、iSCSI 載入時間解析
下一篇
Day 16|Proxmox VE 備份與還原:HDP for Business Beta 的排程、保留與還原演練
系列文
地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言