MON Migration Runbook

本文件提供跨資料中心 Ceph 遷移的 MON / control-plane 切換手冊,聚焦於 quorum 驗證、Rook external mode client endpoint coordination、ceph-csi behavior,以及 KubeVirt / VM 在 MON endpoint 變更期間的驗證。

關於遷移策略的分析與決策依據,請參考 Solutions Overview。關於 OSD bulk data migration 的詳細步驟,請參考 OSD Migration Runbook。關於場景與架構概述,請參考 主文件

High-Level Flow

flowchart LR
    subgraph CEPH["Ceph cluster"]
        direction LR
        A[備份設定與健康檢查] --> B[新增 dc2 MON 節點]
        E[移除 dc1 MON 節點]
        F[最終健康確認]
    end

    subgraph K8S["K8s cluster"]
        direction LR
        C["⏳ 等待 Rook Operator<br/>自動同步 ConfigMap"] -.1-2分鐘.-> D[驗證 csi-rbdplugin logs]
        H[驗證 VM I/O 正常]
    end

    B --> C
    D --> H
    H --> E
    E --> F

    style CEPH fill:#e6ffed,stroke:#2f855a,stroke-width:1.5px
    style K8S fill:#e8f1ff,stroke:#3b82f6,stroke-width:1.5px
    style C fill:#fff4e6,stroke:#ed8936,stroke-width:2px

預期耗時:8-10 分鐘

核心原則

  1. Add-Before-Remove Strategy
    • 先新增 dc2 MON 節點,擴大 quorum(暫時從 3 增至 4、5、6)
    • 驗證新 MON 節點在 quorum 中且穩定
    • 確認 client 端已使用新 endpoint 後,再移除 dc1 MON 節點
  2. Quorum Safety
    • MON quorum 需多數決(3 個中至少 2 個,5 個中至少 3 個)
    • 新增 MON 時,quorum 容錯能力提升(暫時可容忍更多節點失效)
    • 移除 MON 前必須確認剩餘節點數仍能滿足 quorum 要求
  3. Client Endpoint Coordination
    • Rook-Ceph external mode 透過 rook-ceph-mon-endpoints ConfigMap 與 Secret 傳遞 MON 地址
    • rook-ceph-config / mon_host 必須反映新 MON endpoint 集合
    • Rook Operator Auto-Sync (v1.14+): 當 Ceph cluster 的 MON 拓撲變更時,Rook operator 會自動更新 ConfigMaps,無需手動編輯
    • 切換策略:先加後減,再提早切到 dc2-only(先讓 client 吃到 dc1 + dc2,再於 Ceph 側移除前先清理 dc1 endpoints)
    • 兩者(rook-ceph-mon-endpointsrook-ceph-config / mon_host)都應先完成 dc2-only 收斂,再執行 Ceph cluster 的 dc1 MON 移除
    • ceph-csi / librbd 通常能透過 Ceph 的 monmap gossip 學到新 MON;ConfigMap 變更則主要影響 pod 啟動或 reconnect 時讀取到的 ceph.conf
    • 若自動更新失效,則採用分批重啟 CSI pods 而非全面重啟
  4. 最小化業務影響
    • MON failover 通常在數秒內完成,對 RBD I/O 的影響極小
    • KubeVirt VM 通常能透過 librbd 內建的 MON failover 機制自動恢復
    • 重點驗證:VM 在 MON endpoint 切換期間是否持續正常 I/O
    • Timeout 調整屬於環境特定的驗證項目,非預設強制要求

2. Rook-Ceph External Mode / KubeVirt Notes

Rook-Ceph External Mode 連線架構

在本場景中,KubeVirt VM 透過以下路徑連線至 Ceph cluster:

KubeVirt VM (guest OS)
  ↓
virt-launcher pod (KubeVirt operator)
  ↓
ceph-csi (csi-rbdplugin DaemonSet)
  ↓
Rook-Ceph external mode (ConfigMap & Secret)
  ↓
Ceph MON endpoints (external Ceph cluster)

Rook-Ceph External Mode ConfigMap / Secret

