解决 INIT: Id “xvc0” respawning too fast 问题

有位也做 VPS 的同行网友前几天来信说他用 SolusVM 创建用 PyGrub 引导的 Debian VPS 时遇到如下问题,每隔几分钟这个消息就跳出来1次,只打印在控制台(console):

INIT: Id "xvc0" respawning too fast: disabled for 5 minutes

这条消息无害,不影响用户正常使用,因为用户一般是 ssh 登陆,甚至不会看到这条消息。tty 设备文件是用来让用户和系统打交道的(通过 ssh 或 console),通过 pygrub 使用自己内核启动的 VPS 如果没设置好 tty 就容易出现以上错误。解决办法很容易,进入 VPS(虚拟机)后在 /etc/inittab 注释掉 xvc0 一行、在 /etc/securetty 文件里加上 hvc0 一行(如果没有的话):

# vi /etc/inittab
hvc0:2345:respawn:/sbin/getty 38400 hvc0
#xvc0:2345:respawn:/sbin/getty 38400 xvc0

# vi /etc/securetty
# Standard hypervisor virtual console
hvc0

# Oldstyle Xen console
#xvc0

修改完毕后重载一下 inittab 就应该看不到那条烦人的错误提示了:

# telinit q

最近收到的邮件特别多,如果大家有技术问题欢迎直接发在博客上一起讨论,这样同样的问题只需要被解决和回复一次,而且也会帮助有类似问题的朋友通过搜索引擎找过来。我们一般会在有时间的时候回复,如果问题值得继续深入的话 VPSee 会抽时间写博客来详细解释。我们的 email 和即时聊天工具仅用做客户支持和商业合作,谢谢:)

在 Debian 上安装 Xen 虚拟机集群管理工具 Ganeti

随着 Xen 服务器的增多,管理起来会越来越麻烦,如果有一些集成化的辅助工具来统一管理所有的服务器、虚拟机以及集中分配计算资源将会很方便。不过 VPSee 一般都避免使用一些太智能的工具,智能化自动工具有时候太智能,而且很难理解,特别是遇到问题的时候很难排错,因为自动和智能掩盖了工具背后的原理和过程,不知道是工具错了还是自己用错了。市面上有一些结合虚拟技术面向云计算的 Xen/KVM 管理工具,比如 Eucalyptus, OpenNebula, OpenQRM 等用来统一部署和管理虚拟环境,Ganeti 虽然没有前面几个强大,也勉强算一员。Ganeti 最初是由 Google 瑞士苏黎世 office 的一小撮人开发的 Xen/KVM 虚拟机集群管理工具,用来管理内部一些由廉价计算机组成的虚拟服务器集群,廉价计算机集群是 Google 的特色之一

详细一点说,Ganeti 是一个基于 Xen 或 KVM 虚拟技术的虚拟集群环境管理工具,用来管理一堆运行 Xen 服务器的统一管理界面,这样创建、删除、启动、关闭、重装、查看、移植虚拟机就用不着逐个去某台 Xen 服务器上操作,整合了整个虚拟操作环境,统一管理所有硬盘、操作系统、内存等资源,简化了操作,显然 Ganeti 需要运行在 Xen/KVM 平台上。把 Ganeti, Xen/KVM, LVM, DRBD, RAID10 等几个技术整合起来可以架设一个云计算基础环境,配上一个基于 Web 的控制面板和计费系统就可以当作 “云 VPS” 拿来忽悠。

安装和配置基本系统

首先在每个 node(node1, node2, …)上都安装上最基本的 Debian 系统(Ganeti 官方推荐1个集群里的 node 数目不要超过40个),VPSee 建议在所有 node 上一致采用最小化安装并使用最简单的分区方式:使用 sda1 做 /(10GB),使用 sda2 做 swap(2GB),剩余的空间将会在下面的步骤用到。安装完后开始对每个 node 都做如下类似配置,以 node1 为例,每个 node 上都需要配置 /etc/hosts,Ganeti 就是靠这里的 hostname 来识别 node 的,所以这一步很重要,设置好 hostname 后用 hostname -f 测试一下是否正确:

# vi /etc/hosts

127.0.0.1       localhost.localdomain   localhost
172.16.39.10    cluster1.vpsee.com      cluster1
172.16.39.11	node1.vpsee.com node1
172.16.39.12	node2.vpsee.com node2
172.16.39.101   inst1.vpsee.com         inst1

# hostname -f
node1.vpsee.com

如果 node1 上的 hostname 不正确可以修正:

