1 背景信息


本文档是自己在工作中对kvm使用上的一些记录,基于ubuntu 12.04 desktop, 在我的工作笔记本电脑实现,机器带一块以太网卡和一块无线网卡,无线网卡连互联网。

2 文档目的


介绍kvm,包括配置,不使用libvirt层实现的命令行模式虚拟机操作,一些主要参数介绍, 以及kvm虚拟机优化等。在文档中,我会利用kvm命令行方式,实现一个nat模式的虚拟化网 络,虚拟机通过nat访问外网,外网无法访问虚拟机。

3 KVM安装


在ubuntu下需要安装的kvm包:

sudo apt-get install kvm uml-utilities bridge-utils

加载kvm模块:

modprobe kvm-intel

可以先确认是否加载,没有的话可以自己加载(我用的是intel cpu,如果是amd可以通过 kvm-amd加载),修改/etc/modules,在里面添加如下行,使其自动加载:

kvm_intel

如果需要kvm nest功能,上面行需要修改为:

kvm_intel nested=1

同时guest启动命令需要带上如下参数:

-cpu host 或者 -cpu qemu64,+vmx

4 NAT模式虚拟网络


在这里没有使用libvirt,其实用libvirt操作kvm非常方便,这里没用主要是自己希望了解 一下kvm的一些细节,包括虚拟网络创建、参数使用和优化参数等等。

虚拟网络创建通过bridge实现,相比xen的虚拟网络实现,kvm要简单的多,基本就是创建一 个bridge,但是不用绑定到物理网卡上,配置nat策略,同时启用dnsmasq负责guest dhcp即 可,实现方式可以直接修改/etc/qemu-ifup脚本内容如下:

#!/bin/sh
#
# Copyright IBM, Corp. 2010
#
# Authors:
#  Anthony Liguori <aliguori@us.ibm.com>
#
# This work is licensed under the terms of the GNU GPL, version 2.  See
# the COPYING file in the top-level directory.

# Set to the name of your bridge
BRIDGE=virbr0

# Network information
NETWORK=192.168.122.0
NETMASK=255.255.255.0
GATEWAY=192.168.122.1
DHCPRANGE=192.168.122.2,192.168.122.254

# Optionally parameters to enable PXE support
TFTPROOT=
BOOTP=

do_brctl() {
    brctl "$@"
}

do_ifconfig() {
    ifconfig "$@"
}

do_dd() {
    dd "$@"
}

do_iptables_restore() {
    iptables-restore "$@"
}

do_dnsmasq() {
    dnsmasq "$@"
}

check_bridge() {
    if do_brctl show | grep "^$1" > /dev/null 2> /dev/null; then
        return 1
    else
        return 0
    fi
}

create_bridge() {
    do_brctl addbr "$1"
    do_brctl stp "$1" off
    do_brctl setfd "$1" 0
    do_ifconfig "$1" "$GATEWAY" netmask "$NETMASK" up
}

enable_ip_forward() {
    echo 1 | do_dd of=/proc/sys/net/ipv4/ip_forward > /dev/null
}

add_filter_rules() {
do_iptables_restore <<EOF
# Generated by iptables-save v1.3.6 on Fri Aug 24 15:20:25 2007
*nat
:PREROUTING ACCEPT [61:9671]
:POSTROUTING ACCEPT [121:7499]
:OUTPUT ACCEPT [132:8691]
-A POSTROUTING -s $NETWORK/$NETMASK -j MASQUERADE
COMMIT
# Completed on Fri Aug 24 15:20:25 2007
# Generated by iptables-save v1.3.6 on Fri Aug 24 15:20:25 2007
*filter
:INPUT ACCEPT [1453:976046]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1605:194911]
-A INPUT -i $BRIDGE -p tcp -m tcp --dport 67 -j ACCEPT
-A INPUT -i $BRIDGE -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i $BRIDGE -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i $BRIDGE -p udp -m udp --dport 53 -j ACCEPT
-A FORWARD -i $1 -o $1 -j ACCEPT
-A FORWARD -s $NETWORK/$NETMASK -i $BRIDGE -j ACCEPT
-A FORWARD -d $NETWORK/$NETMASK -o $BRIDGE -m state --state RELATED,ESTABLISHED
   -j ACCEPT
