KVM 一键批量创建虚拟机 自动设置IP

目录

一、原理

  1. 需要先创建基础镜像,后续的镜像都是基于该镜像创建的差量镜像。基础镜像不允许修改(需要注意)。
  2. 基础镜像需要设置要一些基本内容。
  3. 通过 virt-edit 实现的设置ip.
  4. ip 信息统一用 <title> 来进行标记。 使用virsh list --title进行查看 机器和IP

完成的功能:

输入机器名称和ip,就能创建我们想要的虚拟机了。ip会自动帮我们设置好。

解决的问题:

  1. 之前创建机器后需要手动去设置IP. virt-edit 进行编辑网络文件。
  2. 创建完机器,我们不知道机器对应的哪个IP. 使用 <title> 来进行标记。 使用virsh list --title进行查看 机器和IP对应关系

二、基础镜像

2.1、创建基础镜像

  • 内存为8G 和2核
  • 磁盘为50G
  • vnc 端口使用随机
  • 网络设置为桥接
  • 机器设置为自动启动
virt-install --name base-image --virt-type kvm --memory 8096 --vcpus 2 --cdrom=/home/kvm/iso/CentOS-7-x86_64-Minimal-1908.iso --disk /home/kvm/data/base-image.qcow2,size=50,format=qcow2  --graphics vnc,listen=0.0.0.0  --network network=net-br --autostart  

2.2、 完善基础镜像

  1. 增加 console 登陆

    grubby --update-kernel=ALL --args="console=ttyS0,115200n8"
    
  2. vnc 端口设置随机

  3. 使用桥接网络

  4. 设置网络配置

    BOOTPROTO=static  
    ONBOOT=yes
    IPADDR=192.168.1.12
    NETMASK=255.255.255.0
    GATEWAY=192.168.1.1
    DNS1=192.168.1.1
    # 注释uuid
    

2.3、基础镜像设置权限

由于使用的是差量镜像的模式,所以基础镜像不允许修改。

chattr +i   /opt/kvm/data/base-image.qcow2

3.4 设置 title

编辑基础镜像的 xml 文件,增加 title。

 <title>192.168.1.156</title>

3.5、基础镜像XML

<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
  virsh edit base-image
or other application using the libvirt API.
-->