Rook external mode 使用以下兩個 Kubernetes resources 傳遞 Ceph cluster 連線資訊:

  1. rook-ceph-mon-endpoints ConfigMap
    • 包含 MON endpoint 地址清單
    • 格式範例:mon1=10.1.1.1:6789,mon2=10.1.1.2:6789,mon3=10.1.1.3:6789
    • 更新策略:先擴充為 dc1 + dc2,驗證 client 正常後,再收斂為 dc2-only
  2. rook-ceph-config ConfigMap
    • 包含 ceph.conf 的 client-side 配置
    • 其中 mon_host 欄位必須反映新 MON endpoint 集合
    • 更新策略:先擴充為 dc1 + dc2,驗證 client 正常後,再收斂為 dc2-only
    • 驗證重點:確認 mon_host 先包含新 MON endpoint 集合,之後再收斂為僅剩 dc2

ceph-csi Behavior

  • 動態學習路徑csi-rbdplugin 內的 librbd client 通常會透過 Ceph 的 monmap gossip 學到新 MON endpoints
  • ConfigMap 角色rook-ceph-mon-endpoints / rook-ceph-config 主要影響 pod 啟動或 reconnect 時讀到的 ceph.conf
  • 驗證方式:檢查 csi-rbdplugin pod logs 與 pod 內連線行為,確認目前連線已穩定落在預期的 MON endpoint 集合
  • 失效處置:若自動更新失效,則採用分批重啟 CSI pods(避免同時重啟所有 pods 造成短暫服務中斷)

KubeVirt VM 影響評估

MON endpoint 切換期間 VM 行為

  1. Short MON Failover Disturbance
    • librbd(Ceph RBD client library)內建 MON failover 機制
    • 當 current MON 失效或地址變更時,librbd 會自動嘗試連線至其他 MON
    • 典型 failover 時間:數秒內完成
  2. I/O Continuity
    • 只要至少一個 MON 可達,RBD I/O 能繼續正常運作
    • MON 主要負責 cluster map 發布與 auth,不參與 data path
    • 驗證重點:VM 在 MON endpoint 切換期間是否持續正常 I/O
  3. Timeout Tuning (Optional)
    • 若環境對 MON failover 延遲敏感(如關鍵交易系統),可考慮調整 rbd_default_timeout
    • 此為環境特定驗證項目,非預設強制要求
    • 建議先執行 pilot test,觀察實際 failover behavior 再決定是否調整

監控重點

  • Ceph 層面
    • ceph mon stat:確認 MON quorum 狀態
    • ceph -s:確認 cluster health 與 MON election 狀態
  • Rook / ceph-csi 層面
    • 檢查 rook-ceph-mon-endpoints ConfigMap 是否已更新
    • 檢查 rook-ceph-configmon_host 欄位
    • 檢視 csi-rbdplugin pod logs,確認 MON connection 正常
  • KubeVirt / VM 層面
    • VM guest OS 的 disk I/O latency(如透過 iostat 或應用監控)
    • KubeVirt virt-launcher pod 的 resource usage
    • 若有應用層 SLA,確認 latency 與 throughput 仍在可接受範圍

3. Detailed MON Migration Runbook

本節詳述 MON migration 的完整執行步驟,包含 Ceph 端 add-before-remove 與 client endpoint 提前切到 dc2-only 的 coordination checkpoints。

🔄 Change Flow

本 runbook 推薦使用以下流程進行 MON migration。此流程依賴 Rook operator v1.14+ 的自動同步功能,無需手動編輯 ConfigMaps。