# vi /etc/hostname
node1.vpsee.com
# /etc/init.d/hostname.sh start

接下来需要给每个 node 配置一个静态 IP,需要注意的是 Ganeti 在默认 bridge 模式下会是用 xen-br0 这个名字,所以我们需要在每个 node 上建立这个 bridge:

# vi /etc/network/interfaces 
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 172.16.39.11
    netmask 255.255.254.0
    network 172.16.38.0
    broadcast 172.16.39.255
    gateway 172.16.38.1
auto xen-br0
iface xen-br0 inet static
    address 172.16.39.11
    netmask 255.255.254.0
    network 172.16.38.0
    broadcast 172.16.39.255
    gateway 172.16.38.1
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0

需要注意的是,要对每个想加入 Ganeti 的 node 做相应的配置和调整,比如 IP,hostname 等。在 node2, node3, …, nodeN 上重复上面的步骤。

安装和配置 LVM

这一步骤也需要在每个 node 上重复。先检查分区,在 sda3 上分区,分区格式是 LVM,每个 node 上的这个区将被拿来做 Ganeti 的存储池(storage pool)用来存储 Xen 虚拟机镜像(要注意的是记得在安装 debian 的是后就留出大部分空间来做 sda3):

$ sudo fdisk -l
...
   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1        1216     9764864   83  Linux
/dev/sda2            1216        1703     3906560   82  Linux swap / Solaris

$ sudo fdisk /dev/sda

n p 3 enter enter t 3 L 8e w

$ sudo fdisk -l
...
   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1        1216     9764864   83  Linux
/dev/sda2            1216        1703     3906560   82  Linux swap / Solaris
/dev/sda3            1703       60801   474711584+  8e  Linux LVM

安装 LVM 工具包,并用 LVM 工具创建物理卷和 LVM 卷组:

# apt-get install lvm2

$ sudo pvcreate /dev/sda3
  Physical volume "/dev/sda3" successfully created

$ sudo vgcreate xenvg /dev/sda3
  Volume group "xenvg" successfully created

重启系统以便刚创建的 LVM 生效:

# shutdown -r now

安装和配置 Xen 系统

按照 “在 Debian 上安装 Xen” 的步骤安装 Xen:

# apt-get install xen-hypervisor-3.2-1-amd64 \
xen-linux-system-2.6.26-2-xen-amd64 xen-utils-3.2-1 \
xenstore-utils xenwatch xen-shell xen-tools

安装和配置 Ganeti

可以从 Ganeti 官方网站下载源代码编译安装,为了少给自己添麻烦避免一些未知的编译、安装错误,建议新手直接从 debian 源安装:

# apt-get install ganeti

开始使用 Ganeti

在给集群(cluster)增加结点(node)之前需要先初始化这个集群,指定谁是老大(master node)。所以首先用 gnt-cluster 初始化一个 node (node1),这个 node1 将成为 master node,登陆到 node1 上,在 node1 上执行以下操作:

# gnt-cluster init node1

# gnt-node list
Node            DTotal  DFree MTotal MNode MFree Pinst Sinst
node1.vpsee.com 454044 454044   3893  3686   128     0     0

有了 master node (node1) 后,这个 master node 就是老大,用来管理其他的 slave nodes (node2, node3, …, nodeN) ,所有操作都要在 master node 上执行。现在我们可以在这个集群中加入 node2:

# gnt-node add node2.vpsee.com

# gnt-node list
Node            DTotal  DFree MTotal MNode MFree Pinst Sinst
node1.vpsee.com 454044 454044   3893  3686   128     0     0
node2.vpsee.com  37440  37440   2035  1024   969     0     0

可以看到这个集群已经统一管理 node1, node2 以及 node1 和 node2 上的资源,比如内存、硬盘等。现在我们终于可以开始创建虚拟机了,我们只需要在 master node (node1) 上执行安装虚拟机的命令就可以自动部署到集群中:

# gnt-instance add -t plain -n node2.vpsee.com -o debootstrap -s 5g \
--swap-size 256 -m 256 --kernel /boot/vmlinuz-`uname -r` \
--ip 172.16.39.101 inst1.vpsee.com
* creating instance disks...
adding instance inst1.vpsee.com to cluster config
 - INFO: Waiting for instance inst1.vpsee.com to sync disks.
 - INFO: Instance inst1.vpsee.com's disks are in sync.
creating os for instance inst1.vpsee.com on node node2.vpsee.com
* running the instance OS create scripts...
...

要重装虚拟机的话,执行 reinstall:

# gnt-instance reinstall inst1.vpsee.com
This will reinstall the instance inst1.vpsee.com and remove all data.
Continue?
y/[n]/?: y
Running the instance OS create scripts...

查看正在运行的虚拟机(instance):

# gnt-instance list
Instance          OS          Primary_node      Status  Memory
inst1.vpsee.com debootstrap node1.vpsee.com running    256

Ganeti 结合 DRBD 后还可以实现冗余、备份、在不同 node 之间自由迁移等功能,比如一个 node 挂了另一个 node 自动接替,某个 node 负载太高把上面的一个或几个 instance(虚拟机)暂时或永久迁移到另一个 node 降低单一 node 的负载等,非常酷。更多参考资料、帮助文档和命令行参数解释请看 Ganeti 的官方文档

Debian 上 Xen 和 X 之间的 bug

上周五 VPSee 在一台新 PC 上安装 Debian 的时候遇到一堆问题,先是安装程序没有找到网卡,没有网卡就需要自己编译驱动,但是编译又需要一些编译包、头文件和库,没有网络就没法 apt-get(因为只下载了 cd1),所以不得不从另外一台机器上下载网卡驱动 e1000e-1.2.10.tar.gz(内核树里居然也没有发现这款网卡,需要从 Intel 官网下载)以及编译驱动所必须的软件包和依赖包。最后 dpkg -i 软件包到 Debian、编译驱动、modprobe 驱动到内核,终于找到网卡。好不容易配好了网络,开始装 X,配置 X Window 的时候居然没有找到鼠标,一查原因原来是 gpm 鼠标服务由于某种原因没起来。最后把 X Window 和窗口管理器装上又发现字体和渲染都很难看,然后又下载其他的字体更改 .fonts.conf. 好不容易可以用桌面了,却发现在 Debian 上安装完 Xen 后进入 Xen(2.6.26-1xen-amd64)内核启动 X Window 就报错:

$ uname -r
2.6.26-1-xen-amd64

$ tail /var/log/Xorg.0.log 
(==) intel(0): RGB weight 888
(==) intel(0): Default visual is TrueColor
(II) intel(0): Integrated Graphics Chipset: Intel(R) G33
(--) intel(0): Chipset: "G33"
(--) intel(0): Linear framebuffer at 0xC0000000
(--) intel(0): IO registers at addr 0xD0300000

Fatal server error:
xf86MapVidMem: Could not mmap framebuffer (0xd0300000,0x80000) (Invalid argument)

VPSee 发现只要用 Xen 内核启动就无法进入 X,但是用原来的内核启动就可以。Debian 用户组有人2008年就报告了这个 bug,原因是 Debian 自带的这个 Xen 内核 2.6.26-1-xen-amd64 在启动 X 调用 mmap () 的时候,CPU 和显卡之间作内存映射(MMIO)出错,导致 X Window 不能启动。这个 bug 居然到现在都没有解决,可能大家都用 Debian 做 Xen 服务器,很少拿 Debian 桌面和 Xen 一起用吧。目前最简单的解决办法是限制 dom0 的内存(小于 2GB 就可以):

# vi /boot/grub/menu.lst
...
kernel          /boot/xen-3.2-1-amd64.gz dom0_mem=1024mb
...

这个 bug 只存在使用共享显卡的机器上,如果使用独立显卡就不会有这个问题。

Ubuntu 10.04 上编译安装 Xen 4.0.1 后的 xend 启动问题

因为 Ubuntu 10.04 不再官方维护 Xen 软件包了(RedHat 6 也不再支持 Xen 了),所以以后要想在这两大平台上用到 Xen 的话就需要自己亲自下载 Xen 源代码编译安装(当然也可以用第三方源)。今天 VPSee 在一台 Ubuntu 10.04 服务器上升级 Xen 到 4.0.1 的时候遇到一个问题,按照 Ubuntu 9.10 上源码安装 Xen 上的步骤编译和安装都正常,启动 Xen 内核也没问题,最后启动 xend 的时候报错如下:

$ sudo /etc/init.d/xend start
Traceback (most recent call last):
  File "/usr/sbin/xend", line 36, in 
    from xen.xend.server import SrvDaemon
ImportError: No module named xen.xend.server
Traceback (most recent call last):
  File "/usr/sbin/xend", line 36, in 
    from xen.xend.server import SrvDaemon
ImportError: No module named xen.xend.server
.Traceback (most recent call last):
  File "/usr/sbin/xend", line 36, in 
    from xen.xend.server import SrvDaemon