<domain type=\'kvm\'>
  <name>base-image</name>
  <uuid>12348899-e829-4217-a0ff-f30eee4d2b31</uuid>
  <title>192.168.1.199</title>
  <memory unit=\'KiB\'>16777216</memory>
  <currentMemory unit=\'KiB\'>8388608</currentMemory>
  <vcpu placement=\'static\' current=\'2\'>4</vcpu>
  <os>
    <type arch=\'x86_64\' machine=\'pc-i440fx-rhel7.0.0\'>hvm</type>
    <boot dev=\'hd\'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode=\'custom\' match=\'exact\' check=\'partial\'>
    <model fallback=\'allow\'>Broadwell-IBRS</model>
    <feature policy=\'require\' name=\'spec-ctrl\'/>
  </cpu>
  <clock offset=\'utc\'>
    <timer name=\'rtc\' tickpolicy=\'catchup\'/>
    <timer name=\'pit\' tickpolicy=\'delay\'/>
    <timer name=\'hpet\' present=\'no\'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled=\'no\'/>
    <suspend-to-disk enabled=\'no\'/>
  </pm>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type=\'file\' device=\'disk\'>
      <driver name=\'qemu\' type=\'qcow2\'/>
      <source file=\'/opt/kvm/data/base-image.qcow2\'/>
      <target dev=\'vda\' bus=\'virtio\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x06\' function=\'0x0\'/>
    </disk>
    <disk type=\'file\' device=\'cdrom\'>
      <driver name=\'qemu\' type=\'raw\'/>
      <target dev=\'hda\' bus=\'ide\'/>
      <readonly/>
      <address type=\'drive\' controller=\'0\' bus=\'0\' target=\'0\' unit=\'0\'/>
    </disk>
    <controller type=\'usb\' index=\'0\' model=\'ich9-ehci1\'>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x04\' function=\'0x7\'/>
    </controller>
    <controller type=\'usb\' index=\'0\' model=\'ich9-uhci1\'>
      <master startport=\'0\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x04\' function=\'0x0\' multifunction=\'on\'/>
    </controller>
    <controller type=\'usb\' index=\'0\' model=\'ich9-uhci2\'>
      <master startport=\'2\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x04\' function=\'0x1\'/>
    </controller>
    <controller type=\'usb\' index=\'0\' model=\'ich9-uhci3\'>
      <master startport=\'4\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x04\' function=\'0x2\'/>
    </controller>
    <controller type=\'pci\' index=\'0\' model=\'pci-root\'/>
    <controller type=\'ide\' index=\'0\'>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x01\' function=\'0x1\'/>
    </controller>
    <controller type=\'virtio-serial\' index=\'0\'>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x05\' function=\'0x0\'/>
    </controller>
    <interface type=\'network\'>
      <mac address=\'52:54:00:28:99:22\'/>
      <source network=\'net-br\'/>
      <model type=\'virtio\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x03\' function=\'0x0\'/>
    </interface>
    <serial type=\'pty\'>
      <target type=\'isa-serial\' port=\'0\'>
        <model name=\'isa-serial\'/>
      </target>
    </serial>
    <console type=\'pty\'>
      <target type=\'serial\' port=\'0\'/>
    </console>
    <channel type=\'unix\'>
      <target type=\'virtio\' name=\'org.qemu.guest_agent.0\'/>
      <address type=\'virtio-serial\' controller=\'0\' bus=\'0\' port=\'1\'/>
    </channel>
    <input type=\'tablet\' bus=\'usb\'>
      <address type=\'usb\' bus=\'0\' port=\'1\'/>
    </input>
    <input type=\'mouse\' bus=\'ps2\'/>
    <input type=\'keyboard\' bus=\'ps2\'/>
    <graphics type=\'vnc\' port=\'-1\' autoport=\'yes\' listen=\'0.0.0.0\' keymap=\'en-us\'>
      <listen type=\'address\' address=\'0.0.0.0\'/>
    </graphics>
    <video>
      <model type=\'cirrus\' vram=\'16384\' heads=\'1\' primary=\'yes\'/>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x02\' function=\'0x0\'/>
    </video>
    <memballoon model=\'virtio\'>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x07\' function=\'0x0\'/>
    </memballoon>
    <rng model=\'virtio\'>
      <backend model=\'random\'>/dev/urandom</backend>
      <address type=\'pci\' domain=\'0x0000\' bus=\'0x00\' slot=\'0x08\' function=\'0x0\'/>
    </rng>
  </devices>
</domain>

三、批量创建机器脚本

因为需要使用 virt-edit,所以需要安装libguestfs-tools

yum install -y libguestfs-tools

#!/bin/bash
#######################################################
# $Name:        create_kvm_machine.sh
# $Version:     v1.0
# $Function:    create kvm machine
# $Author:      dongjiaxiao
# $Create Date: 2020-04-12
# $Description: shell
######################################################
#set -x
# 检查基础镜像和xml是否存在并生成uuid,mac 信息
function check(){
        if [ ! -f "${xmls_dir}${base_xml}" ]&&[ ! -f "${images_dir}${base_img}" ] # 判断基础xml和基础镜像是否存在
        then
                echo "基础镜像或者基础镜像xml不存在"
                exit 1
        else
                vir_uuid=`uuidgen`
                vir_mac="52:54:$(dd if=/dev/urandom count=1 2>/dev/null | md5sum |sed -r \'s/^(..)(..)(..)(..).*$/\1:\2:\3:\4/\')"
                vir_name=$machine_name        
        fi 
        
}
#创建磁盘
function create_disk(){
        chattr -i  ${images_dir}$base_img
        qemu-img create -f qcow2 -b ${images_dir}$base_img ${images_dir}${vir_name}.qcow2 ${vir_disk}G  &>/dev/null
}
#添加磁盘
function attach_disk(){
        qemu-img create -f qcow2  ${images_dir}${vir_name}-2.qcow2  ${vir_attach_disk}G  >/dev/null
        virsh attach-disk ${vir_name} ${images_dir}${vir_name}-2.qcow2 vdb --cache writeback --subdriver qcow2 --persistent >/dev/null
        
}

