本文目录导读:

在Shell脚本中迁移虚拟机到其他宿主机,主要取决于你使用的虚拟化平台(如KVM/libvirt、VMware、Hyper-V等),以下针对最常见的 KVM/libvirt 环境提供几种主流迁移方式的 Shell 脚本实现。
基于 libvirt 的在线迁移(热迁移)
适用于需要零停机时间的场景,要求源和目标宿主机共享存储(NFS、iSCSI、GlusterFS等)。
#!/bin/bash
# live_migration.sh - 虚拟机在线迁移脚本
# 参数配置
VM_NAME=$1 # 虚拟机名称
TARGET_HOST=$2 # 目标宿主机IP或主机名
TARGET_SSH_USER=${3:-"root"} # 目标宿主机SSH用户
# 检查参数
if [ $# -lt 2 ]; then
echo "用法: $0 <虚拟机名称> <目标宿主机> [SSH用户]"
echo "示例: $0 web-server-01 192.168.1.102"
exit 1
fi
# 确认虚拟机存在
if ! virsh dominfo "$VM_NAME" &>/dev/null; then
echo "错误: 虚拟机 '$VM_NAME' 不存在"
exit 1
fi
# 检查目标主机连通性
if ! ping -c 1 "$TARGET_HOST" &>/dev/null; then
echo "错误: 无法连接到目标宿主机 $TARGET_HOST"
exit 1
fi
# 检查源和目标是否共享存储(通过检查同一路径是否存在)
TEST_PATH="/var/lib/libvirt/images/test_shared.tmp"
if ssh "$TARGET_SSH_USER@$TARGET_HOST" "touch $TEST_PATH" && rm -f "$TEST_PATH"; then
echo "存储共享检查通过"
else
echo "警告: 无法确认存储共享,请确保使用共享存储"
fi
# 执行在线迁移
echo "开始迁移虚拟机 '$VM_NAME' 到 $TARGET_HOST ..."
virsh migrate --live \
--verbose \
--persistent \
--undefinesource \
--domain "$VM_NAME" \
--desturi "qemu+ssh://$TARGET_SSH_USER@$TARGET_HOST/system" \
--migrateuri "tcp://$TARGET_HOST:49152"
# 检查迁移结果
if [ $? -eq 0 ]; then
echo "迁移成功完成!"
echo "虚拟机 '$VM_NAME' 现在运行在 $TARGET_HOST"
else
echo "迁移失败,请检查日志"
exit 1
fi
使用前提:
- 源和目标宿主机安装 libvirt 和 qemu-kvm
- 配置 SSH 密钥认证(免密登录)
- 启用 libvirt TCP 迁移(
/etc/libvirt/libvirtd.conf中设置listen_tls=0,listen_tcp=1)
离线迁移(冷迁移 + 文件复制)
适用于非关键业务,需要复制磁盘文件到目标宿主机。
#!/bin/bash
# cold_migration.sh - 虚拟机离线迁移脚本
VM_NAME=$1
TARGET_HOST=$2
TARGET_STORAGE=${3:-"/var/lib/libvirt/images"}
LOCAL_STORAGE=$(virsh dumpxml "$VM_NAME" | sed -n "s|.*source file='\([^']*\)'.*|\1|p")
# 关闭虚拟机
echo "正在关闭虚拟机 '$VM_NAME'..."
virsh shutdown "$VM_NAME"
while virsh domstate "$VM_NAME" | grep -q "running"; do
sleep 2
echo "等待虚拟机完全关闭..."
done
# 获取磁盘路径
echo "获取磁盘文件路径..."
DISK_FILES=()
while IFS= read -r line; do
DISK_FILES+=("$line")
done < <(virsh dumpxml "$VM_NAME" | grep "source file" | sed "s/.*'\([^']*\)'.*/\1/")
# 复制磁盘文件到目标主机
for DISK in "${DISK_FILES[@]}"; do
echo "复制磁盘文件: $DISK 到 $TARGET_HOST:$TARGET_STORAGE/"
scp "$DISK" "root@$TARGET_HOST:$TARGET_STORAGE/"
if [ $? -ne 0 ]; then
echo "磁盘复制失败,请检查网络和权限"
exit 1
fi
done
# 导出并修改XML配置文件
echo "导出并修改XML配置..."
virsh dumpxml "$VM_NAME" > /tmp/${VM_NAME}_migrate.xml
# 修改磁盘路径为目标路径
for DISK in "${DISK_FILES[@]}"; do
NEW_DISK_PATH="$TARGET_STORAGE/$(basename $DISK)"
sed -i "s|$DISK|$NEW_DISK_PATH|g" /tmp/${VM_NAME}_migrate.xml
done
# 将XML复制到目标主机
scp /tmp/${VM_NAME}_migrate.xml "root@$TARGET_HOST:/etc/libvirt/qemu/${VM_NAME}.xml"
# 在目标主机上定义并启动虚拟机
ssh "root@$TARGET_HOST" "virsh define /etc/libvirt/qemu/${VM_NAME}.xml && virsh start $VM_NAME"
# 在源主机上清除虚拟机定义
virsh undefine "$VM_NAME"
# 清理临时文件
rm -f /tmp/${VM_NAME}_migrate.xml
echo "迁移完成!虚拟机 '$VM_NAME' 已迁移到 $TARGET_HOST"
使用 virt-v2v 迁移到其他宿主机(异构环境)
适用于 KVM 到 KVM 或不同虚拟化平台间迁移。
#!/bin/bash
# virt_v2v_migration.sh - 使用virt-v2v工具迁移
SOURCE_VM=$1
TARGET_HOST=$2
# 安装必要工具
if ! command -v virt-v2v &>/dev/null; then
echo "安装 virt-v2v..."
yum install -y virt-v2v # 适用于 CentOS/RHEL
# apt install virt-v2v # 适用于 Ubuntu
fi
# 创建临时存储目录
TEMP_DIR="/tmp/v2v_${SOURCE_VM}"
mkdir -p "$TEMP_DIR"
# 执行转换迁移
echo "开始转换并迁移虚拟机..."
virt-v2v -i libvirt -ic "qemu:///system" \
-o libvirt -oc "qemu+ssh://root@$TARGET_HOST/system" \
-os "/var/lib/libvirt/images" \
-on "$SOURCE_VM" \
-of qcow2 \
-b br0 \
-n default \
"$SOURCE_VM" 2>&1 | tee "$TEMP_DIR/migration.log"
# 检查迁移结果
if [ $? -eq 0 ]; then
echo "迁移成功!请检查目标主机上的虚拟机状态"
else
echo "迁移失败,请查看日志: $TEMP_DIR/migration.log"
exit 1
fi
# 清理临时目录
rm -rf "$TEMP_DIR"
通用迁移检查脚本(先验证环境)
#!/bin/bash
# check_migration_env.sh - 迁移前环境检查
MIGRATION_METHOD=${1:-"live"}
SOURCE_HOST=$(hostname)
TARGET_HOST=$2
check_required_ports() {
echo "检查必要端口..."
for port in 22 16509 49152; do
nc -zv "$TARGET_HOST" "$port" &>/dev/null && \
echo " ✓ 端口 $port 可达" || \
echo " ✗ 端口 $port 不可达"
done
}
check_ssh_auth() {
echo "检查SSH密钥认证..."
ssh -o BatchMode=yes "root@$TARGET_HOST" "echo SSH_OK" &>/dev/null && \
echo " ✓ SSH密钥认证正常" || \
echo " ✗ SSH密钥认证失败,请配置免密登录"
}
check_shared_storage() {
echo "检查共享存储..."
if df -h | grep -qE "(nfs|glusterfs|ceph)"; then
echo " ✓ 检测到共享存储"
else
echo " ! 未检测到共享存储,只能执行离线迁移"
fi
}
# 主检查流程
echo "======= 迁移环境检查 ======="
echo "源宿主机: $SOURCE_HOST"
echo "目标宿主机: $TARGET_HOST"
echo "迁移方式: $MIGRATION_METHOD"
echo "============================"
check_required_ports
check_ssh_auth
check_shared_storage
echo "============================"
echo "环境检查完成"
使用注意事项
-
网络要求:
- 所有宿主机之间需要网络互通
- 热迁移需要至少 1Gbps 网络带宽
- 配置合适的防火墙规则
-
存储要求:
- 热迁移必须使用共享存储
- 冷迁移需要足够磁盘空间和网络传输时间
-
版本兼容性:
- 源和目标宿主机libvirt版本尽量一致
- CPU特性要兼容(可使用CPU模式
host-model)
-
调用示例:
# 热迁移 ./live_migration.sh myvm 192.168.1.101
冷迁移
./cold_migration.sh myvm 192.168.1.101 /data/images
环境检查
./check_migration_env.sh live 192.168.1.101
根据实际环境选择合适的迁移方式,生产环境建议先在测试环境验证。