Mctrain's Blog

What I learned in IT, as well as thought about life

Running Xen on Xen:Xen的嵌套虚拟化技术

| Comments

这篇博文是一个简单的教程,介绍如何在Xen的虚拟机中运行另外一个虚拟机,说白了,就是Xen的嵌套虚拟化技术。

安装Xen

关于如何安装Xen,首选的是看Xen的官方教程

不过由于里面说的比较复杂,所以本教程就简单的把几个步骤列一下:

直接安装

这个我没试过,因为我都是用源码安装的。不过据说很简单,只要

$ sudo aptitude -P install xen-linux-system
$ sudo dpkg-divert --divert /etc/grub.d/08_linux_xen --rename /etc/grub.d/20_linux_xen # change the order of the operating systems so that Xen is the default option.
$ sudo update-grub # regenerate the /boot/grub/grub.cfg file

就行了。如果不行再自己网上搜下吧,毕竟这个不是今天的重点。

源码安装

具体的参阅这里

$ sudo aptitude build-dep xen
$ git clone git://xenbits.xen.org/xen.git
$ cd xen
$ ./configure
$ make xen
$ make tools
$ make install-xen
$ make install-tools
$ sudo dpkg-divert --divert /etc/grub.d/08_linux_xen --rename /etc/grub.d/20_linux_xen
$ sudo update-grub

至于每一句话什么意思,这里就不阐述了,不懂的自己去google,另外还有一些别的需求的还是自己去看文档吧,这里就负责最基本的配置。

在这之后,在系统的/boot目录下会有几个xen.*.gz的镜像文件,如果看/boot/grub/grub.cfg,能够看到诸如这样的项:

/boot/grub/grub.cfg
1
2
3
4
5
6
7
8
9
10
11
12
menuentry 'Debian GNU/Linux, with Xen xen and Linux 3.13.7+' --class debian --class gnu-linux --class gnu -ass os --class xen {
    insmod part_msdos
    insmod ext2
    set root='(hd0,msdos1)'
    search --no-floppy --fs-uuid --set=root 23292666-0022-4e4b-8b4b-4ffcec168ee8
    echo    'Loading Xen xen ...'
    multiboot   /boot/xen.gz placeholder
    echo    'Loading Linux 3.13.7+ ...'
    module  /boot/vmlinuz-3.13.7+ placeholder root=UUID=23292666-0022-4e4b-8b4b-4ffcec168ee8 ro nopat quiet
    echo    'Loading initial ramdisk ...'
    module  /boot/initrd.img-3.13.7+
}

在这里,multiboot /boot/xen.gz placeholder是xen的镜像,module /boot/vmlinuz-3.13.7+是domain 0的镜像,module /boot/initrd.img-3.13.7+是initrd。

重启之后,由于我们之前改了grub的顺序,所以会默认起Xen,domain的内核就是系统最新的内核。当然这些都是可以配置的,这里就不多说了。

另外一点,由于我们在编译源码的时候同样编译安装了xen-tools,所以当Xen启动之后,就可以运行如下命令:

$ sudo xl list

来看当前的虚拟机。如果出现问题,很可能是一些相关的daemon没有跑起来,这个时候只需要运行:

$ sudo /etc/init.d/xendomains start
$ sudo /etc/init.d/xencommons start

就可以了。这个时候再运行xl list,就可以看到:

xl list

这就表明xen正常起来了。其中Domain-0表示的就是Xen里面的特权虚拟机,也就是当前的操作系统。

启动虚拟机

当Xen安装起来之后,就可以启动虚拟机了,Xen的虚拟机的管理也是通过刚刚提到的xl那一套工具。如果你已经有一个虚拟机的镜像,那你只需要准备一个配置文件配置好相应的镜像路径就行了,如果没有虚拟机镜像,那么准备一个iso文件,来安装一个镜像。具体如何做会在后面说明。

在Xen中有两种虚拟化的模式:半虚拟化(para-virtualization)和全虚拟化(full virtualization)。关于这两个虚拟化的概念,以及它们的发展历史,我强烈推荐这两篇博客:

The Paravirtualization Spectrum, part 1: The Ends of the Spectrum

The Paravirtualization Spectrum, Part 2: From poles to a spectrum

如果用一张图来表示的话,我选择里面的这张图:

virtualization spectrum

由于到目前为止,Intel的VT-x硬件虚拟化技术已经能将CPU和内存的性能提高到真机的水平,但是由于设备(如磁盘、网卡)是有数目限制的,虽然VT-d技术已经可以做到一部分的硬件隔离,但是大部分情况下还是需要软件来对其进行模拟,在全虚拟化的情况下,是通过Qemu进行设备模拟的,而半虚拟化技术则可以通过虚拟机之间共享内存的方式利用特权级虚拟机的设备驱动直接访问硬件,从而达到更高效的性能水平。

当然不管怎么样,在虚拟机启动的时候我们还是可以指定要采用哪种方法来启动,如果采用半虚拟化的方法,那么起来的虚拟机的I/O、CPU和内存都是通过半虚拟化的机制。如果采用的是全虚拟化的方法,那么I/O应该用的就是Qemu的软件模拟了,而CPU和内存采用的是硬件虚拟化VT-x技术。