執行步驟

  1. Step 0:執行前置檢查
  2. Step 1:Ceph 端 host add 和 placement 配置(ceph orch host add + ceph orch apply mon/mgr
  3. Step 2:等待 Rook operator 自動同步 + 驗證 csi-rbdplugin & VM I/O(新 6 MON endpoints)
  4. Step 3:Disable dc1 MON daemons(逐步縮減 placement 至 dc2-only)
  5. Step 4:等待 Rook operator 自動同步 + 驗證 csi-rbdplugin(dc2-only endpoints)
  6. Step 5:Remove dc1 MONs from Cluster(ceph orch host rm

預期總耗時:8-10 分鐘

環境需求

  • Rook operator 版本 ≥ v1.14
  • auto-sync 功能已啟用(預設為啟用)

若需完整手動控制

  • 若 Rook operator 未自動更新 ConfigMaps(logs 無相關記錄)或版本 < v1.14
  • 需要精細控制 client endpoint 切換時序
  • 環境複雜或有多個 Kubernetes cluster 連線至同一 Ceph cluster
  • 此時可執行手動 ConfigMap 更新進行介入

Step 0: Pre-Migration Backup and Validation

目標:確保 MON quorum 健康、備份關鍵配置、記錄 baseline

Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
MON Quorum 健康
遷移前 cluster 必須 HEALTH_OK,確認 quorum 完整
Ceph admin 節點
ceph mon stat
ceph quorum_status -f json-pretty
預期結果:ceph mon stat + ceph quorum_status -f json-pretty - quorum = 3/3 且 HEALTH_OK
備份 Rook ConfigMap / Secret
保留還原點,遷移失敗時可快速恢復
K8s admin 節點
export BACKUP_DATE=$(date +%Y%m%d)
kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o yaml > /backup/rook-ceph-mon-endpoints.${BACKUP_DATE}.yaml
kubectl -n rook-ceph get configmap rook-ceph-config -o yaml > /backup/rook-ceph-config.${BACKUP_DATE}.yaml
kubectl -n rook-ceph get secret rook-ceph-mon -o yaml > /backup/rook-ceph-mon-secret.${BACKUP_DATE}.yaml
預期結果:ls -l /backup/rook-ceph-*.yaml - 3 份備份檔案存在且可讀
記錄當前 MON endpoints
作為後續對比與 rollback 基準
K8s admin 節點
kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}'
kubectl -n rook-ceph get configmap rook-ceph-config -o jsonpath='{.data.ceph\.conf}' \| grep mon_host
預期結果:kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}' - 已記錄 dc1 endpoint 清單
確認 dc2 MON 候選主機已就緒
確保 cephadm 已可管理 dc2 節點,且 location metadata 正確
Ceph admin 節點
ceph orch host ls
ceph orch ls mon -f yaml
預期結果:ceph orch host ls - mon-dc2-01/02/03 出現在 host 清單且 metadata 正確
記錄 Client Workload 清單
確認受影響的 csi-rbdplugin pods 與 KubeVirt VM
K8s admin 節點
kubectl -n rook-ceph get pods -l app=csi-rbdplugin
kubectl get vmi -A
預期結果:kubectl -n rook-ceph get pods -l app=csi-rbdplugin + kubectl get vmi -A - Pod/VM 清單已完整記錄

Step 1: Add dc2 MONs to Cluster

目標:將 dc2 MON 候選主機加入 orchestrator,並指定 MON/MGR 角色到所有 6 個節點

cephadm note: 本 Step 分兩階段執行:

  1. 使用 ceph orch host add 逐一將 dc2 節點(mon-dc2-01 / 02 / 03)加入 orchestrator host 清單
  2. 使用 ceph orch apply monceph orch apply mgr 指定完整 6 台節點的 placement
Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
dc2 節點尚未在 orchestrator 清單中
ceph orch host ls 確認,避免重複添加,IP / hostname 正確
Ceph admin 節點
ceph orch host add mon-dc2-01 192.168.1.14
ceph orch host add mon-dc2-02 192.168.1.15
ceph orch host add mon-dc2-03 192.168.1.16
預期結果:ceph orch host ls - 6 台節點全出現在 orchestrator 清單
6 台節點全在 host 清單中
ceph orch host ls 確認,apply placement 前所有節點必須就緒
Ceph admin 節點
ceph orch apply mon --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
sleep 120
ceph orch apply mgr --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
sleep 60
預期結果:ceph mon stat - quorum = 6,且 dc2 三台 MON 皆在 quorum
Rollback:ceph orch apply mon --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03"
Rollback:ceph orch apply mgr --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03"