#配置xml ,替换内存cpu 等信息并导入
function conf_xml(){
        cp  ${xmls_dir}${base_xml}  /tmp/${vir_name}.xml
        sed -i "s#<memory unit=\'KiB\'>.*</memory>#<memory unit=\'KiB\'>${vir_mem}</memory>#"  /tmp/${vir_name}.xml 
        sed -i "s#<currentMemory unit=\'KiB\'>.*</currentMemory>#<currentMemory unit=\'KiB\'>${vir_mem}</currentMemory>#"   /tmp/${vir_name}.xml 
        sed -i "s#<vcpu placement=\'static\'>.*</vcpu>#<vcpu placement=\'static\'>${vir_cpu}</vcpu>#" /tmp/${vir_name}.xml
        sed -i "s/<name>.*<\/name>/<name>${vir_name}<\/name>/" /tmp/${vir_name}.xml
        sed -i "s/<uuid>.*<\/uuid>/<uuid>${vir_uuid}<\/uuid>/" /tmp/${vir_name}.xml
        sed -i "s/<title>.*<\/title>/<title>${vir_ip}<\/title>/" /tmp/${vir_name}.xml
        sed -i "s#<source file=.*/>#<source file=\'${images_dir}${vir_name}.qcow2\'/>#" /tmp/${vir_name}.xml
        sed -i "s/<mac address=.*\/>/<mac address=\'$vir_mac\' \/>/" /tmp/${vir_name}.xml
        virsh define /tmp/${vir_name}.xml >/dev/null
        virt-edit -d ${vir_name}  /etc/sysconfig/network-scripts/ifcfg-eth0  -e "s#IPADDR=".*"#IPADDR="${vir_ip}"#"  # 替换ip
}

#启动并设置开机自启
function start_vir(){
        virsh start ${vir_name} >/dev/null
        virsh autostart ${vir_name} >/dev/null
        chattr +i  ${images_dir}$base_img
}
#记录创建日志
function create_vir_log(){
        echo "$(date +%F_%T)  vir_name: ${vir_name} vir_ip: ${vir_ip} !"   >>$vir_log_file
        echo "$(date +%F_%T)  vir_name: ${vir_name} vir_ip: ${vir_ip} 创建成功!" 
}

main(){
    images_dir="/home/kvm/data/" # 镜像存储的位置
    base_img="base-image.qcow2"  # 基础镜像的名称
    xmls_dir="/etc/libvirt/qemu/"  # xml 的位置
    base_xml="base-image.xml"   # 基础xml的名称 
    vir_log_file="/tmp/kvm_create_log.txt" # 创建日志文件
    vir_disk=50 # 磁盘默认为50G  
    vir_cpu=2 # cpu默认为2核
    vir_mem=8388608 # 内存默认为8G
    echo -e "服务器配置选项:\n 1: 2核8G 50G(测试) \n 2: 1核8G 50G(开发) \n 3: 2核8G 100G(数据库) \n 4: 4核20G 200G" 
    read  -t 30 -p  "输入你选择的配置的编号(1-4):" number
    read  -t 90 -p "输入想要创建的IP(192.168.1.1):"  vir_ip
    read  -t 120 -p "输入想要创建的机器名称(haha-biz-1234567-test):"  machine_name
    if [ -z "$vir_ip" ] || [  -z "$machine_name" ] # 判断是否输入ip和机器名称
    then
       echo "请输入ip和机器名称"
       exit -1
    fi
    case "$number" in
        [1] )
            check
            create_disk
            conf_xml
            start_vir
            create_vir_log
        ;;
        [2] )
            vir_cpu=1  # 设置为1核
            check
            create_disk
            conf_xml
            start_vir
            create_vir_log
        ;;
        [3] )
            vir_disk=100 #设置为磁盘100G盘
            check
            create_disk
            conf_xml
            start_vir
            create_vir_log
        ;;
        [4] )
            base_img="dc-base-image.qcow2"
            vir_cpu=4  # 设置为4核
            vir_mem=20971520 #设置内存为20G
            vir_disk=20 #设置为磁盘200G盘
            vir_attach_disk=200 # 设置附加盘的大小
            check
            create_disk
            conf_xml
            start_vir
            attach_disk
            create_vir_log
        ;;
        *) echo "输入编号(1-4)";;
    esac
}
main

四、挂载磁盘多种方式

扩展对象为: 虚拟机

