QEMU (Quick Emulator) 提供了硬件和处理器虚拟化, 它跑在用户态, 无需内核.
话不多说, 直接用起来. 我使用的 OS 是 Ubuntu16.
apt-get update
apt-get install qemu
然后检查一下
dpkg --list | grep qemu
curl -OL https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2
经过漫长的等待, 检查一下
qemu-img info CentOS-7-x86_64-GenericCloud.qcow2
会输出 format qcow2, virtual size 8G.
qemu-system-x86_64 -name zc -cpu Nehalem -m 1024 -drive format=qcow2,file=CentOS-7-x86_64-GenericCloud.qcow2 -vnc 0.0.0.0:0 -daemonize
-cpu Nehalem Nahalem Intel Core i7, -m 1024 1G 内存, -drive 指定刚才下载的镜像, -vnc 绑定一个端口让你访问虚拟机
然后检查一下
pgrep -la qemu
如果要停止的话直接
pkill -9 qemu
我 macOS 下载了一个 VNC Viewer, 然后在 GUI 上连接 Ubuntu 的 IP:5900, 顺利连接, 然后让我登录, 但我不知道 root 和密码.
改镜像密码, 先下载
apt install -y libguestfs-tools
然后设置 root 密码为 root
virt-customize -a CentOS-7-x86_64-GenericCloud.qcow2 --root-password password:root
会报错 virt-customize: error: libguestfs error: guestfs_launch failed., 这是因为在这个镜像上正跑着一个 VM 呢, 关掉先.
改好密码后最后重新启动一个虚拟机, VNC 连接登录, 成了.
进去后检查一下 cpu, memory, disk
free -h
lscpu
df -h
应该是和我们指定的一样的, 分别是 1G, 1C, 8G.
KVM (Kernel-based Virtual Machine) 和 QEMU 最大的不同是它跑在内核态, 所以需要内核支持.
先检查 cpu 支持 KVM 虚拟化:
lscpu | grep vmx | uniq
然后检查内核模块
modprobe kvm
lsmod | grep kvm
那么来吧
qemu-system-x86_64 -name zc -cpu Nehalem -m 1024 -drive format=qcow2,file=CentOS-7-x86_64-GenericCloud.qcow2 -vnc 0.0.0.0:0 -enable-kvm -daemonize
注意新增的 -enable-kvm.
另一种做法是下载 kvm 二进制
apt install qemu-kvm
kvm -name zc -cpu Nehalem -m 1024 -drive format=qcow2,file=CentOS-7-x86_64-GenericCloud.qcow2 -vnc 0.0.0.0:0 -daemonize
不过本质上 kvm 二进制只是把 qemu-system-x86_64 包了一下, pgrep -la qemu 看到两种拉起来的进程是一样的.
libvirt 对不同的虚拟化技术提供了统一的上层接口, 比方说管理 QEMU/KVM, XEN, LXC.
apt install -y libvirt0-dbg/xenial-updates
apt install -y libvirt-bin
然后 libvirtd daemon 就起来了
systemctl status libvirtd
看看配置
cat /etc/libvirt/libvirtd.conf | grep -v '^#\|^$'
很多东西在 /etc/libvirt/ 里, 猫一眼
# ls -lF /etc/libvirt/
total 84
drwxr-xr-x 2 root root 4096 Mar 11 21:52 hooks/
-rw-r--r-- 1 root root 450 Mar 11 21:52 libvirt-admin.conf
-rw-r--r-- 1 root root 547 Mar 11 21:52 libvirt.conf
-rw-r--r-- 1 root root 15276 Mar 11 21:52 libvirtd.conf
-rw-r--r-- 1 root root 834 Mar 11 21:52 libxl.conf
-rw-r--r-- 1 root root 2169 Mar 11 21:52 libxl-lockd.conf
-rw-r--r-- 1 root root 1235 Mar 11 21:52 lxc.conf
drwxr-xr-x 2 root root 4096 May 19 22:23 nwfilter/
drwxr-xr-x 3 root root 4096 May 19 22:23 qemu/
-rw------- 1 root root 19536 Mar 11 21:52 qemu.conf
-rw-r--r-- 1 root root 2169 Mar 11 21:52 qemu-lockd.conf
-rw-r--r-- 1 root root 2134 Mar 11 21:52 virtlockd.conf
-rw-r--r-- 1 root root 1802 Mar 11 21:52 virtlogd.conf
-rw-r--r-- 1 root root 1217 Mar 11 21:52 virt-login-shell.conf
关注 libvirt.conf 是给 libvirt client 用的, libvirtd.conf 是给 libvirtd 用的, qemu.conf 是 libvirtd 驾驭 QEMU/KVM 的配置, qemu/ 里是创建的 VM 配置
先安装工具
apt install virtinst/xenial-updates
然后生成 libvirt domain xml
virt-install --name v2 --ram 1024 --disk path=CentOS-7-x86_64-GenericCloud.qcow2,format=qcow2 --print-xml > v2.xml
看一下 v2.xml
<domain type="kvm">
<name>v2</name>
<uuid>27144641-23ff-42ad-9bd5-6ab0a4ff6ec7</uuid>
<memory>1048576</memory>
<currentMemory>1048576</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch="x86_64">hvm</type>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode="custom" match="exact">
<model>Broadwell-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>restart</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="qcow2"/>
<source file="/root/CentOS-7-x86_64-GenericCloud.qcow2"/>
<target dev="hda" bus="ide"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<interface type="network">
<source network="default"/>
<mac address="52:54:00:d5:af:0b"/>
</interface>
<input type="mouse" bus="ps2"/>
<graphics type="spice" port="-1" tlsPort="-1" autoport="yes">
<image compression="off"/>
</graphics>
<console type="pty"/>
<channel type="spicevmc">
<target type="virtio" name="com.redhat.spice.0"/>
</channel>
<sound model="ich6"/>
<video>
<model type="qxl"/>
</video>
<redirdev bus="usb" type="spicevmc"/>
<redirdev bus="usb" type="spicevmc"/>
</devices>
</domain>
关注里面的 disk, vcpu, memory 的值; 你也可以直接编辑文件修改.
然后用 libvirt client virsh
virsh define v2.xml
检查一下, 启动起来
virsh list --all
virsh start v2
发现报错 error: Cannot access storage file '/root/CentOS-7-x86_64-GenericCloud.qcow2' (as uid:64055, gid:121): Permission denied, 看一下 uid 64055 是用户 libvirt-qemu, 读不了 /root/, 所以把镜像放在 /opt/qemu-img/ 下
mkdir /opt/qemu-img/
cp /root/CentOS-7-x86_64-GenericCloud.qcow2 /opt/qemu-img/v2.qcow2
然后改下 xml 里的镜像路径到 /opt/qemu-img/v2.qcow2, 重来一遍
virsh undefine v2
virsh define v2.xml
virsh start v2
virsh list
成功!
创建好的 vm 的 xml 都在 /etc/libvirt/qemu/ 里.
pgrep qemu -la 能看到启动的进程依然是 qemu-system-x86_64 那一套, 只不过 flag 爆多
29915 qemu-system-x86_64 -enable-kvm -name v2 -S -machine pc-i440fx-xenial,accel=kvm,usb=off -cpu Broadwell-IBRS -m 1024 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid ab376ac8-20bf-43cb-abdd-a43cfb472f2f -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-v2/monitor.sock,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -boot strict=on -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x6.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x6 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x6.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x6.0x2 -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x5 -drive file=/opt/qemu-img/v2.qcow2,format=qcow2,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=26,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:d8:a3:e7,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -chardev spicevmc,id=charchannel0,name=vdagent -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0 -spice port=5900,addr=127.0.0.1,disable-ticketing,image-compression=off,seamless-migration=on -device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vgamem_mb=16,bus=pci.0,addr=0x2 -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -chardev spicevmc,id=charredir0,name=usbredir -device usb-redir,chardev=charredir0,id=redir0 -chardev spicevmc,id=charredir1,name=usbredir -device usb-redir,chardev=charredir1,id=redir1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 -msg timestamp=on
注意到第二个虚拟机并没有开放端口和 vnc 服务, 我们用 virsh console
virsh console v2
输入密码 root.
当前的内存状态
xmllint --xpath 'string(//memory)' /etc/libvirt/qemu/v2.xml
xmllint --xpath 'string(//currentMemory)' /etc/libvirt/qemu/v2.xml
输出是一样的 1048576
currentMemory 必须比 memory 小, 出现两个内存值的目的是让 VM 可以调整内存 on the fly
virsh setmem v2 --size 500000
这时候通过 console 进去 free -m 就会发现内存减少了
同样可以把 memory 调大, 以增加 currentMemory, 不过必须停机先
virsh destroy v2
virsh setmaxmem v2 --size 2097152
virsh start v2
virsh setmem v2 --size 2097152
通过 virsh setmem 命令修改资源是不会同步修改到 xml 里的, 要注意
在镜像里 df -h 能看到
/dev/sda1 8.0G 850M 7.2G 11% /
这里的 8G 是镜像里定义的
qemu-img info /opt/qemu-img/v2.qcow2
要修改的话
qemu-img resize -f qcow2 /opt/qemu-img/v2.qcow2 +2GB
重启
virsh destroy v2
virsh start v2
然后 fdisk 传统技能走一套
fdisk -l /dev/sda
看到已经是 10G 了, 接下来是传统杂技时间, fdisk /dev/sda 分区, 不表演.
直接改 xml
virsh edit v2
修改 vcpu 的值为 2
<vcpu placement='static'>2</vcpu>
然后重启
virsh destroy v2 && virsh start v2
再进去检查 lscpu 可以看到已经是 2 核
我们玩传统点, 网桥+TUN/TAP.
先创建 TUN/TAP
ip tuntap a dev tap0 mode tap
ip l s tap0 up
然后创建网桥
ip l a name bri0 type bridge
ip l s bri0 up
ip a a 10.16.0.1/16 dev bri0
然后把 tap0 连到 bri0
ip l s tap0 master bri0
然后创建 KVM
kvm -name v3 -cpu Nehalem -m 1024 -drive format=qcow2,file=/opt/qemu-img/v3.qcow2 -vnc 0.0.0.0:1 -net tap,ifname=tap0,script=/bin/true -net nic,macaddr=c6:3a:0d:2a:2e:b1 -daemonize
然后通过 vnc 登录上去, 在 vm 里配置 ip 和路由
ip a a 10.16.0.2 dev eth0
ip r a default dev eth0
然后在 vm 和 host 可以互 ping 了.
就是这么简单.