前言
libvirt是一套用于管理虚拟机平台的工具,其官网[6]包含更多详细信息。相比QEMU命令集,libvirt更方便,且支持不同的虚拟化技术,如QEMU/KVM、Xen和LXC容器等。
1. libvirt的安装和配置
根据官方文档[6],在Ubuntu上可以直接使用apt安装libvirt:
apt update && apt-get install -y libvirt-bin libvirt-doc
安装完成后,我们确认一下libvirt守护进程在正常运行:
➜ ~ pgrep -lfa libvirtd
3973 /usr/sbin/libvirtd
看一下默认配置(排除了注释内容):
➜ ~ cat /etc/libvirt/libvirtd.conf | grep -vi "#" | sed '/^$/d'
unix_sock_group = "libvirt"
unix_sock_ro_perms = "0777"
unix_sock_rw_perms = "0770"
auth_unix_ro = "none"
auth_unix_rw = "none"
修改配置文件/etc/libvirt/qemu.conf
,将QEMU的安全驱动置空(这样做关闭了QEMU的SELinux、AppArmor等安全驱动):
sed -i 's/^#security_driver.*=.*"selinux"$/security_driver = "none"/g' /etc/libvirt/qemu.conf
重启libvirt守护进程:
➜ ~ /etc/init.d/libvirtd restart
[ ok ] Restarting libvirtd (via systemctl): libvirtd.service.
安装配置完成。最后再看一眼libvirt的配置目录吧:
➜ ~ ls /etc/libvirt/
hooks libxl.conf qemu secrets
libvirt-admin.conf libxl-lockd.conf qemu.conf virtlockd.conf
libvirt.conf lxc.conf qemu-lockd.conf virtlogd.conf
libvirtd.conf nwfilter qemu-sanlock.conf virt-login-shell.conf
2. 定义虚拟机实例
在libvirt中,创建虚拟机的操作被称为define
(定义)。与Kubernetes依赖YAML描述文件创建Pod类似,libvirt创建虚拟机依赖XML文件。我们可以手写虚拟机的XML定义文件,也可以使用virt-install
自动生成XML定义文件。
手动编写XML较为复杂,将以下内容保存为kvm1.xml
:
<domain type='kvm' id='1'>
<name>kvm1</name>
<memory unit='KiB'>1048576</memory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>
<boot dev='hd'/>
</os>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/tmp/debian.img'/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<interface type='network'>
<source network='default'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<graphics type='vnc' port='5900' autoport='yes' listen='172.16.56.201'>
<listen type='address' address='172.16.56.201'/>
</graphics>
</devices>
<seclabel type='none'/>
</domain>
可以将上述XML文件与Kubernetes Pod的YAML文件对照,会发现很多有意思的地方。
执行virsh命令创建虚拟机并查看:
➜ ~ virsh define ./kvm1.xml
Domain kvm1 defined from ./kvm1.xml
➜ ~ virsh list --all
Id Name State
----------------------------------------------------
- kvm1 shut off
创建成功。不过,前面提到,我们可以使用virt-install
命令将这个过程自动化。首先安装该工具:
apt install -y virtinst
来尝试一下:
➜ ~ virt-install --name kvm1 --ram 1024 --disk path=/tmp/debian.img,format=raw --graphics vnc,listen=172.16.56.201 --noautoconsole --hvm --import
WARNING No operating system detected, VM performance may suffer. Specify an OS with --os-variant for optimal results.
Starting install...
Domain creation completed.
该命令将直接创建并启动虚拟机:
➜ ~ virsh list --all
Id Name State
----------------------------------------------------
3 kvm1 running
可以在/etc/libvirt/qemu
下找到该虚拟机的定义文件kvm1.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 kvm1
or other application using the libvirt API.
-->
<domain type='kvm'>
<name>kvm1</name>
<uuid>b283c958-2e93-4ebe-a7bc-cf2982e938cf</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-3.1'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='custom' match='exact' check='partial'>
<model fallback='allow'>Broadwell-noTSX-IBRS</model>
</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/bin/kvm-spice</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/tmp/debian.img'/>
<target dev='hda' bus='ide'/>
<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>
<interface type='network'>
<mac address='52:54:00:57:3c:24'/>
<source network='default'/>
<model type='rtl8139'/>
<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>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='172.16.56.201'>
<listen type='address' address='172.16.56.201'/>
</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='0x05' function='0x0'/>
</memballoon>
</devices>
</domain>
可以看到,比我们自己写的要复杂一些。
3. 管理虚拟机实例
官方文档[3]对libvirt创建的虚拟机的生命周期做了很清晰的描述,如下图所示:
这张图与Kubernetes中Pod的生命周期有很多相似之处,我们可以类比学习。
上一节,我们尝试了手动编写XML文件并创建虚拟机,创建后的虚拟机处于shut off
状态。我们尝试启动它,然后查看QEMU进程,可以发现libvirt已经通过QEMU启动了虚拟机:
➜ ~ virsh start kvm1
Domain kvm1 started
➜ ~ pgrep -lfa qemu
6821 /usr/bin/qemu-system-x86_64 -name guest=kvm1,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-6-kvm1/master-key.aes -machine pc-i440fx-trusty,accel=kvm,usb=off,dump-guest-core=off -m 1024 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid a80e675c-45aa-4f6a-a37e-f98a03627ac2 -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-6-kvm1/monitor.sock,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -no-acpi -boot strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/tmp/debian.img,format=raw,if=none,id=drive-ide0-0-0 -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 -netdev tap,fd=25,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:d7:93:9a,bus=pci.0,addr=0x3 -vnc 172.16.56.201:0 -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 -msg timestamp=on
➜ ~ virsh list --all
Id Name State
----------------------------------------------------
6 kvm1 running
最后,强制关机并销毁该虚拟机:
➜ ~ virsh destroy kvm1
Domain kvm1 destroyed
➜ ~ virsh undefine kvm1
Domain kvm1 has been undefined
4. 审查和编辑虚拟机配置
前面曾说过,已创建的虚拟机的定义文件都在/etc/libvirt/qemu/
目录保存。
我们可以到上述目录查看,也可以直接通过以下命令获得虚拟机实例的定义文件(可以用于创建一台新的虚拟机,但是要注意修改<name>
和<uuid>
值确保不同):
virsh dumpxml kvm1 # kvm1 is name of vm instance
该命令与Kubernetes中获取Pod的YAML声明文件的操作十分相像:
kubectl get pods pod-name -o yaml
除此之外,我们还可以借助virsh
命令更新配置,从而更新虚拟机:
virsh edit kvm1 # kvm1 is name of vm instance