4.1 扩容现有的磁盘

  • 这种方式只能增加不能缩小
  • 需要先把虚拟机关闭。(注意)
  • 宿主机操作

    [root@djx-kvm-123456-test opt]# virsh  shutdown   djx-mysql-djxmysq-test
    [root@djx-kvm-123456-test opt]# qemu-img info /home/kvm/data/djx-mysql-djxmysq-test.qcow2
    image: /home/kvm/data/djx-mysql-djxmysq-test.qcow2
    file format: qcow2
    virtual size: 100G (107374182400 bytes)
    disk size: 131M
    cluster_size: 65536
    backing file: /home/kvm/data/base-image.qcow2
    Format specific information:
        compat: 1.1
        lazy refcounts: false
    [root@djx-kvm-af3r34t-test opt]# qemu-img resize /home/kvm/data/djx-mysql-djxmysq-test.qcow2 +3G
    Image resized.
    [root@djx-kvm-af3r34t-test opt]# qemu-img info /home/kvm/data/djx-mysql-djxmysq-test.qcow2
    image: /home/kvm/data/djx-mysql-djxmysq-test.qcow2
    file format: qcow2
    virtual size: 103G (110595407872 bytes)
    disk size: 254M
    cluster_size: 65536
    backing file: /home/kvm/data/base-image.qcow2
    Format specific information:
        compat: 1.1
        lazy refcounts: false
    
    
  • 虚拟机操作

虚拟机可以进行两种类型的操作:(以下两步是冲突的,只能2选1)

1、是使用新增空间扩容现有的磁盘

2、是使用新增空间创建新的分区

  • 使用新增空间扩容现有的磁盘

    # 内核版本大于3.6.0
    
    # 安装 growpart或者xfsprogs扩容格式化工具
    yum install cloud-utils-growpart
    yum install xfsprogs
    # 运行fdisk -l命令查看现有云盘大小
    [root@localhost ~]# df -h 
    Filesystem      Size  Used Avail Use% Mounted on
    devtmpfs        3.9G     0  3.9G   0% /dev
    tmpfs           3.9G     0  3.9G   0% /dev/shm
    tmpfs           3.9G  8.5M  3.9G   1% /run
    tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
    /dev/vda2        50G  1.2G   49G   3% /
    /dev/vda1       497M  134M  363M  27% /boot
    tmpfs           783M     0  783M   0% /run/user/0
    [root@localhost ~]# fdisk  -l 
    
    Disk /dev/vda: 107.4 GB, 107374182400 bytes, 209715200 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk label type: dos
    Disk identifier: 0x000a6596
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/vda1   *        2048     1026047      512000   83  Linux
    /dev/vda2         1026048   104857599    51915776   83  Linux
    # 查看分区的文件系统类型
    [root@localhost ~]# blkid  /dev/vda2 
    /dev/vda2: UU TYPE="xfs" 
    # 调用growpart为需要扩容的云盘和对应的第几个分区扩容
    [root@localhost ~]# growpart   /dev/vda 2
    CHANGED: partition=2 start=1026048 old: size=103831552 end=104857600 new: size=208689119 end=209715167
    # 运行xfs_growfs <PartitionName>命令调用xfs_growfs扩容文件系统。 
    #  xfs 文件系统使用xfs_growfs   ,ext4 文件系统使用 resize2fs 
    [root@localhost ~]# xfs_growfs  /dev/vda2
    meta-data=/dev/vda2              isize=512    agcount=4, agsize=3244736 blks
             =                       sectsz=512   attr=2, projid32bit=1
             =                       crc=1        finobt=0 spinodes=0
    data     =                       bsize=4096   blocks=12978944, imaxpct=25
             =                       sunit=0      swidth=0 blks
    naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
    log      =internal               bsize=4096   blocks=6337, version=2
             =                       sectsz=512   sunit=0 blks, lazy-count=1
    realtime =none                   extsz=4096   blocks=0, rtextents=0
    data blocks changed from 12978944 to 26086139
    
    
  • 使用新增空间创建新的分区(与上一步冲突的)

    [root@localhost ~]# fdisk  /dev/vda 
    Welcome to fdisk (util-linux 2.23.2).
    
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    
    
    Command (m for help): m
    Command action
       a   toggle a bootable flag
       b   edit bsd disklabel
       c   toggle the dos compatibility flag
       d   delete a partition
       g   create a new empty GPT partition table
       G   create an IRIX (SGI) partition table
       l   list known partition types
       m   print this menu
       n   add a new partition
       o   create a new empty DOS partition table
       p   print the partition table
       q   quit without saving changes
       s   create a new empty Sun disklabel
       t   change a partition\'s system id
       u   change display/entry units
       v   verify the partition table
       w   write table to disk and exit
       x   extra functionality (experts only)
    
    Command (m for help): n
    Partition type:
       p   primary (2 primary, 0 extended, 2 free)
       e   extended
    Select (default p): p
    Partition number (3,4, default 3):  
    First sector (104857600-209715199, default 104857600): 
    Using default value 104857600
    Last sector, +sectors or +size{K,M,G} (104857600-209715199, default 209715199): 
    Using default value 209715199
    Partition 3 of type Linux and of size 50 GiB is set
    
    Command (m for help): w
    The partition table has been altered!
    
    Calling ioctl() to re-read partition table.
    
    WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
    The kernel still uses the old table. The new table will be used at
    the next reboot or after you run partprobe(8) or kpartx(8)
    Syncing disks.
    [root@localhost ~]# fdisk  -l
    
    Disk /dev/vda: 107.4 GB, 107374182400 bytes, 209715200 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk label type: dos
    Disk identifier: 0x000a6596
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/vda1   *        2048     1026047      512000   83  Linux
    /dev/vda2         1026048   104857599    51915776   83  Linux
    /dev/vda3       104857600   209715199    52428800   83  Linux
    # 然后需要重启机器。不然直接挂载的话是挂载不了的。
    # 格式化磁盘
    [root@localhost ~]mkfs.xfs  /dev/vda3 
    [root@localhost ~]# mount  /dev/vda3  /home
    # 如果没有重启 ,报错 mount: special device /dev/vda3 does not exist
    
    # 还需要设置开动挂载
    

