QEMU KVM 虚拟机制作

🌟Overview

应使用 libvirt 进行操作、管理. libvirt 使用 XML 来定义各种对象, 最好使用 virt-manager 创建虚拟机然后在配置文件里进行修改, 也可使用 virt-install 创建.

XML 格式官方说明

🌟模拟网卡设置

1
2
3
4
5
6
7
8
9
10
11

# qemu/kvm 命令行操作

# 指定网卡为 Intel e1000

kvm ... -net nic,model=e1000,macaddr=mac,addr=addr

# 指定使用 virtio 类型 (准虚拟化的I/O驱动) 的网卡设备

kvm ... -net nic,model=virtio

🌟vhost-net

virtioHost 端的后端处理程序 (backend) 一般是由用户空间的 QEMU 提供的. vhost-net 是一个驱动模块, 是内核级别的后端处理程序, 将 virtio-net 的后端处理任务放到内核空间执行, 减少内核态与用户态之间的 context 切换, 从而提高效率.

1
2
3
4
5
6
7
8
9
10
11
12
13

<!-- 使用 qemu-kvm 命令行时, 加上 vhost=on 即启用, off 即关闭而使用 qemu -->

<!-- 使用 libvirt 时, Guest 配置文件设置即启用 vhost-net -->

<interface type="network">

<model type="e1000" />

<driver name="vhost" />

</interface>

🌟virtio-balloon

  • Host: 检查virtio-balloon 设备

  • Guest: 如果时 Linux 则检查 CONFIG_VIRTIO_BALLOON=m 及驱动, 如果是 Windows 检查驱动 virtio_ballon.

  • 实例: kvm -smp 2 -m 2048 -drive file=xxx.qcow2,if=ide,media=disk,format=qcow2 -boot c -name Centos6 -net nic,model=e1000 -balloon virtio

  • 动态调整 VM 内存: 在 Host 中进入 QEMU Monitor Console,

    • 输入 info balloon 查看 气球 信息

    • 输入 balloon 512 将 VM 的内存调整为 512M

🌟多队列 Virtio-net

可处理大流量网络, 一个队列独占一个虚拟 CPU (会增加 CPU 的负担), 启用多队列 Virtio-net, 需要在虚拟机的 XML 配置文件中增加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13

<interface type='network'>

<source network='default' />

<module type='virtio' />

<driver name='vhost' queues='N' />

</interface>

<!-- 然后在主机上运行命令: ethtool -L eth0 combined M (1 <= M <= N) -->

🌟libvirt 虚机 XML 配置之磁盘定义

任何磁盘设备, 包括软盘、硬光驱或者半虚拟化驱动都使用 <disk> 标签来定义.

  1. volume 类型的 disk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

<!-- type 用来指定 device source 类型(表现在 Host 中): file/block/dir/network/volume, 具体则由 child 中的 <source> 标签定义 -->

<!-- device 用来指定 device target 类型(表现在 Guest 中): floppy/disk/cdrom/lun, 具体设置由 child 中的 <target> 标签定义 -->



<!-- volume 类型的 disk -->

<disk type='volume' device='disk'>

<driver name='qemu' type='raw' />

<source pool='blk-pool0' volume='blk-pool0-vol0' />

<target dev='hdk' bus='ide' />

</disk>



<!-- file 类型的 disk -->

<disk type='file' snapshot='external'>

<driver name='tap' type='aio' cache='default' />

<source file='/var/lib/xen/images/fv0' startupPolicy='optional' />

<target dev='hda' bus='ide' />

</disk>



<!-- block 类型的 disk -->

<disk type='block' device='cdrom'>

<driver name='qemu' type='raw' />

<target dev='hdd' bus='ide' tray='open' />

<readonly/>

</disk>



<!-- network 类型的 disk -->

<disk type='network' device='cdrom'>

<driver name='qemu' type='raw' io="threads" ioeventfd="on" event_idx="off"/>

<source protocol='http' name='url_path'>

<host name='hostname' port="80" />

</source>

<target dev='hdd' bus='ide' />

<boot order='1'/>

</disk>

🌟libvirt 虚机 XML 配置之网卡定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

<!-- #virsh: attach-interface --domain dom1 --type network --source isolatednet1 --mac 00:11:22:33:44:55 -config -->

<devices>

<!-- 定义一个连接 Virtual Network 的 interface -->

<interface type="network">

<source network='default' />

</interface>

...

<interface type='network'>

<source network='hostntw' portgroup='engineering' />

<target dev='vnet7' />

<mac address="00:11:22:33:44:55" />

<virtualport>

<parameters instanceid09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f />

</virtualport>

</interface>

</devices>



<!-- type='bridge' 定义一个 Bridge 2 LAN 的 interface: 前提是 Host 上存在一个 bridge, 该 bridge 已经连到 物理 LAN -->

<!-- 桥接到 br0 -->

<interface type='bridge'>

<source bridge='br0' />

</interface>



<!-- 桥接到 br1 -->

<interface type='bridge'>

<source bridge='br1' />

<target dev='vnet7' />

<mac address="00:11:22:33:44:55" />

</interface>



<!-- type='ethernet' 定义一个使用指定脚本连接到 LAN 的 interface -->