-A FORWARD -o $BRIDGE -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i $BRIDGE -j REJECT --reject-with icmp-port-unreachable
COMMIT
# Completed on Fri Aug 24 15:20:25 2007
EOF
}

start_dnsmasq() {
    do_dnsmasq \
	--strict-order \
	--except-interface=lo \
	--interface=$BRIDGE \
	--listen-address=$GATEWAY \
	--bind-interfaces \
	--dhcp-range=$DHCPRANGE \
	--conf-file="" \
	--pid-file=/var/run/qemu-dnsmasq-$BRIDGE.pid \
	--dhcp-leasefile=/var/run/qemu-dnsmasq-$BRIDGE.leases \
	--dhcp-no-override \
	${TFTPROOT:+"--enable-tftp"} \
	${TFTPROOT:+"--tftp-root=$TFTPROOT"} \
	${BOOTP:+"--dhcp-boot=$BOOTP"}
}

setup_bridge_nat() {
    if check_bridge "$1" ; then
	create_bridge "$1"
	enable_ip_forward
	add_filter_rules "$1"
	start_dnsmasq "$1"
    fi
}

setup_bridge_vlan() {
    if check_bridge "$1" ; then
	create_bridge "$1"
	start_dnsmasq "$1"
    fi
}

setup_bridge_nat "$BRIDGE"

if test "$1" ; then
    do_ifconfig "$1" 0.0.0.0 up
    do_brctl addif "$BRIDGE" "$1"
fi
cmdcmd

这样当你在启动一个kvm guest的时候,就会自动创建一个nat模式的网络,bridge名字是 virbr0,guest通过dhcp获得一个192.168.122.0/24网段的ip地址,可以联通互联网。

5 创建虚拟机


5.1 创建镜像

以创建centos虚拟机为例,你首先需要创建一个磁盘镜像文件,也可以是一个块设备:

$kvm-img create -f raw centos.img 10G

这里我们创建了一个raw格式的磁盘镜像文件,大小为10g,注意文件实际并不占用10g空 间,而是按需分配1。关于文件格式的区别简单描述如下:

  • raw格式在文件镜像中性能最优,但是功能支持也少,比如不支持快照,精简分配需要文 件系统支持holes。
  • qcow2是功能丰富,精简配置无须文件系统支持holes,支持压缩和加密,支持快照和 backing_file功能。
  • vdi/vmdk/vpc,分别对应virtualbox/vmware/ms virtualpc

当然你也可以通过lvm来分配一个lv给虚拟机用,块设备性能最佳,当然也有很多问题,可 维护性一般,而且一般也不支持精简配置,其他的分布式块系统比如sheepdog这里就不多说 了。最终目的只有一个,给虚拟机提供磁盘块安装操作系统。

5.2 配置启动参数