ImportError: No module named xen.xend.server
.Traceback (most recent call last):
  File "/usr/sbin/xend", line 36, in 
    from xen.xend.server import SrvDaemon

刚开始怀疑是 Python 版本问题,后来查了一下 /usr/sbin/xend 文件发现第36行:from xen.xend.server import SrvDaemon 在导入 SrvDaemon 就报错,xend 可能没有找到 xen tools,怀疑和安装路径有关。Ubuntu 上 Python 的默认安装在 /usr/lib/python2.6/ 下面,如果不设定 PYTHON_PREFIX_ARG 参数手动编译安装 xen tools 后也会默认安装到 /usr/lib/python2.6/,这样就出问题了,因为 xend 会默认从 /usr/local/lib/python2.6/dist-packages/ 找 script 和导入库,但是这时候 /usr/local/lib/python2.6/dist-packages/ 下面什么东西都没有。所以要改变 install-tools 的默认安装路径到 /usr/local/lib/python2.6/dist-packages/ 下,PYTHON_PREFIX_ARG 不带任何参数就可以了:

$ sudo make install-tools PYTHON_PREFIX_ARG=

最后检查一下是否能正常启动 xend:

$ sudo /etc/init.d/xend start
$ sudo xm list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0  3713     4     r-----      6.4

用同一个配置文件启动任意 Xen DomU

当我们使用 xm create vps1 这行命令创建一个 Xen DomU (VPS) 的时候,xm 会自动在 /etc/xen/ 目录下匹配到 vps1 这个配置文件,通过正确解析 vps1 配置文件而成功启动一个 DomU,如果我们有很多个 DomU 需要启动的话,那就需要在 /etc/xen/ 下创建和编辑很多个对应的 DomU 配置文件。这些配置文件的内容都是差不多的,无非就是一些参数需要修改,那么如何只在 /etc/xen/ 下保留一份配置文件并让所有 DomU 能通过传参数的方式来启动不同的 DomU 呢?比如,如何通过下面一行命令来自定义配置文件参数并启动 DomU 呢?

# xm create vps.config vpsid=1 vpscpu=2 vpsmem=512

我们企图通过上面这行命令来启动一个 VPS ID 为1、CPU cores 数为2、内存大小为 512MB 的 VPS (DomU). 我们接下来需要编辑 vps.config 这个文件,让这个文件在 xm create 时能接受 vpsid, vpscpu, vpsmem 这些参数。

# A domU configuration file for all the domUs
# written by vpsee.com

def vpsid_check(var, val):
    val = int(val)
    if val <= 0:
         raise ValueError
    return val
def vpscpu_check(var, val):
    val = int(val)
    if val <= 0:
        return 1
    elif val >= 8:
        return 8
    return val
def vpsmem_check(var, val):
    val = int(val)
    if val <= 128:
        return 128
    return val

xm_vars.var('vpsid',
            use="VPS ID > 0",
            check=vpsid_check)
xm_vars.var('vpscpu',
            use="VPS CPU > 0 and <= 8",
            check=vpscpu_check)
xm_vars.var('vpsmem',
            use="VPS RAM >= 128",
            check=vpsmem_check)

xm_vars.check()

name="vps%d" % vpsid
bootloader = "/usr/bin/pygrub"
vcpus = "%d" % vpscpu
maxmem="%d" % vpsmem
memory="%d" % vpsmem
disk=[ "tap:aio:/home/vpsee/xen/vps%d/disk.img,sda1,w" % vpsid ]
vif = [ "bridge=xenbr0" ]
on_shutdown = "destroy"
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"

上面的片段来自我们自己的脚本程序,VPSee 去除了一些和业务相关的代码,比如 xm create 的时候自动把客户名和客户的联系方式、VPS 配置、初始化流量等信息提交到数据库等。我们自己编写了很多类似的脚本帮助我们自动化管理和减少我们的管理、维护服务器和 VPS 的成本。

1GB 的 VPS 只有 727MB?

上周六我们一位客户报告了一个奇怪的问题,他在我们这里购买的 1024MB 内存的 VPS 只有 727MB,我们立即检查了 Xen 服务器上的配置和他的 VPS 运行情况,没有发现问题,他的 Xen VPS 配置文件以及 Xen 工具都是显示的是他有 1024MB 内存,客户发来了截图,并且给了我们 root 密码,我们登录进去看到客户的 VPS 确实只有 727MB,更奇怪的是我们可以通过动态调整来减少这个 VPS 的内存到 512MB,但是不能加到 1024MB,总是在 727MB 这个地方就加不上去了。我们服务器上有足够的内存,我们检查了各种 Xen 配置文件和 Xen 的日志,没有发现任何异常,Xen 技术已经相当成熟,如果是 bug 的话,应该早就有人遇到和解决了,所以我们估计和客户的系统有关。