4.2 添加新的磁盘

  • 宿主机操作

    [root@k5-m2 ~]# qemu-img create -f qcow2  /home/kvm/data/djx-biz-djx1234-dev-2.qcow2  10G
    Formatting \'/home/kvm/data/djx-biz-djx1234-dev-2.qcow2\', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off
    [root@k5-m2 ~]# virsh attach-disk djx-biz-djx1234-dev  /home/kvm/data/djx-biz-djx1234-dev-2.qcow2 vdb --cache writeback --subdriver qcow2 --persistent
    Disk attached successfully
    
    [root@djx-kvm-af3r34t-test data]# virsh domblklist  djx-biz-djx1234-dev
    Target     Source
    ------------------------------------------------
    vda        /home/kvm/data/djx-biz-djx1234-dev.qcow2
    vdb        /home/kvm/data/djx-biz-djx1234-dev-2.qcow2
    hda        -
    
    
  • 虚拟机操作

    [root@localhost ~]# fdisk  -l 
    
    Disk /dev/vda: 85.9 GB, 85899345920 bytes, 167772160 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk label type: dos
    Disk identifier: 0x000a6596
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/vda1   *        2048     1026047      512000   83  Linux
    /dev/vda2         1026048   104857599    51915776   83  Linux
    /dev/vda3       104857600   167772126    31457263+  83  Linux
    
    Disk /dev/vdb: 10.7 GB, 10737418240 bytes, 20971520 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    # 我们可以在系统盘这边看到我们新增加的磁盘,然后我们可以对该磁盘进行初始化和分区,并挂载使用了,注意在挂载的时候需要注意设置开机自动挂载。
    具体操作见 7.1 虚拟机操作-使用新增空间创建新的分区
    

五、常用操作命令

  • 查看虚拟机对应的ip

    virsh list --title
    
  • 登录虚拟机

    • 通过 console

      virsh console djx-biz-qawsed4-test
      
    • 通过 ssh

    • 通过 vnc

      vnc 端口为随机。通过查找对应的进程来获取。

  • virsh list [--all] #查看所有KVM虚拟机

  • virsh dominfo name # 查看虚拟机 CPU/内存的使用率

  • virsh start name #启动KVM虚拟机

  • virsh shutdown name #正常关闭KVM虚拟机、基本是关不掉的

  • virsh autostart name # 设置开机自启

  • virsh autostart –disable name # 关闭开机自启

  • virsh destroy name #强制关闭KVM虚拟机(类似于直接断电)

  • virsh suspend name #挂起KVM虚拟机

  • virsh resume name #恢复挂起的KVM虚拟机

  • virsh dumpxml name #查看KVM虚拟机配置文件

  • virsh edit name #编辑KVM虚拟机的xml配置文件

  • virsh undefine name #彻底删除KVM虚拟机,不可逆,如果想找回来,需要备份/etc/libvirt/qemu的xml文件

  • virsh snapshot-create name #创建快照

  • virsh snapshot-delete name --current/--snapshotname #删除快照

  • virsh snapshot-dumpxml name #导出XML

  • virsh snapshot-list name #查看快照