有了磁盘镜像文件之后,你就可以启动虚拟机了,由于我们这里直接通过KVM命令行启动虚 拟机,不需要创建额外的xml配置文件。启动虚拟机涉及到组成计算机的几个核心组件: cpu/ram/storage/network/cdrom/soundcard/display,我们一一描述:

  • cpu

    可以通过下面命令查看kvm支持的cpu类型:

    kvm -cpu ?
    

    主要涉及到一些指令集多少问题,qemu32/qemu64兼容性最好,如果你需要支持特定的指 令集,添加即可,比如你需要添加vt指令集,直接"qemu64,+vmx"即可2

    如果你的所有主机CPU一样,可以直接用“-cpu host",这样虚拟机的cpu和宿主机一致, 性能最佳。通过-smp参数设置多cpu支持,通过“-numa”参数模拟多节点numa。

  • storage

    通过下面参数设置:

    -drive file=centos.img if=virtio,cache=none,aio=native
    

    这里涉及到两个参数if和cache:

    1. if用来指定驱动类型,这里我们用的是virtio, virtio绕开qemu模拟层,是优化io的 重要部分,当然前提是你的guest os需要支持virtio,安装对应的驱动。
    2. cache指定缓存模式
      Mode host page cache guest disk write cache
      none off on
      writethough on off
      writeback on on
      unsafe on ignored

      cache设置涉及到两个层面的影响,一个是宿主机的缓存,一个是guest的缓存:3

      host page cache打开意味着数据copy到宿主机缓存即完成写操作,通过fsync刷新缓 存,能够从缓存完成读,但是问题在于guest也会缓存同样的数据,也就意味着同样的 数据在内存中保留两份,一般建议如果是本地设备(包括文件和块设备),建议关闭 宿主机缓存。

      guest disk write cache打开意味着写操作进入缓存即完成,可能存在数据丢失风险 ,能提高写性能。

      一般情况下本地设备建议选择none,性能最佳,如果是远程设备,建议选择writeback 或者writethrough。unsafe一般很少使用,在安装系统的时候使用能加快安装速度, 但是如果进入正式环境使用,需要切换到对应模式。

      另外对于磁盘镜像文件模式,还需要考虑块对齐问题,一般保持和宿主机同样的块大 小,分区块对齐,否则可能引发跨块的io操作,影响io性能。

    3. aio指定io的模式,支持thread和native,native性能更佳。
  • network

    通过下面参数设置:

    -net nic,vlan=0,model=virtio,macaddr=DE:AD:BE:EF:FC:70 \
    -net tap,vlan=0,vhost=on \
    

    缺省qemu使用user mode网络,完全和宿主机隔离,性能差,通常都需要使用tap模式,同 时打开vhost-net特性,vhost-net完全bypass qemu,并且运行在kernel层,能大大降低 cs的开销,性能接近宿主机网络。

    同时采用virtio半虚拟化驱动,相比模拟驱动性能提升明显,前提同样是guest os需要支 持virtio驱动。同时打开两者获取最好的网络性能。另外注意vhost需要加载vhost_net模块:

    modprobe vhost_net
    

    确保使用了vhost_net特性,你只需在启动guest的时候,查看是否有vhost线程存在:

    ps -ef | grep vhost- | grep -v grep
    root      1563     2  0 Feb18 ?        00:00:00 [vhost-1561]
    
  • qemu monitor

    qemu和guest交互的一个控制台,支持多种模式交互,比如unix socket,tcp socket等, 通过下面参数设置:

    -monitor unix:/home/tacy/vm/monitor/centos.monitor,server,nowait
    

    上面是unix socket模式, 这样你可以直接发送system_powerdown指令关机了,相当于按 power键;system_reset相当于按reset键,这个要小心:

    socat - UNIX-CONNECT:/home/tacy/vm/monitor/centos.monitor
    

    直接关闭虚拟机可以通过下面指令:

    echo system_reset|socat - UNIX-CONNECT:/home/tacy/vm/monitor/centos.monitor
    
  • other

    时间同步可以采用ntp或者"-rtc base=localtime,clock=vm", vnc鼠标同步用 "-usbdevice tablet", pass-through usb口用"-usbdevice host:19d2:0117", 关闭 console用"-nographic".

5.3 启动虚拟机

下面是我的启动命令:

sudo kvm -m 2048 -smp 2 -cpu host -enable-kvm -boot c \
    -drive file=/home/tacy/software/CentOS-6.3-x86_64.iso,media=cdrom -boot d \
    -drive file=centos.img,if=virtio,cache=none,aio=native \
    -net nic,vlan=0,model=virtio,macaddr=DE:AD:BE:EF:FC:70 \
    -net tap,vlan=0,vhost=on \
    -soundhw es1370 \
    -rtc base=localtime,clock=vm \
    -usbdevice host:19d2:0117 -usbdevice tablet \
    -monitor unix:/home/tacy/vm/monitor/centos.monitor,server,nowait \
    -vga std -nographic -vnc :0 \
    >/dev/null 2>&1 &

上面我指定了光驱,和从光驱启动,这样你通过vnc就可以连接上虚拟机,进行系统安装了。

6 虚拟机串口