这是一个很有意思的问题,VPSee 很想弄明白怎么回事,但是又不能不停的重启客户的 VPS 来测试,也没办法在自己机器上重现。这个时候客户给了我们一条重要的提示信息,他自己编译过 Linux 内核。和其他 VPS 服务商采用公共的内核不同,我们的 VPS 支持用户自己定义和编译内核。我们开始怀疑客户编译内核的时候某些选项弄错了,我们让客户发来他编译内核时用到的配置选项,他自己编译和使用的是64位的内核,而我们提供的 Linux VPS 是32位的,刚开始简单怀疑是32位程序使用64位内核的问题,可能部分32位程序调用64位内核提供的64位系统调用的时候出的问题。不过这个说法说不过去,因为64位是向下兼容的,运行大部分32位程序应该没问题(反过来32位内核运行64位程序就不一定了,因为64位程序指针会被32位内核截断成32位可能造成程序错误)。

周日下午连上服务器新建了一个 1024MB Arch Linux VPS,VPS 正常显示的是 1024MB,没有问题,按照客户的说明和这篇:在 ArchLinux VPS 上编译内核 提供的默认内核配置文件编译后,问题来了,启动系统后果然内存只有 727MB,打印内核信息只看到 727MB 内存:

# dmesg | more
...
last_pfn = 0x40000 max_arch_pfn = 0x1000000
Warning only 727MB will be used.
Use a HIGHMEM enabled kernel.
...

估计就是内核配置低端内存 LOWMEM 限制的问题,找到问题就好办了,检查默认的内核配置文件发现没有启用 HIGHMEM(CONFIG_NOHIGHMEM=y):

# vi kernel26-xen/config
...
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_X86_PAE=y
...

把上面的相关部分改成下面的配置就可以了:

# vi kernel26-xen/config
...
# CONFIG_NOHIGHMEM is not set
# CONFIG_HIGHMEM4G is not set
CONFIG_HIGHMEM64G=y
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_HIGHMEM=y
CONFIG_X86_PAE=y
...

重新编译安装内核并加入到 grub,最后重启系统登录后就会看到 1024MB 内存回来了:

# makepkg --asroot
# pacman -U kernel26-xen-2.6.34.1-1-i686.pkg.tar.xz
# pacman -U kernel26-xen-headers-2.6.34.1-1-i686.pkg.tar.xz

# vi /boot/grub/menu.lst
...
timeout 5
default 0

title Xen for ArchLinux (VPSee)
root (hd0,0)
kernel /boot/vmlinuz26-xen root=/dev/xvda1 ro console=/dev/xvc0
initrd /boot/kernel26-xen.img
...

# reboot

谢谢我们的客户给我们提供充分的信息和截图帮助我们找到和解决问题,也很感谢客户对我们的信任、遇到问题及时向我们反映而不是猜测和抱怨,不了解的人还以为我们在忽悠人呢。

在 ArchLinux VPS 上编译内核

昨天我们有位 ArchLinux 用户遇到一个 OpenVPN 的问题,在他的 VPS 上安装和配置好 OpenVPN 后可以从自己电脑连上 VPN,但是不能用 VPN 出去(访问外部网站),VPSee 和用户一起排错发现配置 OpenVPN 时候忘了用 iptable 做 SNAT 或 MASQUERADE,进一步运行 iptables 报错,内核缺少 iptables 模块:

# iptables -t nat -A POSTROUTING -s 1.1.1.1 -j SNAT --to-source 2.2.2.2
can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.

找到问题就好办了,解决的办法也很容易,下载内核代码、配置 iptable 内核选项、重新编译内核。(本文已经发给客户,我们的客户可以按照这里的步骤自己编译和替换内核,如果怕麻烦的话也可以找我们要已经编译好的内核。我们争取对我们的客户遇到的问题都能写出文章和流程来帮助理解和解决,这样不但我们自己客户受益,对其他 VPS 用户也有所帮助。)

安装必要工具

编译内核需要一些工具,比如 gcc 编译器什么的:

# pacman -S make gcc patch xmlto docbook-xsl

有一点要注意的就是不是每个内核都可以在 Xen 上运行的,因为是半虚拟化所以必须使用针对 Xen 的 Linux 内核版本,还好,ArchLinux 已经为我们准备好了官方的 Xen 版本内核:

