Logo

Personal Ops Runbook

Personal runbook covering infrastructure operations for Cloud, Kubernetes, OpenStack, and Ceph environments. Includes deployment and teardown procedures, node management, cluster monitoring setup, and incident response workflows compiled from day-to-day operational work. Intended strictly for personal reference — configurations and scripts are environment-specific and not guaranteed to work as-is elsewhere.

RUNBOOK — Fix Ceph Bug #70390 (BlueStore ESB) trên PUBC09

mClock client-first + Remove/Redeploy OSD giữ ID + Thay đĩa hỏng

Cụm đích: PUBC09 (Ceph Squid, cephadm-managed, pool PUBC09-NVME-01 size 2 / min_size 1).
Mục tiêu: redeploy các OSD do Squid tạo để loại bỏ metadata shared-blob hỏng (#70390), trong khi ưu tiên client tối đa (workload backup tạo/xoá snap hàng ngày rất nặng).
Tham chiếu bug: https://tracker.ceph.com/issues/70390


0. NGUYÊN TẮC AN TOÀN BAO TRÙM (đọc trước, áp suốt)

  1. HEALTH_OK trước khi bắt đầu. Tuyệt đối không remove/redeploy OSD khi cluster còn HEALTH_ERR/degraded/inconsistent. Trên size 2 không có lớp đệm thứ ba.
  2. PG 2.1f8 inconsistent (nếu còn) phải xử lý dứt điểm trước khi chạy bất kỳ bước remove nào.
  3. Một OSD tại một thời điểm. Hết trọn vẹn một OSD (về active+clean) mới sang con kế. Điều này vừa an toàn size 2, vừa đảm bảo khớp ID tất định (chỉ 1 slot destroyed mỗi lúc).
  4. Thay đĩa = luôn --replace. Không bao giờ xoá hẳn (crush remove + osd rm + auth del) — xoá hẳn trả ID về pool trống → bị bốc số nhỏ nhất (đúng lỗi osd.4→0 đã gặp).
  5. destroyed là entry logic trong CRUSH — tách rời khỏi khay vật lý, tên /dev/sdX, và việc node sống/chết. Nó chỉ giữ chỗ số ID.
  6. Backfill phải BẬT trong lúc drain. Nếu nobackfill/norecover đang set thì drain sẽ đứng im.
  7. Nghiệm thu fix bug = trên mỗi OSD mới: bluestore_elastic_shared_blobs=false OSD fsid đã đổi.

PHẦN A — mCLOCK: ƯU TIÊN CLIENT (làm MỘT LẦN trước cả đợt)

A0. Bối cảnh cơ chế (vì sao cấu hình như dưới)

  • mClock chia 3 bucket: client / background_recovery / background_best_effort.
  • Phân loại operation (quan trọng):
  • background_recovery = chỉ degraded object recovery (an toàn dữ liệu).
  • background_best_effort = backfill (misplaced) + snap trim + scrub + PG deletion.
  • ⚠️ Khi reweight/redeploy, data chạy là misplaced → backfill → best_effort. Snaptrim của bạn cũng nằm trong best_effort → hai thứ chen chung một bucket.
  • res = sàn đảm bảo (không phải trần). lim = trần (0 = không giới hạn). wgt = chỉ chia phần dư trên reservation.
  • Squid: res/lim là TỶ LỆ 0.0–1.0 của OSD IOPS capacity. (Quincy/lab cũ dùng IOPS tuyệt đối — đừng bê số qua lại.)
  • Khi mClock active (kể cả custom), các *_sleep (osd_snap_trim_sleep, osd_recovery_sleep) bị khoá về 0 → không dùng sleep để ghìm snaptrim được; phải dùng concurrency knob.

A1. Dọn cấu hình lệch + kiểm tra capacity

# Gỡ profile lẻ của osd.31 (đang high_recovery_ops, lệch khỏi cả cluster)
ceph config rm osd.31 osd_mclock_profile

# Capacity NVMe-through-Ceph ~46k-69k IOPS là BÌNH THƯỜNG (không phải thủ phạm).
# Nhưng sequential bandwidth đang để default SATA 1200 MiB/s -> nâng cho NVMe:
ceph config set osd osd_mclock_max_sequential_bandwidth_ssd 3221225472   # ~3GB/s, đặt theo spec NVMe thật

A2. Chuyển profile custom — ĐÚNG THỨ TỰ (custom TRƯỚC, value SAU)

⚠️ Khi còn ở built-in profile (balanced…), mọi osd_mclock_scheduler_* set vào bị revert về default của profile (báo success nhưng không lưu). Phải profile=custom trước thì value mới ăn.

# 1. Custom TRƯỚC
ceph config set osd osd_mclock_profile custom
ceph config get osd osd_mclock_profile          # = custom

# 2. RỒI set value (giờ mới có hiệu lực)
# Client: sàn 0.5, không trần, weight cao
ceph config set osd osd_mclock_scheduler_client_res 0.5
ceph config set osd osd_mclock_scheduler_client_wgt 4
ceph config set osd osd_mclock_scheduler_client_lim 0
# Degraded recovery (an toàn dữ liệu): đừng bóp quá chặt
ceph config set osd osd_mclock_scheduler_background_recovery_res 0.1
ceph config set osd osd_mclock_scheduler_background_recovery_lim 0.4
ceph config set osd osd_mclock_scheduler_background_recovery_wgt 1
# Best-effort (backfill + snaptrim): VAN CHÍNH bảo vệ client
ceph config set osd osd_mclock_scheduler_background_best_effort_res 0.1
ceph config set osd osd_mclock_scheduler_background_best_effort_lim 0.3
ceph config set osd osd_mclock_scheduler_background_best_effort_wgt 1

Vì sao client_res = 0.5 chứ không 0.7: res là sàn, để quá cao ép best_effort luôn nhường → snaptrim không kịp drain → queue phình → lại sinh slow. client_lim 0 đã cho client dùng tới 100% khi rảnh.

A3. Ghìm song song bằng các knob ngoài mClock (vẫn hiệu lực)

# Snaptrim: hạ song song (mặc định 2x2=4 op/OSD -> 1x1=1)
ceph config set osd osd_pg_max_concurrent_snap_trims 1
ceph config set osd osd_max_trimming_pgs 1

# Backfill: trên prod đang override=true + max_backfills=12 + recovery_max_active=24 (RẤT MẠNH).
# Chọn 1 trong 2 hướng:

# Hướng khuyến nghị (client-first, ghìm cứng song song):
ceph config set osd osd_max_backfills 1
ceph config set osd osd_recovery_max_active_ssd 1
# (giữ override=true để 2 dòng trên có hiệu lực)

# Hướng "thuần mClock" (sạch hơn nhưng tin hoàn toàn vào capacity):
# ceph config set osd osd_mclock_override_recovery_settings false

A4. Verify (2 góc nhìn)

ceph config dump | grep mclock_scheduler                 # góc DB: đủ 9 dòng đã set
ceph tell osd.4 config show | grep mclock_scheduler      # góc runtime: wgt=4, best lim=0.3, recovery res=0.1...
ceph tell osd.5 config show | grep mclock_scheduler      # kiểm tra thêm vài OSD

Điều chỉnh động khi vận hành: giờ cao điểm hạ best_effort_lim 0.2–0.3; off-peak nâng 0.5 cho backfill/snap drain nhanh rồi hạ lại. Theo dõi nguồn slow:
ceph daemon osd.<id> dump_historic_slow_ops (client hay snaptrim?), ceph -s (SLOW_OPS / snaptrim backlog).


PHẦN B — REMOVE / REDEPLOY MỘT OSD (đĩa còn tốt — ca fix bug)

Dùng cho việc redeploy OSD do Squid tạo để xoá metadata ESB hỏng. Đĩa còn sống → drain an toàn, không mất data.
<id> = OSD đang xử lý; <host> = node chứa nó; <dev> = đĩa của nó.

Cách 1 (KHUYẾN NGHỊ) — orchestrator một lệnh

Bước Lệnh Gate PASS (mới đi tiếp)
Tiền kiểm ceph -s ; ceph health detail HEALTH_OK, all active+clean, không inconsistent/degraded
Ghi nhận ./map-osd-disk.sh \| grep "osd.<id> " ; ceph osd tree \| grep "osd.<id> " Ghi lại đĩa + weight gốc (~13.97260)
ok-to-stop ceph osd ok-to-stop osd.<id> Trả lời OK
Replace ceph orch osd rm <id> --replace --zap "Scheduled OSD(s) for removal"
Theo dõi ceph orch osd rm status STATE=done, PGS=0
Verify destroyed ceph osd tree \| grep -E 'osd.<id>\|destroyed' thấy <id> ... destroyed (ID không biến mất)
Redeploy managed → tự tạo lại; unmanaged → ceph orch daemon add osd <host>:/dev/<dev>
Verify ID ceph osd tree \| grep "osd.<id> " ; ceph orch ps <host> --daemon-type osd up, đúng ID cũ, container ID mới + AGE nhỏ
Restore weight ceph osd crush reweight osd.<id> <weight_gốc> weight đúng trị gốc
Chờ clean ceph -s lại active+clean toàn bộ

Cách 2 — manual từng bước (nếu cần kiểm soát từng nhịp)

ceph osd set noout
ceph osd crush reweight osd.<id> 0                 # drain
# CHỜ: ceph -s hết misplaced/backfilling + PG trên osd.<id> = 0 (ceph osd df)
ceph osd safe-to-destroy osd.<id>                  # phải "safe to destroy"
ceph orch daemon stop osd.<id>                     # CHỜ STATUS=down (osd tree)
ceph osd destroy <id> --yes-i-really-mean-it       # -> destroyed, GIỮ ID
ceph orch daemon rm osd.<id> --force
ceph orch device zap <host> /dev/<dev> --force     # đối chiếu ĐÚNG đĩa trước khi zap!
ceph orch daemon add osd <host>:/dev/<dev>         # nuốt ID destroyed
ceph osd crush reweight osd.<id> <weight_gốc>      # nếu vào weight 0
# CHỜ active+clean trước khi sang OSD kế

KHÔNG dùng chuỗi cũ out → crush remove → osd rm → auth del → daemon rm: nó xoá hẳn ID → add lại nhảy số.
ceph osd destroy thay cho cả crush remove + osd rm + auth del, giữ ID ở destroyed.

Nghiệm thu fix bug (BẮT BUỘC cho mỗi OSD mới)

ceph config get osd bluestore_elastic_shared_blobs        # = false
ceph tell osd.<id> config show | grep elastic_shared_blobs # OSD mới = false
ceph-volume lvm list <id>                                  # fsid PHẢI khác fsid cũ (chứng minh mkfs mới)

Vì sao redeploy là bắt buộc: metadata ESB hỏng nằm trong RocksDB/BlueStore on-disk. Tắt flag chỉ bảo vệ OSD mới tạo. --zap xoá sạch BlueStore + mkfs lại với flag=false = vứt bỏ tận gốc metadata hỏng; data lành backfill từ replica về.


PHẦN C — THAY ĐĨA HỎNG (giữ ID) — cho vận hành sau này

Cùng cơ chế destroyed, khác ở chỗ đĩa đã chết → không drain/zap được.

# 1. Đĩa hỏng -> replace, GIỮ ID. Bỏ --zap (đĩa chết không zap nổi), thêm --force nếu OSD down không drain
ceph orch osd rm <id> --replace --force
ceph osd tree | grep -E 'osd.<id>|destroyed'      # "<id> ... destroyed"

# 2. (size 2) Ceph tự re-replicate từ bản sao NGAY khi OSD bị out.
#    CHỜ ceph -s về active+clean (khôi phục redundancy) rồi mới thao tác vật lý.

# 3. DC rút đĩa hỏng, cắm đĩa MỚI (khay nào cũng được, miễn ĐÚNG HOST)

# 4. Xác định đĩa mới (đừng đoán theo /dev/sdX hay khay):
ceph orch device ls <host> --refresh              # đĩa mới = Available=Yes
lsblk -o NAME,SERIAL,SIZE                          # khớp serial đĩa DC vừa lắp

# 5. Tạo lại OSD -> nuốt ID destroyed
#    - Cluster 1 OSD/đĩa: managed tự tạo, HOẶC add tay:
ceph orch daemon add osd <host>:/dev/disk/by-id/<serial>
#    - Cluster NHIỀU OSD/đĩa hoặc DB/WAL tách riêng: PHẢI để spec managed dựng (xem D3), KHÔNG add tay

# 6. Verify
ceph osd tree | grep osd.<id>                     # up, đúng ID, trên đĩa mới
ceph osd crush reweight osd.<id> <weight_gốc>     # nếu cần

PHẦN D — THAM CHIẾU NHANH

D1. Khác biệt theo VERSION (đừng nhầm lab Quincy vs prod Squid)

Việc Squid (prod PUBC09) Quincy (lab)
mClock res/lim Tỷ lệ 0.0–1.0 IOPS tuyệt đối (số nguyên; 0.5 báo strict_si_cast error)
Khoá auto-deploy ceph orch set-unmanaged osd.<name> / set-managed Sửa YAML unmanaged: true/false rồi ceph orch apply -i
Tên service ở orch ls ceph orch ls osd osd.<name> (có tiền tố osd.) giống

Phần remove/destroy/zap/add giống nhau giữa hai version.

D2. Ba cách gắn OSD & khả năng kiểm soát ID

Cách Ép ID tùy ý? Giữ ID cũ? Stray?
orch osd rm --replace → redeploy (qua destroyed) Không
orch daemon add osd Không (bốc số trống nhỏ nhất) Chỉ nếu ID đang destroyed Không
ceph-volume lvm create --osd-id Thường có; trên cephadm hay fail (Failed to connect to bus)

Kết luận: trên cephadm, không có đường thủ công sạch để ép ID tùy ý. Muốn kiểm soát ID → dùng trạng thái destroyed. Cần ép ID đặc biệt (nắn ID lệch) → dùng spec osd_id_claims, không phải ceph-volume tay.

D3. unmanaged + spec nhiều OSD/đĩa

  • ceph orch daemon add osd host:/dev/X = 1 đĩa → 1 OSD, bỏ qua spec (không biết osds_per_device: 2).
  • Cluster có 2 OSD/đĩa hoặc DB/WAL riêng → phải bật lại managed để cephadm dựng đúng spec, không add tay.
  • Bật lại managed sẽ tóm mọi đĩa trống khớp spec → chỉ bật khi chắc không có đĩa trống ngoài ý muốn.

D4. Bảy điều đã chốt về destroyed / thay đĩa

  1. Đĩa mới nuốt đúng ID destroyed nếu chỉ 1 slot destroyed/host tại thời điểm đó; nhiều slot → làm tuần tự hoặc osd_id_claims.
  2. Node đầy khay vẫn thay được: destroyed là logic trong CRUSH, không chiếm khay; rút đĩa hỏng giải phóng khay.
  3. Node down khi có slot destroyed → không sao; trạng thái lưu ở mon, bền qua down/up.
  4. DC cắm đĩa vào khay khác → vẫn được; Ceph chỉ cần đúng device, đúng host.
  5. /dev/sdX đổi sau reboot → không hỏng OSD đã tạo (định danh qua LVM UUID); tên kernel chỉ quan trọng lúc add → luôn device ls --refresh hoặc dùng /dev/disk/by-id/.
  6. Spec 2 OSD/đĩa + add tay → không tạo đủ 2; phải để spec managed dựng.
  7. --replace dùng cho cả redeploy (đĩa tốt) lẫn thay đĩa hỏng; cái giữ ID là destroyed, không phải "cùng đĩa".

D5. Dọn dẹp & bảo mật

ceph osd unset noout                 # gỡ SAU KHI xong cả đợt
# Nếu từng scp admin keyring xuống node OSD để test -> XOÁ đi (bảo mật):
#   rm -f /etc/ceph/ceph.client.admin.keyring /etc/ceph/*.keyring   (trên node OSD)

CHECKLIST TỔNG (mỗi OSD)

[ ] cluster HEALTH_OK, không inconsistent (PG 2.1f8 đã sạch)
[ ] mClock custom đã verify (Phần A)  chỉ làm 1 lần đầu đợt
[ ] ghi đĩa + weight gốc của OSD
[ ] ok-to-stop OK
[ ] ceph orch osd rm <id> --replace --zap
[ ] osd rm status = done, PGS = 0
[ ] osd tree = destroyed (ID còn)
[ ] redeploy -> up, ĐÚNG ID, container mới
[ ] NGHIỆM THU: elastic_shared_blobs=false + fsid mới
[ ] restore weight
[ ] CHỜ active+clean -> mới sang OSD kế
[ ] (cuối đợt) unset noout