Step 2: Wait for Rook Operator Auto-Sync and Verify I/O

目標:等待 Rook operator 自動同步 ConfigMaps(反映 6 MON 拓撲),並確認 csi-rbdplugin 與 VM I/O 正常

⚠️ Rook Operator Auto-Sync Note (v1.14+): 當 Ceph cluster MON 拓撲變更後,rook-ceph-mon-endpointsrook-ceph-configmon_host自動同步更新。 先確認 operator logs 是否已自動更新;若已更新,跳過手動介入部分。

Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
Step 1 quorum = 6 已確認
Rook operator 在 MON 拓撲變更後 1-2 分鐘自動同步 ConfigMap
K8s admin 節點
等待 1-2 分鐘後
kubectl logs -n rook-ceph deployment/rook-ceph-operator --tail=50 \| grep -i mon
kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}'
預期結果:kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}' - 包含 6 個 MON endpoints(dc1 + dc2)
Rollback:kubectl -n rook-ceph edit configmap rook-ceph-mon-endpoints
確認 rook-ceph-config mon_host 已更新
csi-rbdplugin reconnect 時讀取 ceph.conf,mon_host 必須含 dc1 + dc2
K8s admin 節點
kubectl -n rook-ceph get configmap rook-ceph-config -o jsonpath='{.data.ceph\.conf}' \| grep mon_host
預期結果:kubectl -n rook-ceph get configmap rook-ceph-config -o jsonpath='{.data.ceph\.conf}' \| grep mon_host - mon_host 含 dc1 + dc2 地址
Rollback:kubectl -n rook-ceph edit configmap rook-ceph-config
確認 csi-rbdplugin 已吸收新 MON endpoints K8s admin 節點
kubectl -n rook-ceph logs -l app=csi-rbdplugin --tail=50 \| grep -i mon
預期結果:kubectl -n rook-ceph logs -l app=csi-rbdplugin --tail=50 \| grep -i mon - logs 顯示已連線新 MON endpoints
Rollback:kubectl -n rook-ceph delete pod <pod>(分批,每批間隔 30s)
csi-rbdplugin 可連線至 Ceph cluster
確認 client 端已可 reach dc2 MON
K8s admin 節點 → exec 進 csi-rbdplugin pod
kubectl -n rook-ceph exec -it <csi-rbdplugin-pod> -- bash
ceph -s --conf=/etc/ceph/ceph.conf --keyring=/etc/ceph/keyring
預期結果:ceph -s --conf=/etc/ceph/ceph.conf --keyring=/etc/ceph/keyring - 正常回傳且無連線錯誤
VM I/O 正常(關鍵驗證)
MON endpoint 切換期間 VM 不應有 I/O 中斷
VM guest OS
virtctl console <vm-name> -n <namespace>
dd if=/dev/zero of=/tmp/test.dat bs=1M count=100
iostat -x 1 5
預期結果:dd + iostat -x 1 5 - VM I/O 正常,無錯誤與明顯延遲
Rollback:ceph orch apply mon --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03"
Rollback:ceph orch apply mgr --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03"

Step 3: Disable dc1 MON Daemons

目標:逐步縮減 MON placement 至 dc2-only,移除 dc1 MON daemons