# wget http://aur.archlinux.org/packages/kernel26-xen/kernel26-xen.tar.gz
# tar -xf kernel26-xen.tar.gz
# cd kernel26-xen

修改 kernel26-xen/PKGBUILD 文件,去掉下面这行的注释:

# vi PKGBUILD
pkgname=('kernel26-xen' 'kernel26-xen-headers') # Build kernel with a different name

编译和安装内核

如果打开 kernel26-xen/config 文件就会发现内核已经是为 Xen 配置好的,并且 iptable 相关选项已经是 m 状态(以内核模块的方式运行),如果不放心的话可以再次检查 CONFIG_IP_NF_IPTABLES=m 和 CONFIG_NF_NAT=m 等选项看看是否已经是 m 或 y 状态。在 ArchLinux 下编译和安装内核:

# makepkg --asroot
...
==> Creating package...
  -> Generating .PKGINFO file...
  -> Compressing package...
==> Finished making: kernel26-xen 2.6.34.1-1 (Mon Jul 19 15:15:05 EDT 2010)

# pacman -U kernel26-xen-2.6.34.1-1-i686.pkg.tar.xz
# pacman -U kernel26-xen-headers-2.6.34.1-1-i686.pkg.tar.xz

配置 grub 以启动新内核:

# vi /boot/grub/menu.lst
...
timeout 5
default 0

title Xen for ArchLinux (VPSee)
root (hd0,0)
kernel /boot/vmlinuz26-xen root=/dev/xvda1 ro console=/dev/xvc0
initrd /boot/kernel26-xen.img
...

测试

重启系统后检查和测试新装的 Linux 内核是否有了 iptables 内核模块并安装 iptables 用户端工具:

# uname -r
2.6.34-xen

# modprobe ip_tables

# lsmod
Module                  Size  Used by
ip_tables               9099  0 
x_tables               10364  1 ip_tables
evdev                   6810  0 
pcspkr                  1383  0 
rtc_core               11631  0 
rtc_lib                 1454  1 rtc_core
ext3                  108916  1 
jbd                    35426  1 ext3
mbcache                 4250  1 ext3

# pacman -Syy iptables

Xen domain0 和 domainU 的时间同步

在 Xen 的默认设置下,domainU 的时间总是要自动和 domain0 保持同步,所以想简单的在 domainU 内部用各种时间、日期等命令改变 domainU 的系统时间并不起作用。如何给 domainU 设置单独的时钟而不受 domain0 的影响呢?我们经常接到我们的 Xen VPS 客户的询问是否能把他们的 VPS 时钟改成北京时间,为什么他们改变了时钟和时区却不起作用等问题。如果每个 VPS 用户(domainU)来自不同国家或时区而想在自己的 VPS 里使用自己的区域时间该怎么办?很简单,只需要在自己的 VPS(domainU)里改变一个参数就可以了,Linux/Xen 很灵活,传递参数方式有很多种,可以用下面任意的一种方式来改变这个设置。

直接改变 xen 内核的运行时参数:

# echo 1 > /proc/sys/xen/independent_wallclock

不过上面的方法会在重启 domainU 的时候丢失,可以把上面的命令加到某个自动启动文件中。

或者也可以把改变 xen 内核设置的参数加到 sysctl.conf 文件中,VPSee 更偏向采用这种方法:

# vi /etc/sysctl.conf
xen.independent_wallclock=1

# sysctl -p

另外一种方法在 VPS 外面进行,需要 VPS 服务商的干预,在 domainU 的启动配置文件种加上以下参数:

# vi /etc/xen/vps01
...
extra='independent_wallclock=1'
...

Xen 部署 iSCSI 存储

运行在 Xen 的虚拟机(domainU)有多种存储方式可以选择,可以是普通的文件(file)、逻辑卷(LVM)、物理硬盘分区(partition)等,也可以是网络存储 NFS、NAS、GNBD、SAN、AoE、iSCSI 等。在企业、高校等机构里,我们一般有充足的硬件资源来部署基于 Xen 的虚拟化环境,比如我们最近拿到的一台 SUN Fire V880,可以容下12个硬盘,就非常适合来做网络存储,为了虚拟环境达到高可靠、高性能的要求,采用一些更高级、更昂贵的网络存储方式会让后续的管理、容错、备份、迁移、灾难恢复等工作更容易一些。

