Khi nào cần live migration — và tại sao không phải cứ tắt VM là xong
Có những tình huống bắt buộc phải di chuyển VM mà không được tắt: host vật lý cần thay RAM, kernel update cần reboot, hoặc tải CPU trên một host đang quá cao trong khi host kia nhàn rỗi. Tắt VM → chuyển → bật lại nghe có vẻ đơn giản, nhưng với database server hay web server đang phục vụ traffic, downtime dù 30 giây cũng là vấn đề thật sự.
KVM live migration sinh ra để xử lý đúng chuyện này. Cơ chế hoạt động khá thú vị: RAM state được copy dần sang host đích trong khi VM vẫn chạy bình thường. Đến giai đoạn cuối, VM gốc dừng lại chỉ vài millisecond để sync nốt phần dirty pages còn lại. Người dùng kết nối vào VM gần như không nhận ra — ping loss thường chỉ 1–2 packet.
Mình chạy homelab với Proxmox VE quản lý 12 VM và container — đây là playground để test mọi thứ trước khi đưa lên production. Proxmox có UI live migration rất tiện, nhưng thực ra bên dưới nó cũng gọi virsh migrate. Bài này tập trung vào raw KVM + libvirt để hiểu từng bước xảy ra thay vì ấn nút.
Có hai loại live migration cần phân biệt ngay từ đầu:
- Shared storage migration: Disk VM nằm trên NFS/Ceph shared giữa các host → chỉ chuyển RAM state, nhanh và ít ảnh hưởng VM.
- Block migration (non-shared): Chuyển cả RAM lẫn disk → chậm hơn nhiều nhưng không cần chuẩn bị shared storage.
Chuẩn bị môi trường
Yêu cầu phần cứng và network
Trước khi động vào cấu hình, cần kiểm tra mấy điều kiện này — thiếu một là migration fail ngay:
- Cả hai host đều cài KVM/libvirt và đang chạy
- CPU cùng vendor — Intel sang Intel, AMD sang AMD. Migrate chéo Intel/AMD về mặt lý thuyết có workaround nhưng thực tế thường fail
- Network thông giữa 2 host, đặc biệt TCP port 16509 (libvirtd) và dải port 49152–49215 (QEMU migration channels)
- Bridge network phải cùng tên trên cả 2 host — nếu host1 dùng
br0mà host2 dùngvirbr0, VM sau migrate sẽ mất network
# Kiểm tra tên bridge network trên từng host
ip link show type bridge
Cài đặt packages cần thiết
Chạy trên cả hai host:
# Ubuntu/Debian
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients \
virtinst bridge-utils
# RHEL/CentOS/Rocky Linux
sudo dnf install -y qemu-kvm libvirt virt-install bridge-utils
sudo systemctl enable --now libvirtd
# Xác nhận libvirtd đang chạy
sudo systemctl status libvirtd
sudo virsh list --all
Cấu hình chi tiết để live migration hoạt động
Bước 1 — Mở libvirtd cho remote connection
Mặc định libvirtd chỉ lắng nghe local socket. Cần bật TCP transport để migration hoạt động giữa 2 host.
Chỉnh /etc/libvirt/libvirtd.conf trên cả hai host:
sudo nano /etc/libvirt/libvirtd.conf
Thêm hoặc bỏ comment các dòng sau:
# Bật TCP transport
listen_tcp = 1
listen_addr = "0.0.0.0"
tcp_port = "16509"
# Tắt auth để test nội bộ
# (production: dùng sasl hoặc TLS)
auth_tcp = "none"
Kích hoạt flag --listen cho daemon:
# Ubuntu/Debian
sudo sed -i 's/#LIBVIRTD_ARGS=""/LIBVIRTD_ARGS="--listen"/' /etc/default/libvirtd
# RHEL/CentOS
sudo sed -i 's/#LIBVIRTD_ARGS="--listen"/LIBVIRTD_ARGS="--listen"/' /etc/sysconfig/libvirtd
sudo systemctl restart libvirtd
# Xác nhận port đã mở
ss -tlnp | grep 16509
Bước 2 — SSH key-based authentication
Virsh migrate qua SSH cần kết nối không hỏi password. Chạy từ source host:
# Tạo SSH key riêng cho migration
ssh-keygen -t ed25519 -f ~/.ssh/id_migration -N ""
# Copy sang destination host (192.168.1.102)
ssh-copy-id -i ~/.ssh/id_migration.pub [email protected]
# Test kết nối và xem VM trên destination
ssh -i ~/.ssh/id_migration [email protected] "virsh list --all"
Bước 3 — Thiết lập NFS shared storage
NFS shared storage là nền tảng của toàn bộ setup. Disk VM phải nằm trên NFS mount được mount cùng đường dẫn ở cả 2 host — sai điều này, migration sẽ báo lỗi không tìm được disk.
Cài và export trên NFS server (có thể là host thứ 3, hoặc dùng chính một trong 2 KVM host):
sudo apt install -y nfs-kernel-server
sudo mkdir -p /srv/kvm-shared
# Export thư mục ra mạng LAN
echo "/srv/kvm-shared 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)" | \
sudo tee -a /etc/exports
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
Mount trên cả hai KVM host:
sudo apt install -y nfs-common
sudo mkdir -p /var/lib/libvirt/images/shared
# Mount NFS (192.168.1.100 là IP NFS server)
sudo mount -t nfs 192.168.1.100:/srv/kvm-shared /var/lib/libvirt/images/shared
# Thêm vào /etc/fstab để tự mount sau reboot
echo "192.168.1.100:/srv/kvm-shared /var/lib/libvirt/images/shared nfs defaults,_netdev 0 0" | \
sudo tee -a /etc/fstab
Tạo VM mới với disk đặt trên NFS share ngay từ đầu:
sudo virt-install \
--name testvm \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/shared/testvm.qcow2,size=20 \
--os-variant ubuntu22.04 \
--network bridge=br0 \
--graphics none \
--location /var/lib/libvirt/images/ubuntu-22.04-live-server-amd64.iso,kernel=casper/vmlinuz,initrd=casper/initrd
Thực hiện live migration với virsh
Giả sử source host là host1 (192.168.1.101), destination là host2 (192.168.1.102). VM tên testvm đang chạy trên host1.
Migrate qua SSH
# Cú pháp cơ bản
virsh migrate --live testvm qemu+ssh://[email protected]/system
# Thêm --verbose để xem tiến trình
virsh migrate --live --verbose testvm qemu+ssh://[email protected]/system
Migrate qua TCP transport (nhanh hơn trong LAN)
virsh migrate --live --verbose \
testvm \
qemu+tcp://192.168.1.102/system
Block migration khi không có shared storage
Dùng --copy-storage-all để chuyển cả disk. Với disk 20GB trên LAN gigabit mất khoảng 3–5 phút, VM vẫn chạy nhưng performance I/O sẽ giảm trong thời gian này:
virsh migrate --live \
--copy-storage-all \
--verbose \
testvm \
qemu+ssh://[email protected]/system
Tinh chỉnh thời gian downtime cuối
Ở giai đoạn cuối migration, VM phải dừng vài millisecond để đồng bộ dirty pages còn lại. Mặc định là 300ms — nếu VM có workload nặng, tăng lên một chút giúp migration hoàn thành thay vì bị timeout:
# Cho phép tối đa 500ms downtime ở giai đoạn final
virsh migrate --live \
--migrate-setmaxdowntime 500 \
testvm \
qemu+ssh://[email protected]/system
Kiểm tra và Monitoring
Xác nhận VM đã chuyển thành công
# Trên host1 — testvm không còn ở đây nữa
virsh list --all
# Trên host2 — testvm đang running
virsh list --all
# Expected:
# Id Name State
# 1 testvm running
Monitor tiến trình migration real-time
# Chạy lệnh này trên source host trong khi migration đang diễn ra
watch -n 1 "virsh domjobinfo testvm"
# Output sẽ hiển thị:
# Job type: Unbounded
# Time elapsed: 3421 ms
# Data processed: 768 MiB
# Data remaining: 64 MiB
# Memory processed: 768 MiB
# Memory remaining: 64 MiB
Kiểm tra network không bị ngắt
# Lấy IP của VM
virsh domifaddr testvm
# Ping liên tục từ máy ngoài trong khi migration chạy
ping -i 0.2 <IP-cua-testvm>
# Nếu migration thành công, chỉ thấy 1-2 packet loss tối đa
Xử lý lỗi thường gặp
# Xem log libvirt trên source host
sudo tail -f /var/log/libvirt/libvirtd.log
# Log QEMU của VM cụ thể
sudo tail -f /var/log/libvirt/qemu/testvm.log
Một vài lỗi mình hay gặp khi test trong homelab:
- “Unable to allow access for disk path”: Disk VM nằm trên local storage, không phải NFS. Cần chuyển disk sang NFS share trước (tắt VM, copy file,
virsh editđể cập nhật path, bật lại). - “authentication failed”: Kiểm tra
auth_tcp = "none"tronglibvirtd.confvà đã restart daemon. - Migration bị timeout: VM có workload I/O nặng liên tục tạo dirty pages nhanh hơn migration copy được. Thử tăng
--migrate-setmaxdowntimehoặc giảm tải VM trước khi migrate. - VM mất network sau migrate: Bridge name khác nhau giữa 2 host. Đồng bộ tên bridge network là cách fix dứt điểm.