策略:分三 Phase 逐個移除 dc1 MON(6→5→4→3),每 Phase 驗證 quorum 穩定後再進行下一步

Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
csi-rbdplugin 已切到新 endpoints(Step 2 gate 通過)
確認 client-side 已穩定,quorum 目前 = 6
Ceph admin 節點
Phase 1 — 移除 mon-dc1-01
ceph orch apply mon --placement="mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
ceph orch apply mgr --placement="mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
sleep 120
預期結果:ceph mon stat + ceph health detail - quorum = 5 且 HEALTH_OK
Rollback:ceph orch apply mon --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
Rollback:ceph orch apply mgr --placement="mon-dc1-01 mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
Phase 1 quorum = 5 已確認
ceph mon stat 驗證,確保穩定後再繼續
Ceph admin 節點
Phase 2 — 移除 mon-dc1-02
ceph orch apply mon --placement="mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
ceph orch apply mgr --placement="mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
sleep 120
預期結果:ceph mon stat + ceph health detail - quorum = 4 且 HEALTH_OK
Rollback:ceph orch apply mon --placement="mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
Rollback:ceph orch apply mgr --placement="mon-dc1-02 mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
Phase 2 quorum = 4 已確認
ceph mon stat 驗證,確保穩定後再繼續
Ceph admin 節點
Phase 3 — 移除 mon-dc1-03(完全切至 dc2)
ceph orch apply mon --placement="mon-dc2-01 mon-dc2-02 mon-dc2-03"
ceph orch apply mgr --placement="mon-dc2-01 mon-dc2-02 mon-dc2-03"
sleep 120
預期結果:ceph mon stat + ceph health detail - quorum = 3(全為 dc2)且 HEALTH_OK
Rollback:ceph orch apply mon --placement="mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"
Rollback:ceph orch apply mgr --placement="mon-dc1-03 mon-dc2-01 mon-dc2-02 mon-dc2-03"

Step 4: Verify Rook Operator Auto-Sync (dc2-only)

目標:等待 Rook operator 自動同步 ConfigMaps 以反映 dc2-only MON 拓撲,並確認 csi-rbdplugin 正常

Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
Step 3 quorum = 3(dc2-only)已確認
Rook operator 在 MON 拓撲變更後 1-2 分鐘自動同步 ConfigMap
K8s admin 節點
等待 1-2 分鐘後
kubectl logs -n rook-ceph deployment/rook-ceph-operator --tail=50 \| grep -i mon
kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}'
預期結果:kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}' - 僅包含 dc2 MON endpoints(3 個)
Rollback:kubectl -n rook-ceph edit configmap rook-ceph-mon-endpoints
確認 rook-ceph-config mon_host 已更新為 dc2-only
ceph.conf mon_host 必須只含 dc2 地址
K8s admin 節點
kubectl -n rook-ceph get configmap rook-ceph-config -o jsonpath='{.data.ceph\.conf}' \| grep mon_host
預期結果:kubectl -n rook-ceph get configmap rook-ceph-config -o jsonpath='{.data.ceph\.conf}' \| grep mon_host - mon_host 僅含 dc2 地址
Rollback:kubectl -n rook-ceph edit configmap rook-ceph-config
VM I/O 正常(關鍵驗證)
MON endpoint 切換期間 VM 不應有 I/O 中斷
VM guest OS
virtctl console <vm-name> -n <namespace>
dd if=/dev/zero of=/tmp/test.dat bs=1M count=100
iostat -x 1 5
預期結果:dd + iostat -x 1 5 - VM I/O 正常,無錯誤與明顯延遲
Rollback:ceph orch apply mon --placement="mon-dc2-01 mon-dc2-02 mon-dc2-03 mon-dc1-03"
Rollback:ceph orch apply mgr --placement="mon-dc2-01 mon-dc2-02 mon-dc2-03 mon-dc1-03"

Step 5: Remove dc1 MONs from Cluster

目標:確認 dc1 無其他 daemon 後,從 orchestrator 中移除 dc1 主機

Precheck
(檢查項目 / 使用指令 / 原因)
Action
(節點 / 指令)
Postcheck
(預期結果 / Rollback)
Step 4 gate 通過,csi-rbdplugin 連線至 dc2-only
確認 dc1 節點無其他非 MON daemon(如 OSD / MGR)
Ceph admin 節點
ceph orch ps \| grep mon-dc1
確認無殘留 daemon 後:
ceph orch host rm mon-dc1-01
ceph orch host rm mon-dc1-02
ceph orch host rm mon-dc1-03
預期結果:ceph orch host ls + kubectl -n rook-ceph get configmap rook-ceph-mon-endpoints -o jsonpath='{.data.data}' - dc1 主機已移除且 endpoint 為 dc2-only

相關連結