NFS 是文件级别的存储(Network File Storage),提供文件、目录级别的共享和访问,而 iSCSI 之类的网络存储则是块级别的存储(Block Storage)。他们的工作方式不一样,缓存机制也不一样,NFS 自己有文件缓存系统,而 iSCSI 的缓存依赖相应的文件系统的缓存。经测试表明,在大数据繁重(Data-intensive)的应用中 NFS 的性能稍好一些,在小数据(Meta-data)频繁、面向操作的应用中 iSCSI,因为虚拟化环境大部分传输的是命令之类的 meta-data,所以 iSCSI 非常适合部署在虚拟化环境。

为了描述方便,VPSee 用 A 机器代表运行 domain0 的 Xen 服务器,用 B 机器代表存储多个 domainU 的 iSCSI 服务器。他们的关系是这样的,A(iSCSI 客户端)通过 iSCSI 协议来启动和运行 B(iSCSI 服务端)上的 Xen 虚拟机镜像(可以是文件、LVM、物理分区等)。下面的操作在 CentOS 5.5 上执行:

安装必要软件包

# yum install kernel-devel openssl-devel gcc rpm-build

安装和配置 iSCSI target 服务器

到 http://sourceforge.net/projects/iscsitarget/ 下载最新的 iscsitarget 源代码、解压、编译并安装:

# mv iscsitarget-1.4.20.1.tar.gz /usr/src
# cd /usr/src
# tar xvf iscsitarget-1.4.20.1.tar.gz
# cd iscsitarget-1.4.20.1
# make
# make install

关闭防火墙或者打开 iSCSI 需要的 3260 端口,否则客户端会连接不上:

# system-config-securitylevel-tui

配置 iSCSI target 服务器,设置客户端可以访问的用户名和密码,本来为了达到好的稳定性和性能这里是应该分一个 LVM 逻辑分区出来当作 Xen 虚拟机的块设备,然后在上面安装 domainU 的,这里为了简便 VPSee 直接拿一个已经装好的虚拟机镜像文件 vpsee.img 来充当 LVM 分区:

# vi /etc/iet/ietd.conf
...
Target iqn.2010-06.xen-sanhead:xen-vpsee
        IncomingUser vpsee 123456
        OutgoingUser vpsee 123456
        Lun 0 Path=/iSCSI/vpsee.img,Type=fileio,IOMode=wb
        Alias iSCSI for diskname
        ImmediateData Yes
        MaxConnections 1
        InitialR2T Yes

iSCSI target 服务器端设置完后重启服务:

# /etc/init.d/iscsi-target restart

安装和配置 iSCSI 客户端

安装 iSCSI 客户端:

# yum install iscsi-initiator-utils

配置 iSCSI 客户端:

# vi /etc/iscsi/iscsid.conf

...
node.session.auth.username = vpsee
node.session.auth.password = 123456
discovery.sendtargets.auth.username = vpsee
discovery.sendtargets.auth.password = 123456

启动服务:

# /etc/init.d/iscsi start

发现并登陆:

# iscsiadm -m discovery -t sendtargets -p 172.16.39.101
172.16.39.101:3260,1 iqn.2010-06.xen-sanhead:xen-vpsee

# iscsiadm -m node -T iqn.2010-06.xen-sanhead:xen-vpsee --login
# /etc/init.d/iscsi restart

执行 fdisk 就会看到本机(A 机器)多出了一个块设备,那正是 B 机器上的 vpsee.img:

# fdisk -l
...
Disk /dev/sdc: 10.4 GB, 10486808576 bytes
64 heads, 32 sectors/track, 10001 cylinders
Units = cylinders of 2048 * 512 = 1048576 bytes

Disk /dev/sdc doesn't contain a valid partition table

最后在 A 机器上把 Xen 配置文件的 disk 一行改成:

disk = [ "phy:/dev/sdc,sda1,w" ]

启动 Xen 虚拟机后,就实际上从 A 机器的块设备 /dev/sdc 通过 iSCSI 协议启动并连到了 B 机器上的 vpsee.img 文件,虽然 domainU 运行在 A 机器上,但是所有数据和程序都在 B 机器的 vpsee.img 中。这样实现了操作和数据的分离,将更有利于以后迁移、管理和备份 Xen 虚拟机。

Xen 支持的虚拟机类型

我们都知道 Xen 支持两种虚拟机类型:半虚拟化(paravirtualization)和全虚拟化(full virtualization),我们也知道 Xen 支持32位的和64位的虚拟机。决定 Xen 服务器是否能支持半虚拟化、全虚拟化、32位和64位的关键因素是处理器,即 CPU 的类型。