这里可以看到,如果我们采用PVHVM的方式,即CPU和内存采用VT-x技术,而I/O采用半虚拟化技术,那么性能就是最优的。其实现在linux的mainstream已经将其整合进去啦,默认情况下就可以在HVM里面采用半虚拟化的驱动,具体的可以看这篇文档。其实主要就是在启动配置文件里面加上这句话:

pv.cfg
1
xen_platform_pci=1

那么虚拟机启动的时候就会将Qemu的设备unplug,然后匹配半虚拟化的设备,如xen-netfront等。

半虚拟化启动虚拟机

准备配置文件:

pv.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
kernel = "/path/to/vmlinuz"
ramdisk = "/path/to/initrd.img"
extra = "root=/dev/xvda1"

name = "pv-vm"

memory = 1024
vcpus = 2

disk = [ 'file:/path/to/vm.img,xvda,rw' ]

# boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) 
boot="cd"

其中kernelramdisk是自己编译出来的内核镜像和initrd镜像,这个最好在虚拟机里面编译,然后再拷贝出来,当然我也试过用在主机上编译生成的镜像,可以启动,但是会有一些其他的问题,这里就不展开了。

之后,就可以运行:

$ sudo xl create -c pv.cfg

来启动虚拟机了,其中-c表示将虚拟机的输出打在console上,这样我们就可以直接看到虚拟机启动的信息了,然后登录进去,就可以操作虚拟机啦:

pv vm

全虚拟化启动虚拟机

准备配置文件:

hvm.cfg
1
2
3
4
5
6
7
8
9
10
11
12
kernel = "hvmloader"
builder="hvm"

name = "hvm-vm"

memory = 1024
vcpus = 2

disk = [ 'file:/path/to/vm.img,xvda,rw' ]

# boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) 
boot="cd"

和半虚拟化的配置文件一样,除了kernel直接填写“hvmloader”,再增加一个builder,填上“hvm“就可以了。

之后,运行:

$ sudo xl create hvm.cfg

来启动虚拟机,然后利用vnc来控制虚拟机:

$ vncviewer localhost:0

hvm vm

利用iso镜像安装虚拟机

如果你没有虚拟机镜像,那么先用dd生成一个空的镜像,设置文件系统格式:

$ dd if=/dev/zero of=/path/to/vm.img bs=1M count=10000
$ mkfs.ext4 /path/to/vm.img

这就相当于格式化了一个10G的ext4格式的硬盘,然后下载一个iso镜像,利用之前的配置文件,只需要多加一个disk选项,并将boot启动顺序做一个修改:

*.cfg
1
2
3
4
5
6
...
disk = [ 'file:/path/to/vm.img,xvda,rw', 'file:/path/to/iso,hdc:cdrom,r' ]
...
# boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) 
boot="dc"
...

然后启动,安装镜像就好了。

运行嵌套虚拟机

这个是这篇博文的重点。其实在当前最新的Xen的版本中,这个功能是默认就开启的,具体的参看这个链接

在一般的嵌套虚拟化中,整个架构是这样子的:

nested virtualization

其中,L1是第一层虚拟机,在这个虚拟机中会再运行一个hypervisor,里面运行嵌套的那个虚拟机,被称为L2层。由于我们在L1和L2层运行的都是Xen hypervisor,所以整个架构看起来是这样子的:

xen nested virtualization

当然,在这种情况下,还可以分成4个子情况:

  • L1运行PV Xen,L2运行PV Xen
  • L1运行PV Xen,L2运行HVM Xen
  • L1运行HVM Xen,L2运行PV Xen
  • L1运行HVM Xen,L2运行HVM Xen

其实方法都大同小异,我就介绍最简单的一种吧:

L1运行HVM Xen,L2运行PV Xen

按照之前“全虚拟化启动虚拟机”的步骤做下来,在启动虚拟机的时候加两个选项hap=1nestedhvm=1

l1-guest.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kernel = "hvmloader"
builder="hvm"

name = "l1-guest"

memory = 1024
vcpus = 2

disk = [ 'file:/path/to/vm.img,xvda,rw' ]

# boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) 
boot="cd"

hap=1
nestedhvm=1

进入虚拟机之后,按照和之前一样的步骤:

  • 编译和安装xen和xen-tools
  • 运行:sudo dpkg-divert –divert /etc/grub.d/08_linux_xen –rename /etc/grub.d/20_linux_xen
  • 运行update-grub更新grub
  • 重启虚拟机,进入Xen的镜像

这个时候按照前面说的步骤启动L2虚拟机:

  • 准备虚拟机镜像;
  • 启动xendomainsxencommons两个服务;
  • 准备“半虚拟化启动虚拟机”的配置文件
  • 利用xl启动虚拟机镜像

就能成功在L1的HVM虚拟机里面启动L2的PV虚拟机了:

l2 run in l1

另外推荐大家看一个人的毕业论文,讲的是在不同的平台上运行嵌套虚拟化的虚拟机,以及相关的性能比较。

Comments