kvm虚拟机克隆

  • 链接克隆和完整克隆的区别
  • 完整克隆
  • 自动完整克隆
  • 手动克隆的步骤
  • 1.复制模板vm磁盘为新vm的磁盘
  • 2.复制模板vm配置文件为新vm的配置文件
  • 3.修改新vm配置文件中的信息为新vm的信息
  • 4.导入新vm的配置文件
  • 5.启动新vm
  • 链接克隆
  • 1.生成链接克隆虚拟机磁盘文件
  • 2.后续流程与手动克隆一致
  • kvm虚拟机自动链接克隆
  • 自动链接克隆脚本1
  • 自动连接克隆脚本2
  • 自动链接克隆脚本3


链接克隆和完整克隆的区别

kvm导入qcow2 bootingfrom hard disk kvm导出_kvm虚拟机克隆



完整克隆

完整克隆是将当前虚拟机的磁盘文件完全复制一份。



自动完整克隆

# 自动完整克隆
## -o 源虚拟机
## -n new新的虚拟机
virt-clone --auto-clone -o vm1 -n vm2

克隆时虚拟机必需处于**挂起****关机**状态。

kvm导入qcow2 bootingfrom hard disk kvm导出_kvm_02



手动克隆的步骤

手动克隆的步骤如下:



1.复制模板vm磁盘为新vm的磁盘
# 复制模板vm磁盘为新vm的磁盘
cp centos7-clone.qcow2 app2.qcow2



2.复制模板vm配置文件为新vm的配置文件
# 复制模板vm配置文件为新vm的配置文件
virsh dumpxml centos7-clone > app2.xml



3.修改新vm配置文件中的信息为新vm的信息
# 修改新vm配置文件的name/UUID/磁盘/mac地址
vim app2.xml
  • 修改vm的name
  • 删除vm的uuid
  • 删除vm的mac地址
  • 修改vm的磁盘路径


4.导入新vm的配置文件
# 导入新vm的配置文件
virsh define app2.xml



5.启动新vm
# 启动新vm
virsh start app2



链接克隆

链接克隆占用磁盘空间较小,但是前置条件是源虚拟机文件要存在
也就是说,如果把源虚拟机删除了,链接克隆后的虚拟机就不能用了。



1.生成链接克隆虚拟机磁盘文件

# 创建链接克隆磁盘
## 创建链接克隆磁盘要指定-f 为qcow2
## -b 创建链接克隆磁盘
qemu-img create -f qcow2 -b 源磁盘 新磁盘

kvm导入qcow2 bootingfrom hard disk kvm导出_链接克隆_03

# 查看链接克隆磁盘
qemu-img info 新磁盘
## backing file 基于这个磁盘文件做的链接克隆

kvm导入qcow2 bootingfrom hard disk kvm导出_链接克隆_04



2.后续流程与手动克隆一致

  • 复制vm配置文件为新vm
  • 修改vm配置文件中的信息为新vm的信息
  • 修改vm的name
  • 删除vm的uuid
  • 删除vm的mac地址
  • 修改vm的磁盘路径
  • 导入新vm的配置文件
  • 启动新vm


kvm虚拟机自动链接克隆

kvm没有官方的自动链接克隆工具.
下面是3个自动链接克隆脚本,全都没有在生产环境下测试过,总有一款适合你。



#!/usr/bin/env bash

echo "本脚本未做过任何测试"

