chundev
日期:2026-05-12
環境:Nutanix AOS 6.10.1.5、AHV 20230302.103014、Ubuntu 18.04 guest
把一台 VM 的 disk 從 SATA 換成 virtio-scsi,每台 downtime 約 15-60 秒(不是 hours,因為是 metadata-only clone 不真的搬資料)。
核心指令三步:vm.disk_create bus=scsi clone_from_vmdisk → vm.disk_delete disk_addr=sata.0 → vm.update_boot_device disk_addr=scsi.0。
關鍵注意:cluster 內有應用 quorum(DB / search / message queue)的 VM 要一台一台來,等 cluster 恢復 healthy 再動下一台。
詳見 前文:跨層除錯 Nutanix VM 偶發 read-only 與 virtio-scsi vs emulated SATA 深入。
簡言之:emulated SATA 在儲存層偶發慢的情境下會 hard reset link,這在 software-defined storage 上常造成 partial write 丟失 → ext4 corruption。換 virtio-scsi 從根本拆掉這個 over-reaction。
# 1. virtio_scsi 在 initramfs(開機初期就要有 driver 才能 mount root)
sudo lsinitramfs /boot/initrd.img-$(uname -r) | grep -iE 'virtio_scsi|virtio_blk'
# 期望:看到 virtio_scsi.ko + virtio_blk.ko
# 2. fstab 用 UUID/LVM(不能依賴 /dev/sd*)
cat /etc/fstab | grep -vE '^#|^$'
# 期望:/dev/disk/by-id/dm-uuid-LVM-... 或 /dev/disk/by-uuid/...
# 3. grub 用 lvmid 或 UUID
sudo grep '^set root' /boot/grub/grub.cfg | head -1
# 期望:set root='lvmid/...' 或 set root='hd0,gpt2'(UUID 模式)
# 4. 確認當下還是 SATA
lsblk
# 期望:sda 在 SATA bus(要看 /sys/block/sda/device/driver/ 指向 ata 才確定)
全綠才動,任一不符合都先補強(重編 initramfs 或改 fstab/grub)。
# === 變數準備 ===
VM=infominer-storage02
VMDISK_UUID=5248d62f-e309-4410-9745-975b9efc715e # 從 acli vm.get 抄
TS=$(date +%Y%m%d_%H%M%S)
# === Step 1:保存 baseline(救命用) ===
acli vm.get $VM > ~/${VM}-before-$TS.txt
# === Step 2:通知應用層 stop service(你自己處理) ===
# 視應用而定,例如 systemctl stop pm2-ubuntu
# === Step 3:graceful shutdown VM ===
acli vm.shutdown $VM
# 輪詢直到 state=kOff
until acli vm.get $VM | grep -q 'state: "kOff"'; do sleep 5; done
# === Step 4:建立新 SCSI vmdisk(atomic clone of 舊 SATA) ===
# Nutanix 內部是 metadata-only,2.5TB 也只要幾秒
acli vm.disk_create $VM bus=scsi clone_from_vmdisk=$VMDISK_UUID
# === Step 5:sanity check 兩顆 disk 都在 ===
acli vm.get $VM | grep -E 'addr|bus:|index:|vmdisk_uuid'
# 應該看到 sata.0 (舊) + scsi.0 or scsi.1 (新)
# === Step 6:刪舊 SATA disk(acli 要互動確認,pipe yes) ===
echo yes | acli vm.disk_delete $VM disk_addr=sata.0
# === Step 7:明確指定從新 SCSI disk 開機 ===
echo yes | acli vm.update_boot_device $VM disk_addr=scsi.0
# === Step 8:確認最終配置 ===
acli vm.get $VM | sed -n '/boot {/,/^ }/p'
# 應該看到 disk_addr: bus="scsi" index=0
# === Step 9:power on ===
acli vm.on $VM
until acli vm.get $VM | grep -q 'state: "kOn"'; do sleep 5; done
# === Step 10:guest 內驗證 ===
ssh $VM "ls -l /sys/block/sda/device/driver/ # → 應指向 virtio_scsi
mount | grep -E ' / | /boot' # → rw mount OK
sudo touch /tmp/test && echo OK"
# === Step 11:套 SCSI timeout 180s(防禦深度) ===
ssh $VM "
echo 180 | sudo tee /sys/block/sda/device/timeout
sudo tee /etc/udev/rules.d/99-storage-scsi-timeout.rules <<'EOF'
ACTION==\"add|change\", SUBSYSTEM==\"scsi\", ATTR{type}==\"0\", ATTR{vendor}==\"NUTANIX\", ATTR{timeout}==\"180\"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger --action=change --subsystem-match=scsi
"
# === Step 12:應用層服務啟動 + cluster healthy 驗證 ===
# 視應用而定
重點觀念:clone_from_vmdisk 是 metadata-only。2.5TB 跟 100GB 一樣快(幾秒),因為 storage 平台內部用 redirect-on-write,沒真的搬資料。
有些 VM 同時有 SATA + SCSI 兩顆 disk(例如歷史殘留)。要做的是只動 SATA 那顆:
# 看現況
acli vm.get $VM | grep -E 'bus:|index:|vmdisk_uuid'
# 假設:sata.0 = 200GB OS root, scsi.0 = 100GB data
# 從 SATA clone(不指定 index → 自動放下個可用 SCSI slot,會是 scsi.1)
acli vm.disk_create $VM bus=scsi clone_from_vmdisk=<sata-vmdisk-uuid>
# 刪舊 SATA
echo yes | acli vm.disk_delete $VM disk_addr=sata.0
# 明確指定 boot 從新 SCSI(記得是 scsi.1 不是 scsi.0)
echo yes | acli vm.update_boot_device $VM disk_addr=scsi.1
陷阱:如果不明確 set boot device,BIOS 可能從 scsi.0(原本的 data disk)試開,找不到 bootloader 就失敗。
如果 VM 是 cluster 成員(RethinkDB / ElasticSearch / Consul / RabbitMQ 等),絕對不要同時下兩台。
操作骨架(3-node cluster 範例):
for VM in node1 node2 node3; do
# 1. 改 VM bus
do_bus_change $VM
# 2. 等該 VM 應用層完全 rejoin cluster
wait_until_cluster_green # ElasticSearch: cluster health = green
# RabbitMQ: cluster_status partitions=[]
# Consul: members alive
# RethinkDB: client port LISTEN + cluster connected
# 3. 再進入下一台
done
各 cluster 的「healthy」訊號:
| Cluster | 檢查指令 | 健康訊號 |
|---|---|---|
| ElasticSearch | curl localhost:9200/_cluster/health |
status: green + number_of_nodes 不變 |
| RabbitMQ | rabbitmqctl cluster_status |
partitions: [] + running_nodes = 全部 |
| Consul | consul members |
所有 server alive |
| RethinkDB | ss -tln \| grep 28015 |
port LISTEN |
為什麼:分散式 cluster 同時下兩台 = quorum 喪失 = service unavailable + 可能 data inconsistency。
兩條路:
操作前用 PE UI 或 ncli 拍 snapshot:
ncli pd add-one-time-snapshot name=<PD-name>
若 VM 改完不正常,PE UI → Data Protection → Snapshot → Restore VM。
5-15 分鐘救回(會建一台 restored-<name> 的新 VM,把 NIC 換到原 IP 即可)。
acli vm.shutdown $VM
# 從快照拿 vmdisk_uuid(PE UI → snapshot detail)
acli vm.disk_create $VM bus=sata index=0 clone_from_vmdisk=<snapshot-vmdisk-uuid>
echo yes | acli vm.disk_delete $VM disk_addr=scsi.0
echo yes | acli vm.update_boot_device $VM disk_addr=sata.0
acli vm.on $VM
操作這天的紀錄(從 shutdown 到 power on):
| Disk size | Downtime |
|---|---|
| 100 GB | 12-21 秒 |
| 200 GB | 21 秒 |
| 700 GB | 1-4 分鐘(第一台 4 min 含 grace shutdown wait) |
| 2.5 TB | 17-25 秒 |
| 3 TB | 17 秒 |
Downtime 跟 disk size 無關(因為 clone 是 metadata-only),跟「graceful shutdown service 要花多久」相關。
應用層 rejoin cluster 才是大頭:
clone_from_vmdisk 是 metadata-only,幾 TB 跟幾 GB 一樣快,不要被 disk size 嚇到不敢做echo yes | acli vm.disk_delete ...,否則 stdin 一斷會死循環印 prompt接續閱讀(建議從上往下讀):