当 Xen 虚拟机运行在不支持虚拟化的硬件上的时候(CPU 不支持虚拟化),所有的内核和虚拟机(domains)都必须使用相同类型内存模型和指令大小。比如,如果使用的是 64位的 hypervisor 和 domain0,那么上面所有的 domainU 都必须是64位的或32位 PAE 的;同样,如果使用的是32位(带 PAE 内存扩展)的 xen 内核的话,那么所有在上面运行的 domainU 也都必须是32位(带 PAE 内存扩展)的。

当 Xen 虚拟机运行在支持虚拟化的硬件上、有了硬件的支持的时候(CPU 支持虚拟化),上面的限制就变得宽松多了,可支持的虚拟机类型范围要大多了。1个32位带 PAE 支持的 Xen 内核可以在上面运行1个不带 PAE 支持、全虚拟出来的 domainU;1个64位的 Xen 系统可以运行任何32位的 Linux domainU(包括半虚拟的 domainU 和全虚拟的 domainU);但是1个32位的 Xen 系统可以运行32位半虚拟的 domainU 而不能运行64位半虚拟的 domainU 了。所以 Xen 是向前兼容的,64位的 Xen 内核可以兼容运行32位PAE、纯32位的 domainU,但是不能反过来,32位的 Xen 内核不能运行64位的 domainU 等。

如果觉得上面的文字说明看得有点头昏,VPSee 整理了一个表格:

Hypervisor domain0 domainU (PV) domainU (HVM)
32bit 32bit 32bit 32bit
32bit PAE 32bit PAE 32bit PAE 32bit or 32bit PAE
64bit 64bit 64bit or 32bit PAE 32bit, 32bit PAE or 64bit

Intel VT(Virtualization Technology)和 AMD SVM(Secure Virtual Machine)是两大处理器生产商为了迎合虚拟化发展的趋势而在自己的处理器里直接增加对虚拟化技术的硬件支持。辨别自己的 CPU 是否支持虚拟技术很简单,只需要检查 cpuinfo 里面是否带有虚拟化标志,如果使用的是 Intel CPU,那么 flags 里应该有 vms 字样;如果使用 AMD CPU,那么 flags 里应该可以找到 svm,下面是 VPSee 在一台 SUN Fire X2100 服务器上打印的结果:

# cat /proc/cpuinfo | grep flags
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt rdtscp lm
3dnowext 3dnow pni cx16 lahf_lm cmp_legacy svm extapic cr8_legacy
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov 
pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt rdtscp lm 
3dnowext 3dnow pni cx16 lahf_lm cmp_legacy svm extapic cr8_legacy

注意:如果已经启动到 Xen 系统中, cat /proc/cpuinfo | grep flags 将在默认情况下不会显示 vmx 或 svm 标志位,只有在安装 Xen 前的纯 Linux 内核下才可以看到。还有就是,确定 BIOS 中打开了 Intel VT 或 AMD SVM 虚拟化的支持。

通常安装完 Xen 后,Xen 就能自动识别出系统支持哪几种虚拟机类型。只需要简单打印出 Xen 虚拟机的兼容名单就可以看出来:

# cat /sys/hypervisor/properties/capabilities
xen-3.0-x86_64 xen-3.0-x86_32p hvm-3.0-x86_32 hvm-3.0-x86_32p hvm-3.0-x86_64

上面打印出来的内容表示这个系统可以运行 64位 domains(xen-3.0-x86_64)、32位带 PAE 的 domains(xen-3.0-x86_32p)、32位全虚拟化 domains(hvm-3.0-x86_32)、32位带 PAE 全虚拟化 domains(hvm-3.0-x86_32p)、64位全虚拟化 domains(hvm-3.0-x86_64).

在普通 Linux 下面的 /proc 里包含了一些运行时的 Linux 内核参数可以查看和修改,和 /proc 的作用类似,在 Xen 里面 /sys 里包含了 xen hypervisor 的一些参数。如果在你的 Xen 系统上没有发现 /sys/hypervisor,多半时因为在配置 Xen 内核的时候没有选择上 XEN_SYSFS,重新配置、编译和安装 带 Xen 的 Linux 内核就可以了。

在自己的 IT 环境里部署 Xen 虚拟化前需要了解一下自身 IT 环境的一些特点,比如:用户的使用类型(将在虚拟机上干什么?),需要运行的应用(是否某应用程序必须运行在老的32位的系统上?)等,这样方便选购服务器、迁移平台和应用以及部署虚拟化。