# 将获取源vm实例、新vm实例名称
function parse_arguments() {
  # 如果没有传入足够的参数,输出使用说明并退出
  if [[ $# -lt 2 ]]; then
    echo "Usage: $0 <src_vm_name> <new_vm_name>"
    exit 1
  fi

  # 获取源vm实例名称,赋值给全局变量 $src_vm_name
  src_vm_name=$1

  # 获取新vm实例名称,赋值给全局变量 $new_vm_name
  new_vm_name=$2

  # 设置新vm实例配置文件的路径和文件名,赋值给全局变量 $new_vm_xml
  new_vm_xml="/tmp/${new_vm_name}.xml"

  # 生成新vm实例的uuid,赋值给全局变量 $new_vm_uuid
  new_vm_uuid=$(uuidgen)
}

# 将从源vm实例导出配置到新vm实例配置文件的代码封装为函数
function export_vm_config() {
  # 从源vm实例导出配置到新vm实例配置文件
  virsh dumpxml "$src_vm_name" >"$new_vm_xml"
}

# 将从新vm实例配置文件中过滤出磁盘完整路径的代码封装为函数
function get_vm_disk_path() {
  # 从新vm实例配置文件中过滤出磁盘完整路径
  src_vm_name_disk=$(grep qcow2 "$new_vm_xml" | awk -F "'" '/source file/{print $2}')

  # 读取src_disk所在的目录
  src_disk_dir=$(dirname "$src_vm_name_disk")

  # 拼接出新vm实例的磁盘完整路径,赋值给全局变量 $new_vm_disk
  new_vm_disk=${src_disk_dir}/${new_vm_name}.qcow2
}

# 将创建基于链接克隆的虚拟磁盘文件的代码封装为函数
function clone_vm_disk() {
  # 创建基于链接克隆的虚拟磁盘文件
  qemu-img create -f qcow2 -b "$src_vm_name_disk" "$new_vm_disk"
}

# 将修改新虚拟机的xml配置文件的代码封装为函数
function modify_vm_config() {
  # 修改新虚拟机的xml配置文件
  sed -i 's/vmname/'"$new_vm_xml"'/' "$new_vm_xml"
  sed -i 's/vmuuid/'"$new_vm_uuid"'/' "$new_vm_xml"
  sed -i '/mac address/d' "$new_vm_xml"
  sed -i '2s#'"$src_vm_name"'#'"$new_vm_name"'#' "$new_vm_xml"
  sed -i 's#'"$src_vm_name_disk"'#'"$new_vm_disk"'#g' "$new_vm_xml"
  sed -i '/\/var\/lib\/libvirt\/qemu\/channel\/target/d' "$new_vm_xml"
}

# 将导入新vm实例的虚拟机配置文件的代码封装为函数
function import_vm_config() {
  # 导入新vm实例的虚拟机配置文件
  virsh define "$new_vm_xml"
}

# 将测试启动新vm实例的代码封装为函数
function start_vm() {
  # 测试启动新vm实例
  virsh start "$new_vm_name"
}

# 主函数,调用上述函数组合实现整个脚本的功能
function main() {
  echo "本脚本只在Centos7测试过"

  # 解析命令行参数
  parse_arguments "$@"

  # 导出源vm实例的配置到新vm实例的配置文件
  export_vm_config

  # 获取源vm实例的磁盘路径并生成新vm实例的磁盘路径
  get_vm_disk_path

  # 创建基于链接克隆的虚拟磁盘文件
  clone_vm_disk

  # 修改新vm实例的xml配置文件
  modify_vm_config

  # 导入新vm实例的虚拟机配置文件
  import_vm_config

  # 测试启动新vm实例
  start_vm
}

# 调用主函数
main "$@"



自动连接克隆脚本2

#!/usr/bin/env bash

# 以时间格式生成VM_NAME
function generate_vm_name() {
  # 定义虚拟机名称的前缀
  local VM_NAME_PREFIX="vm"
  # 获取当前时间,精确到纳秒
  NEWVM="${VM_NAME_PREFIX}$(date +%Y%m%d%H%M%S%N)"
  # 返回生成的随机虚拟机名称
  echo "${NEWVM}"
}

# 定义函数,用于检查虚拟机磁盘镜像是否已经存在
function check_vm_image() {
  # 检查新虚拟机的磁盘镜像是否已经存在,如果存在则输出错误消息并退出
  if [ -e "${IMG_DIR}/${NEWVM}.img" ]; then
    echo "File exists."
    exit 68
  fi
}

# 定义函数,用于创建新虚拟机的磁盘镜像
function create_vm_image() {
  # 创建新的虚拟机磁盘镜像,并提示创建结果
  echo -en "创建虚拟机磁盘映像......\t"
  # -f qcow2:指定新磁盘镜像的格式为 qcow2。
  # -b "${IMG_DIR}/${BASEVM}.img":指定新磁盘镜像基于的现有磁盘镜像
  # ${IMG_DIR}/${NEWVM}.img 是新磁盘镜像的路径和文件名。
  # &> /dev/null:将命令的标准输出和标准错误输出都重定向到 /dev/null,即丢弃输出。
  qemu-img create -f qcow2 -b "${IMG_DIR}/${BASEVM}.img" "${IMG_DIR}/${NEWVM}.img" &> /dev/null
  # 打印绿色的OK
  echo -e "\e[32;1m[OK]\e[0m"
}

# 定义函数,用于修改虚拟机配置文件
function modify_vm_config() {
  # 读取默认的虚拟机配置文件,并将其拷贝到临时文件中
  cat "${IMG_DIR}/.rhel7.xml" > /tmp/myvm.xml
  # 将虚拟机配置文件中所有出现的BASEVM替换为NEWVM
  sed -i "s/${BASEVM}/${NEWVM}/g" /tmp/myvm.xml
  # 生成一个新的UUID,并将虚拟机配置文件中的UUID替换为新的UUID
  sed -i "s/<uuid>.*<\/uuid>/<uuid>$(uuidgen)<\/uuid>/g" /tmp/myvm.xml
  # 将虚拟机配置文件中所有出现的BASEVM.img替换为NEWVM.img
  sed -i "s/${BASEVM}\.img/${NEWVM}\.img/g" /tmp/myvm.xml
  # 将虚拟机配置文件中的MAC地址从a1修改为0c
  sed -i "s/a1/0c/g" /tmp/myvm.xml # 修改 MAC 地址
}

# 定义函数,用于定义新虚拟机并启动
function define_vm() {
  # 将新虚拟机的配置文件定义为一个新的虚拟机,并提示定义结果
  echo -en "定义新的虚拟机......\t\t"
  virsh define /tmp/myvm.xml &> /dev/null
  # 输出一个绿色的"[OK]"
  echo -e "\e[32;1m[OK]\e[0m"
}

# 定义函数,用于创建新虚拟机
function main() {
  # 1. 以时间格式生成VM_NAME
  generate_vm_name

  # 2.调用check_vm_image函数来检查新虚拟机的磁盘镜像是否已经存在
  check_vm_image

  # 3.调用create_vm_image函数来创建新的虚拟机磁盘镜像
  create_vm_image

  # 4.调用modify_vm_config函数来修改新虚拟机的配置文件
  modify_vm_config

  # 5.调用define_vm函数来定义新虚拟机并启动
  define_vm
}


####################################################
# 设置变量,指定新虚拟机的磁盘镜像目录和基础虚拟机名称
IMG_DIR=/var/lib/libvirt/images
BASEVM=rh7_template

# 调用函数来创建新的虚拟机
create_vm

# 退出码:
# 65 -> 用户未输入任何内容
# 66 -> 用户输入的不是数字
# 67 -> 用户输入的数字超出范围
# 68 -> 虚拟机磁盘镜像已经存在



自动链接克隆脚本3

#!/bin/bash
# 自动链接克隆 KVM 虚拟机的脚本,适用于生产环境

# 开启debug
set -ex

# 配置
vm_name="myvm" # 源虚拟机的名称
clone_prefix="clone-" # 克隆虚拟机名称的前缀
clone_count=5 # 要创建的克隆虚拟机的数量
clone_memory="4G" # 每个克隆虚拟机的内存大小(例如 "2G"、"4096")
clone_vcpus=2 # 每个克隆虚拟机的虚拟 CPU 数量
clone_disk_size="20G" # 每个克隆虚拟机的磁盘镜像文件大小(例如 "10G"、"100GiB")

# 获取源虚拟机的磁盘镜像文件名和目录
function get_source_disk() {
  src_vm_name_disk=$(virsh dumpxml "$vm_name" | grep 'source file' | awk -F "'" '{print $2}')
  src_disk_dir=$(dirname "$src_vm_name_disk")
}

# 创建一个克隆虚拟机
function create_clone_vm() {
  # 克隆磁盘镜像文件
  qemu-img create -f qcow2 -b "$src_vm_name_disk" -o size="$clone_disk_size" "$clone_vm_disk"

  # 为克隆虚拟机生成新的 XML 配置文件
  clone_vm_xml=$(mktemp)
  virsh dumpxml "$vm_name" | sed "s/<name>$vm_name<\/name>/<name>$clone_name<\/name>/" > "$clone_vm_xml"

  # 修改克隆虚拟机的 XML 配置文件
  sed -i "s/<uuid>.*<\/uuid>/<uuid>$(uuidgen)<\/uuid>/" "$clone_vm_xml"
  sed -i "s/<memory unit='KiB'>.*<\/memory>/<memory unit='GiB'>$clone_memory<\/memory>/" "$clone_vm_xml"
  sed -i "s/<currentMemory unit='KiB'>.*<\/currentMemory>/<currentMemory unit='GiB'>$clone_memory<\/currentMemory>/" "$clone_vm_xml"
  sed -i "s/<vcpu placement='static'>.*<\/vcpu>/<vcpu placement='static'>$clone_vcpus<\/vcpu>/" "$clone_vm_xml"
  sed -i "s/<source file='.*.qcow2'\/>/<source file='$clone_vm_disk'\/>/" "$clone_vm_xml"
  sed -i "s/<target dev='vda' bus='virtio'\/>/<target dev='vda' bus='virtio'\/><address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'\/>/" "$clone_vm_xml"

  # 使用修改后的 XML 配置文件定义克隆虚拟机
  virsh define "$clone_vm_xml"

  echo "已完成克隆虚拟机 '$vm_name' 为 '$clone_name' 的创建。"
}

# 创建多个克隆虚拟机
function create_multiple_clones() {
  # 循环创建指定数量的克隆虚拟机
  for ((i=1; i<=clone_count; i++)); do
    clone_name="${clone_prefix}${i}"
    clone_vm_disk=${src_disk_dir}/${clone_name}.qcow2

    create_clone_vm
  done
}

# 调用函数创建克隆虚拟机
get_source_disk
create_multiple_clones

# 这个脚本从指定的源虚拟机中克隆指定数量的虚拟机,并为每个虚拟机生成新的 XML 配置文件。虚拟机的名称、内存大小、CPU 数量和磁盘镜像大小都可以在脚本中进行配置