<interface type='ethernet'>

<target dev='vnet7' />

<script path='/etc/sysconfig/network-script/ifcfg-vnet7' />

</interface>

🌟libvirt 虚机 XML 配置之网络定义

定义一个用于构造该虚拟网络的网桥:

1
2
3

<bridge name='virbr0' stp='on' delay='5' macTableManager='libvirt' />

定义 DHCP server 的 DNS domain:

1
2
3
4
5

<domain name="example.com" localOnly='no' .>

</domain>

定义虚拟网络直接联到物理 LAN 的方式. mode 指的是转发模式 [nat/route/bridge]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

<network>

<name>default</name>

<bridge name='virbr0' />

<forward mode='nat'/>

<!-- OR 指定公共 IP 地址和端口-->

<forward mode='nat'>

<nat>

<address start='1.2.3.4' end='1.2.3.10'/>

</nat>

</forward>

<forward mode='nat'>

<nat>

<port start='500' end='10000'/>

</nat>

</forward>

<ip address="192.168.122.1" netmask="255.255.255.0">

<dhcp>

<range start="192.168.122.2" end="192.168.122.254" />

</dhcp>

</ip>

<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />

</network>



<!-- route 模式: 类似于 nat, 但使用 routing-table -->

<!-- bridge 模式: 使用不受 libvirt 管理的 bridge, 比如主机上已有的bridge -->

<network>

<name>host-bridge</name>

<forward mode='bridge' />

<bridge name='br0' />

</network>



<!-- Host-Only 模式 -->

<network>

<name>hostntw</name>

<bridge name='virbr1' stp='on' delay='0' />

<ip address='192.168.15.250' netmask='255.255.255.0' />

</network>

<!-- # virsh net-define hostntw.xml -->

<!-- # virsh net-autostart hostntw -->

<!-- # virsh net-start hostntw -->

<!-- # virsh net-info/list/dumpxml hostntw -->

🌟libvirt 虚机 XML 配置之 CPU 定义

参考文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<!-- 1. 使用设备直接分配(Device Pass-Through), 基本不需要 KVM 的涉入可能影响迁移 -->

<cpu mode='host-passthrough' >

<feature name='vmx' policy='disabled' />

...

</cpu>



<!-- 2. 由 QEMU 自动选择 -->

<cpu mode='host-model' >

<feature name='vmx' policy='disabled' />

...

</cpu>



<!-- 3. 自定义 CPU 型号, 可动态增添 CPU 功能 -->

<cpu mode='custom' >

<model>Westmere</model>

<feature name='pcid' policy='require' />

...

</cpu>

🌟使用 libvirt API 管理 KVM 虚机

基本过程:

  • 定义虚机的基本配置,包括 vCPU、内存、磁盘或者 ccdrom 以及启动顺序, 生成 xml 配置文件; 调用 virDomainCreateXML 接口来启动虚机.

  • 使用 Domain 相关的 API 来管理虚拟机的生命周期. 参考

  • 添加磁盘 (virsh define domain.xml): 定义一个 disk 的 xml 配置, 使用 virDomainAttachDevice API将其关联到虚机上.

  • 添加 NIC (virsh net-define nic.xml): 使用 Network API 定义一个虚拟网络, 然后定义一个 interface 的 XML 配置, 使用 virDomainAttachDevice API 将其关联到虚拟机.

  • 创建快照: virsh snapshot-create-as DomainName SnapName

  • 恢复快照: virsh snapshot-revert DomainName SnapName

  • 删除快照: virsh snapshot-delete DomainName SnapName

  • 删除 Domain (需要先删除快照): virsh undefine DomainName, 然后清除磁盘文件

🌟virt-install 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 使用已装好系统的虚拟磁盘, 创建新的虚拟机定义, 创建好之后就可以使用 libvirt 进行管理了

## 可配合 virt-sysprep 使用, 该工具可重置 .qcow2 内部数据里的一些设置

## virt-sysprep -a <Image File>

## --import 从已存在的 disk img 中创建guest; 更多说明见 -h

qemu-img create -f qcow2 500G



virt-install --name DomainName --vcpus=2 --cpu host-passthrough --memory 2048 --disk path=/data/images/dom.qcow2,bus=virtio(ide),cache=writeback,size=0(不分配初始大小,自增长, 前面创建已限制最大值) --disk path=/data/images/config.iso,device=cdrom --graphics vnc,listen=0.0.0.0,password=foobar,port=5901 --network network=hostntw(bridge=virtbr1),model=e1000(virtio) --noautoconsole --os-type=windows --boot=hd -v(全虚拟化) --virt-type kvm --os-variant win7 --check path_in_use=off


## 安装完后重新设置 boot device, virsh edit DomainName


# 使用镜像安装系统

## 首先创建一块虚拟机磁盘

qemu-img create -f qcow2 500G

## 或者从 vmdk 转换

qemu-img convert -O qcow2 -c in.vmdk out.qcow2

## 使用 virt-install 安装、定义

virt-install ...

## 防火墙开放端口

firewall-cmd --add-port=5901/tcp --zone=public --permanent

firewall-cmd --reload

## 使用 virtsh 管理

virsh edit DomainName