如果你设置了nographic启动参数,你就看不到虚拟机的console了,有时候你希望能看看 console上的一些异常,比如导致启动失败的异常,这时候,你就可以利用虚拟机串口重定 向功能来解决,简单来说,就是让虚拟机把console重定向到串口输出,然后再通过qemu设 置虚拟机串口输出到host设备上,可以是tcp/udp/unix socket/file/pipe,然后在host上 查看虚拟机console信息。

首先需要完成虚拟机重定向console设置,简单修改grub.conf,添加参数:

console=/dev/tty0 console=/dev/ttyS0,115200

设置qemu启动参数,添加如下启动项:

-serial telnet::4446,server,nowait

重启虚拟机,然后你就可以通过telnet连接到虚拟机console上了。这里只是以telnet为例 子,其他的你可以参考qemu man实现,比如你可以直接设置虚拟机串口输出到host当前终端 的stdio,试试就知道了,非常方便。

7 Windows7 guest


7.1 virtio

如果把系统安装在virtio磁盘上,安装的时候必须指定驱动,否则找不到磁盘,驱动下载地 址可以参考Windows guest drivers,另外注意,在安装的时候加载virtio驱动,需要把驱 动光盘防止在第一个光盘驱动器,否则会无法启动,例如:

sudo kvm -m 2048 -smp 2 -cpu host -enable-kvm -boot d \
    -drive file=/home/tacy/vm/software/virtio-win-0.1-30.iso,media=cdrom \
    -drive file=/home/tacy/vm/software/win7/win7_ultimate_sp1.iso,media=cdrom \
    -drive file=win7.template.img,if=virtio,cache=none,aio=native \

采用virtio磁盘安装,我测试了一下,在我机器上不超过15分钟就完成了。

7.2 audio

直接用ac97,不过你需要自己去下载驱动,注意下载win7版本的就行

7.3 usb

说实在的,被这玩意搞死了,实在是不熟悉usb这块,搞了两天才弄明白,如果你用下面方 式加载usb:

-usb -usbdevice host:0951:1624

恭喜你,是有八九你能碰到和我同样的问题,在windows上能发现设备,但是在设备管理器 里面有警告:

usb mass storage usb cannot start code 10

就为这问题,害我重复编译了好几遍qemu,最后看到这两个帖子太恍然大悟4, 5, 查了一下我机器上的usb口:

tacy@tacy:~$ lspci|grep USB
00:1a.0 USB controller: Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 (rev 05)
00:1d.0 USB controller: Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 (rev 05)

没错,我的是ehci,不是uhci,而qemu用-usb方式模拟出来的是uhci,搞半天,在uhci上接 了2.0的设备,不能正常驱动,知道原因,解决起来就简单了:

-device usb-ehci,id=ehci \
-drive if=none,id=usbstick,file=/dev/sdX \
-device usb-storage,bus=ehci.0,drive=usbstick \

其中的sdX是你的usb驱动名,这样你就可以正常在windows上看到usb驱动器了,后面两行可 以通过monitor动态添加,但是第一行必须带上:

drive_add 0 id=usbdrive,if=none,file=/dev/sdX
device_add usb-storage,id=usbdrive,bus=ehci.0,drive=usbdrive

7.4 shutdown(about winxp and win2003)

gpedit.msc (允许无用户登入关机)

Computer Configuration\Windows Settings\Security Settings\Local Policies\
Security Options\Shutdown: Allow system to be shut down without having to log on

regedit (有用户登入时,提示超时关机)

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows]  "ShutdownWarningDialogTimeout"=dword:00000001

8 Spice


很不幸,在ubuntu12.04上要用spice缺省是不行的,首先,缺省的kvm包不带spice功能,需 要另外安装qemu-kvm-spice,但是这个版本有bug6,用这个包启动黑屏并且CPU 100% ,没法启动虚拟机。查了一圈,有人说是seabios问题,也有人说改改配置就可以,我试了 试都不好使。bug里面说ubuntu 12.10里面的版本已经解决了这个问题,但咱这是工作电脑 ,不能随便升级,所以只能自己动手编译。

更悲剧的事情是,spice由于是redhat开发的,对ubuntu极不友好,依赖的一些包在fedora 上是标准包但在ubuntu上都没有,必须自己去编译,我这里主要参考了两个文档7, 8

8.1 准备软件包

下载相关依赖包和代码9

sudo apt-get install libtool libnss3-dev libxrandr-dev libxfixes-dev
  libaio-dev libsasl2-dev libjpeg8-dev libpixman-1-dev libcap-dev
  libattr1-dev libusb-1.0.0-dev texinfo
wget http://downloads.us.xiph.org/releases/celt/celt-0.5.1.3.tar.gz
wget http://spice-space.org/download/releases/spice-protocol-0.12.4.tar.bz2
wget http://spice-space.org/download/releases/spice-0.12.2.tar.bz2
wget http://spice-space.org/download/libcacard/libcacard-0.1.2.tar.bz2
wget http://spice-space.org/download/usbredir/usbredir-0.6.tar.bz2
wget http://wiki.qemu-project.org/download/qemu-1.3.1.tar.bz2

这里的celt版本是指定版本,缺省ubuntu 12.04上的版本不行,必须安装这个版本,注意, 我这里由于没有使用virt-manager,使用系统里面相关的spice包都被我删除了,一般你的情 况不一样,应该不用从头编译10,另外这里没用spice代码库里的qemu,而是直接用的 qemu代码库里的代码,我试了试没问题,应该是合并了。

8.2 编译软件包

  1. celt,注意我们这里缺省都安装在/usr/local下,以免出现覆盖系统包的情况
    tar zxvf celt-0.5.1.3.tar.gz
    cd celt-0.5.1.3
    ./configure --prefix=/usr/local
    make -j5
    sudo make install
    
  2. libcacard
    cd libcacard
    ./configure --prefix=/usr/local
    make -j5
    sudo make install
    
  3. usbredir
    cd usbredir
    ./configure --prefix=/usr/local
    make -j5
    sudo make install
    
  4. spice-protocol
    cd spice-protocol
    #./configure --prefix=/usr/local
    make -j5
    sudo make install
    
  5. spice
    cd spice
    ./configure --prefix=/usr/local --enable-client --enable-smartcard
    make j5
    sudo make install
    
  6. qemu,这里编译没有带sdl,这样qemu启动不会弹出窗口,如果你需要,添加相关编译参数即可
    cd qemu
    ./configure --prefix=/usr/local \
        --target-list=x86_64-softmmu \
        --extra-cflags="-march=native -O2 -no-omit-framepoint -pipe" \
        --extra-ldflags="-Wl,-Bsymbolic-functions -Wl,-z,relro" \
        --audio-drv-list="pa,alsa,oss" \
        --enable-kvm --enable-linux-aio --enable-spice \
        --enable-vhost-net --enable-vnc --enable-virtfs \
        --enable-system --enable-usb-redir --enable-docs
    make j5
    sudo make install
    

    参考了ubuntu qemu-kvm包编译11和gentoo编译优化12

编译过程中,可能会出现动态库找不到的情况,确保LD_LIBRARY_PATH包括/usr/local/lib 目录,这样你就可以用spice了。13

8.3 启动虚拟机

启动windows虚拟机

sudo LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH} qemu-system-x86_64 \
    -m 2048 -smp 2 -cpu host -enable-kvm -boot d \
    -drive file=win7.template.img,if=virtio,cache=none,aio=native \
    -net nic,vlan=0,model=virtio,macaddr=DE:AD:BE:EF:FC:74 \
    -net tap,vlan=0,vhost=on \
    -soundhw ac97 \
    -rtc base=localtime,clock=vm \
    -device virtio-serial-pci \
    -device usb-ehci,id=ehci \
    -drive if=none,id=usbstick,file=/dev/sdc \
    -device usb-storage,bus=ehci.0,drive=usbstick \
    -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 \
    -chardev spicevmc,id=spicechannel0,name=vdagent \
    -monitor unix:/home/tacy/vm/monitor/win7.monitor,server,nowait \
    -vga qxl -spice port=5900,addr=127.0.0.1,disable-ticketing \
    >/dev/null 2>&1 &

8.4 客户端连接

启动spice客户端spicec

/usr/local/bin/spicec -h localhost -p 5900 -f

为了获得更好的性能,需要在虚拟机上安装spice guest tools,直接去spice网站下载 spice-guest-tools即可:http://www.spice-space.org/download.html, 里面已经包括 了qxl驱动和guest agent。

8.5 usbredir14

简单来说,就是客户端机器上插入的usb存储设备能够在vm上发现并使用,举例来说,你用 你的笔记本电脑通过网络访问远程虚拟机,那么插入你笔记本电脑上的usb存储设备能在虚 拟机上使用。目前支持usbredir的spice客户端只有spice-gtk,我们下面来编译spice-gtk ,使他具有usbredir功能:

  1. 下载spice-gtk代码:
    wget http://spice-space.org/download/gtk/spice-gtk-0.18.tar.bz2
    
  2. 编译包:
    cd spice-gtk
    ./configure --prefix=/usr/local --with-gtk=2.0 --enable-usbredir=yes \
      --enable-smartcard=yes --with-python=yes
    make
    sudo make install
    
  3. 运行虚拟机命令增加usbredir设置: 首先需要一个ich9-ehci-uhci.cfg文件,你可以从qemu代码里面找,在 src/qemu1.3.1/docs目录下,拷贝到/usr/local/etc/qemu/目录下
    cp qemu1.3.1/docs/ich9-ehci-uhci.cfg /usr/local/etc/qemu/
    

    然后需要修改虚拟机启动脚本,添加如下三行

    -readconfig /usr/local/etc/qemu/ich9-ehci-uhci.cfg \
    -chardev spicevmc,name=usbredir,id=usbredirchardev1 \
    -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,debug=3 \
    

    然后启动虚拟机,并用spicy连接

    sudo spicy -h localhost -p 5900
    

    选中spicy option菜单中的auto connection选项,在客户端中插入usb设备,不出意外 的话,你就能在虚拟机上看到插入的usb设备了。

9 Base image & Snapshot


9.1 base image15

base image简单可以理解为模板,举个例子,你在部署公司的虚拟化环境,公司的所有的系 统都跑在centos上,只是上面配置的应用各有不同,有c开发的,有java开发的等等,简单 来说,你会先安装一个base image

$kvm-img create -f qcow2 centos.qcow2 10g
$kvm -drive file=centos.qcow2 -m 1024 -boot d -drive file=centos.iso,media=cdrom

安装完操作系统和相应补丁之后,你可以从你的base image创建一个新的image:

$kvm-img create -b centos.qcow2 -f qcow2 centos-clone.qcow2

新的image文件并不会实际占用空间,他链接在base image上,只有修改之后,才会通过 copy on write方式保存修改内容到新的image文件:

$kvm-img info centos-clone.qcow2
image: centos-clone.qcow2
file format: qcow2
virtual size: 10G (10737418240 bytes)
disk size: 136K
cluster_size: 65536
backing file: centos.qcow2 (actual path: centos.qcow2)

你可以从centos-clone.qcow2启动虚拟机,然后完成配置,然后重新rebase该clone,生成 新的base image:

kvm-img convert centos-clone.qcow2 -O qcow2 centos-base-java.qcow2

9.2 移动base image

有时候,为了运维的目的,你可能需要移动base image, 这个时候你需要重新rebase所有相 关的clone,否则clone就会出错:

kvm-img rebase -f qcow2 -u -b centos54.img -F raw centos-clone.qcow2

9.3 snapshot16

快照是虚拟机一个常用的功能,你可以利用快照功能来保留某个时间点的虚拟机状态,方便 虚拟机回滚。离线快照参考man手册即可。在线快照通过monitor或者QMP实现。

10 qemu概念

10.1 arm-softmmu和arm-linux-user区别

前者是指模拟的硬件平台;后者是直接在宿主平台运行arm程序,无须安装android系统即 可运行。

11 其他相关


11.1 查看虚拟机ip地址

如果虚拟机很少,简单通过“arp -an”查看即可,如果虚拟机很多,你不容易找到ip和mac的 对应关系,需要自己写脚本去实现了17.

11.2 查看设备信息

进入monitor, 然后用info qtree命令查看设备信息.



blog comments powered by Disqus