升级 Red Hat Linux 7.3 到 CentOS 3.1

最近用 VMware vCenter Converter 工具企图虚拟化一台很古老的 Red Hat Linux 7.3 物理服务器失败,可能是因为 RedHat 7.3 版本太老 VMware Converter 支持不到位。虚拟化太老的系统如果使用一些自动迁移工具不成功的话可以自己动手迁移,虽然麻烦点,比如做个虚拟硬盘、加上分区表、把文件系统拷贝过去、重置 grub、最后修改几个关键文件等。现在这里的想法是把 RedHat 7.3 升级到 CentOS 3.1 再用 VMware Converter 试一下,如果这样还不成功就只能手动虚拟化物理机了。升级前先备份系统(可用光盘启动后 dd 硬盘到另一个硬盘),防止升级失败后系统启动不了或者升级后关键程序不能运行。升级前不确定 RedHat 7.3 到 CentOS 3.1 这种不同版本、不同版本号的大跨度升级能否成功,有必要纪录一下。

登陆 RedHat 7.3 后安装 yum:

# wget http://ftp.ie.freshrpms.net/pub/freshrpms/redhat/7.3/yum/yum-1.0.3-3.rh.fr.i386.rpm
# rpm -ivh yum-1.0.3-3.rh.fr.i386.rpm

编辑 yum.conf 加入 centos 3.1 的源:

# vi /etc/yum.conf
[main]
cachedir=/var/cache/yum
debuglevel=2
logfile=/var/log/yum.log
pkgpolicy=newest
distroverpkg=redhat-release
installonlypkgs=kernel kernel-smp kernel-hugemem kernel-enterprise kernel-debug kernel-uns
upported kernel-smp-unsupported kernel-hugemem-unsupported
tolerant=1
exactarch=1

[base]
name=CentOS-$releasever - Base
baseurl=http://centosa3.centos.org/centos-3/3.1/os/i386/
gpgcheck=1

#released updates
[update]
name=CentOS-$releasever - Updates
baseurl=http://centosa3.centos.org/centos-3/3.1//updates/i386/
gpgcheck=1

#packages used/produced in the build but not released
[addons]
name=CentOS-$releasever - Addons
baseurl=http://centosa3.centos.org/centos-3/3.1/addons/i386/
gpgcheck=1

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=http://centosa3.centos.org/centos-3/3.1/extras/i386/
gpgcheck=1

升级系统,完成后重启:

# yum update
# yum upgrade

# shutdown -r now

VMware vSphere Client 访问虚拟机控制台无故断开问题

安装在 Windows Server 2008 R2 上的 VMware vSphere Client 在查看虚拟机 console 的时候出现如下问题,无法访问和看到虚拟机的控制台:

vmrc console problem

解决办法是打开 Windows 程序管理器,终止 vmware-vmrc.exe 进程(通常有2个):

kill vmware-vmrc.exe

然后重启 VMware vSphere Client 后重新连接 VMware vSphere 服务器。如果还有问题杀掉 vmware console 和 vmware converter 相关进程后再试一下,还不行就卸载 vmware converter 后再试试。

FreeBSD 9.0 文件系统的默认 fragment size 是 4096

今天发现在一台小硬盘的 FreeBSD 9.0 虚拟机上启动 vi 时报错:

% vi

/: create/symlink failed, no inodes free
ex/vi: Error: Unable to create temporary file: No space left on device

检查了一下硬盘容量,貌似这个虚拟机只用了53%的硬盘,应该还有足够的空间啊:

% df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/ada0p3    5.7G    2.8G    2.4G    53%    /
devfs          1.0k    1.0k      0B   100%    /dev

仔细看错误信息发现是文件系统 no inodes free,应该是文件系统的 inode 不够了,df -i 查看 inode 用了100%,没了可用的 inode 也就不能创建文件了。

% df -i
Filesystem  1K-blocks    Used   Avail Capacity iused ifree %iused  Mounted on
/dev/ada0p3   5939036 2916144 2547772    53%  378873     5  100%   /
devfs               1       1       0   100%       0     0  100%   /dev

用 newfs 查看当前文件系统设置发现 fragment size 4096. 查看 newfs 命令的帮助文件得知 FreeBSD 9.0 下的 fragment size 和 block size 默认分别为32768和4096字节,是 FreeBSD 8.2(8192和1024字节)时的4倍(难怪以前在小硬盘上用 FreeBSD 8.2 的时候没遇到这个问题):

# newfs -N /dev/ada0p3
/dev/ada0p3: 5892.9MB (12068736 sectors) block size 32768, fragment size 4096
	using 8 cylinder groups of 740.00MB, 23680 blks, 47360 inodes.
super-block backups (for fsck -b #) at:
 192, 1515712, 3031232, 4546752, 6062272, 7577792, 9093312, 10608832

% man newfs
...
EXAMPLES
           newfs /dev/ad3s1a

     Creates a new ufs file system on ad3s1a.  The newfs utility will use a
     block size of 32768 bytes, a fragment size of 4096 bytes and the largest
     possible number of blocks per cylinders group.  These values tend to pro‐
     duce better performance for most applications than the historical
     defaults (8192 byte block size and 1024 byte fragment size).  This large
     fragment size may lead to much wasted space on file systems that contain
     many small files.
...

查看源码 freebsd/sbin/newfs/newfs.h 再次确认了 FreeBSD 9.0 下文件系统的 fragment size 和 block size 默认大小:

/*
 * The following two constants set the default block and fragment sizes.
 * Both constants must be a power of 2 and meet the following constraints:
 *      MINBSIZE <= DESBLKSIZE <= MAXBSIZE
 *      sectorsize <= DESFRAGSIZE <= DESBLKSIZE
 *      DESBLKSIZE / DESFRAGSIZE <= 8
 */
#define DFL_FRAGSIZE    4096
#define DFL_BLKSIZE     32768

现在要想办法改变 block size, fragment size,增加 inode 数目,/dev/ada0p3 分区刚好是 root 分区,只能重装了,分区的时候记得在分区格式化步骤的时候带上初始化参数,在动手之前 man newfs 仔细看看帮助文件里对 -b -f -i 等参数的说明:

# man newfs

# newfs -U -b 4096 -f 512 -i 2048 /dev/ada0p3

Xen 和 KVM 下如何关闭 virbr0

安装 Xen安装 KVM 后都会发现网络接口里多了一个叫做 virbr0 的虚拟网络接口:

# ifconfig
...
virbr0    Link encap:Ethernet  HWaddr d2:91:97:b8:3d:fc  
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
...

这是由于安装和启用了 libvirt 服务后生成的,libvirt 在服务器(host)上生成一个 virtual network switch (virbr0),host 上所有的虚拟机(guests)通过这个 virbr0 连起来。默认情况下 virbr0 使用的是 NAT 模式(采用 IP Masquerade),所以这种情况下 guest 通过 host 才能访问外部。

virtual network switch (virbr0)

大多数时候我们虚拟机使用的是 bridge(网桥)直接连到局域网里,所以这个 virbr0 不是必须的(注:不要搞混淆了,bridge 和这里的 virbr0 bridge 是互不相干的)。如何关掉这个 virbr0 呢?先 net-destroy 然后 net-undefine,最后别忘了重启 libvirtd 让设置生效:

# virsh net-list
Name                 State      Autostart
-----------------------------------------
default              active     yes

# virsh net-destroy default
Network default destroyed

# virsh net-undefine default
Network default has been undefined

# service libvirtd restart
Stopping libvirtd daemon:                                  [  OK  ]
Starting libvirtd daemon:                                  [  OK  ]

释放 Linux 系统预留的硬盘空间

大多数文件系统都会保留一部分空间留作紧急情况时用(比如硬盘空间满了),这样能保证有些关键应用(比如数据库)在硬盘满的时候有点余地,不致于马上就 crash,给监控系统和管理员一点时间去察觉。不过有时候这部分预留的硬盘空间不用的话有点浪费。如何释放这部分系统预留的空间呢?

在 Linux ext2/ext3/ext4 文件系统上通常默认预留5%的硬盘空间,如果硬盘是 4TB 的话就意味着有 200GB 的空间就这样浪费了,我们可以通过 tune2fs 来改变5%的默认设置,比如只预留1%的空间。可不可以设成0%呢?当然可以,但是不推荐。

查看当前硬盘空间情况:

# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg_cloud22-lv_root
                       32G  1.1G   30G   4% /
tmpfs                  24G     0   24G   0% /dev/shm
/dev/sda1             485M   68M  392M  15% /boot
/dev/mapper/vg_cloud22-lv_home
                      3.2G   70M  2.9G   3% /home
/dev/sdd1            1008G  161G  797G  17% /var/cloud

调整 /dev/sdd1,只预留1%的空间:

# tune2fs -m 1 /dev/sdd1
tune2fs 1.41.12 (17-May-2010)
Setting reserved blocks percentage to 1% (2684381 blocks)

调整后查看释放后的硬盘空间,发现多出了 838-797=41GB 的空间:

# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg_cloud22-lv_root
                       32G  1.1G   30G   4% /
tmpfs                  24G     0   24G   0% /dev/shm
/dev/sda1             485M   68M  392M  15% /boot
/dev/mapper/vg_cloud22-lv_home
                      3.2G   70M  2.9G   3% /home
/dev/sdd1            1008G  161G  838G  17% /var/cloud

如果硬盘被塞满了,想清理硬盘那是另外一回事,可以参考:什么吃掉了我的硬盘?

如何在 KVM 虚拟机上运行 KVM

上次讨论了如何在 VMware ESXi 虚拟机上运行 KVM 问题,前不久有读者想 “在 kvm 上面创建个虚拟机安装 rackspace 的 openstack” 问到 “如何开启虚拟机上的 CPU VT 功能以便在 KVM 上运行 KVM”,又是一个嵌套应用虚拟机的问题:在 KVM 虚拟机上运行 KVM 虚拟机。以下步骤在 Ubuntu Server 12.04 LTS 64 bit 上测试通过。

首先检查 KVM host(母机)上是否打开了嵌套虚拟机功能(默认是开启的):

# modinfo kvm_intel | grep nested
parm:           nested:bool

# cat /sys/module/kvm_intel/parameters/nested
Y

如果上面的显示结果不是 Y 的话需要开启 nested:

# modprobe -r kvm-intel
# modprobe kvm-intel nested=1
# cat /sys/module/kvm_intel/parameters/nested
Y

然后在 KVM guest(虚拟机)的 xml 配置文件中加入 vmx 选项,并启动虚拟机(这里用的是 Ubuntu 官方发布的 Ubuntu KVM 镜像 ubuntu-12.04-server-cloudimg-amd64-disk1.img):

# vi nestedvm.xml
...
<cpu match='exact'/>
   <model>core2duo</model/>
   <feature policy='require' name='vmx'//>
</cpu/>
...

# virsh create nestedvm.xml

启动虚拟机后登陆并安装 KVM,执行 kvm-ok 和 modinfo 均出现错误:

# apt-get install ubuntu-virt-server

# kvm-ok
INFO: /dev/kvm does not exist
HINT:   sudo modprobe kvm_intel
INFO: Your CPU supports KVM extensions
KVM acceleration can be used

# modinfo kvm_intel
ERROR: modinfo: could not find module kvm_intel

这是因为我们使用的是 ubuntu-12.04-server-cloudimg-amd64-disk1.img 这个官方虚拟机镜像,这个镜像使用的是 linux 3.2.0-23-virtual 内核,缺少 KVM 模块(kvm-intel.ko),所以我们需要改为 generic 内核:

# uname -a
Linux test 3.2.0-23-virtual #36-Ubuntu SMP Tue Apr 10 22:29:03 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

# apt-get install linux-generic

重启后进入虚拟机执行 kvm-ok 和 modinfo 均成功:

# kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

# modinfo kvm_intel
filename:       /lib/modules/3.2.0-30-generic/kernel/arch/x86/kvm/kvm-intel.ko
license:        GPL
author:         Qumranet
srcversion:     3BAF54F96ECD4B02292CAA0
depends:        kvm
intree:         Y
vermagic:       3.2.0-30-generic SMP mod_unload modversions 
parm:           vpid:bool
parm:           flexpriority:bool
parm:           ept:bool
parm:           unrestricted_guest:bool
parm:           emulate_invalid_guest_state:bool
parm:           vmm_exclusive:bool
parm:           yield_on_hlt:bool
parm:           fasteoi:bool
parm:           nested:bool
parm:           ple_gap:int
parm:           ple_window:int

现在应该可以在这个虚拟机上创建另一个虚拟机了。

用 MultiTail 查看多个 OpenStack 日志

使用 OpenStack 特别是排错的时候需要查看多个日志来定位错误,如果用 tail 会开很多 Terminal.app 程序切换查看,不方便;如果用 screen 会用 ctrl+A+N 在多个窗口切换也不方便。啥工具能在一个屏幕上跟踪多个日志文件呢?MultiTail 就是这样的一个工具,可以在一个窗口实时显示多个文件内容的更新情况,并提供了配色方案,垂直、水平分割屏幕等方便阅读和查看的功能。

在 Ubuntu/Debian 上安装 multitail:

$ sudo apt-get install multitail

在 CentOS/RHEL/Fedora 上安装 multitail:

# wget http://pkgs.repoforge.org/multitail/multitail-5.2.9-1.el6.rf.x86_64.rpm
# rpm -ivh multitail-5.2.9-1.el6.rf.x86_64.rpm

运行 multitail 在一个屏幕同时监控 nova-schedule, nova-compute, nova-network 日志:

$ multitail -s 2 /var/log/nova/nova-scheduler.log \
/var/log/nova/nova-compute.log \
/var/log/nova/nova-network.log

这里为了控制截图大小不得不把窗口弄小,理想情况是把这个 Terminal 窗口投放到外接显示器上并同时显示8个日志,这样排错会很有效率~

multitail

如果使用 DevStack 脚本安装 OpenStack 的话,日志会显示在 screen 会话里,使用 screen -x 连接后就可以 ctrl+A+N 切换看日志,不过这个日志是没有保存的,所以没法直接用 multitail 打开日志,需要先保存日志。要保存日志文件则需要在安装 OpenStack 前就配置 DevStack 脚本告诉 DevStack 把 OpenStack 运行日志写到 /opt/stack/logs/screen 下:

$ vi devstack/localrc
...
DEST=/opt/stack
SCREEN_LOGDIR=$DEST/logs/screen
...

然后运行 multitail:

$ multitail -s 2 /opt/stack/logs/screen/screen-n-sch.log \
/opt/stack/logs/screen/screen-n-cpu.log \
/opt/stack/logs/screen/screen-n-net.log

SGE 运行在 OpenStack 上的 HOST_NOT_RESOLVABLE 问题

4月份在介绍《安装 Sun Grid Engine》的时候曾经提过我们希望能在云计算平台上快速创建多个高配置虚拟机并自动接入到我们的 SGE (Sun Grid Engine) 集群,这样能迅速满足整个实验室计算高峰需求。

我们现在已经把 OpenStack 整合到了高性能集群生产环境,每台物理服务器上配置成一个 OpenStack Compute 计算节点(nova-compute),每个 Compute 节点上运行一个虚拟机,每个虚拟机配置成一个 SGE 运算节点(sge_execd)。为啥不直接在物理服务器上配置成 SGE 运算节点?因为运行在虚拟机上更方便、更灵活,可以随时迅速关闭、重装、更换、启动系统。这也是云计算、虚拟机的巨大优势,不用去机房捣腾硬件、不用刻盘重装系统,省时省力。

在 OpenStack 的一个实例上(Ubuntu)安装完 SGE 执行结点(hostname 是 grid62),手动启动守护进程(sge_execd)的时候报错:

$ ssh root@grid62

# /etc/init.d/gridengine-exec restart
 * Restarting Sun Grid Engine Execution Daemon sge_execd
error: communication error for "grid62.novalocal/execd/1" running on port 6445: "can't bind socket"
error: commlib error: can't bind socket (no additional information available)

到主控节点(hostname 是 grid00)上查看日志发现原因 grid62.novalocal 这个域名不能解析:

$ ssh root@grid00

# cat /var/spool/gridengine/qmaster/messages | grep grid62
...
08/26/2012 12:14:15|listen|grid00|E|commlib error: can't resolve host name (can't resolve rdata hostname "grid62.novalocal")
08/26/2012 12:14:16|listen|grid00|E|commlib error: local host name error (remote rdata host name "grid62.novalocal" is not equal to local resolved host name "(HOST_NOT_RESOLVABLE)")

进一步调查发现 grid62.novalocal 这个名字我们的 Puppet 服务器在 OpenStack 启动虚拟机实例后注射到虚拟机 /etc/hosts 里面的(我们的 SGE 节点由 Puppet 管理),Puppet 得到这个 grid62.novalocal 名字而不是 grid62.vpsee.com 这样真实的域名和 OpenStack 自己的 DNS 管理有关,这个问题从 Puppet 或 OpenStack dnsmasq 方面入手都可以解决,不过最简单的方法是从虚拟机实例入手。

解决办法是在 grid62 这个虚拟机实例的 /etc/hosts 文件里加上 grid62 一行,然后 kill 掉现有的 sge_execd 进程并重新启动 gridengine-exec (sge_execd):

# vi /etc/hosts
127.0.0.1	localhost.localdomain	localhost
192.168.2.62	grid62.vpsee.com	grid62

# killall sge_execd

# /etc/init.d/gridengine-exec start

试玩 Rackspace 的 OpenStack 私有云系统

8月15日 Rackspace 发布了一套基于 OpenStack/KVM/Chef/Ubuntu 的私有云系统(代码名 Alamo),可以免费在自己的服务器上安装和建立自己的私有云(最多可以支持20个计算节点),简单的说 Alamo 就是 Rackspace 版的 OpenStack,OpenStack 生态链正在形成,有点像当年的 Linux(比如,Redhat 版的 Linux),明年 Redhat 将发布自己的 Redhat 版 OpenStack,版本大战还在后面。Alamo 可以免费使用,Rackspace 也为该系统提供付费技术支持,据称该系统也是 Rackspace 目前用于自己数据中心的云系统,稳定性有保障。有了这套傻瓜云计算系统,大家再不用自己痛苦的手动安装 OpenStack 或使用 DevStack 自动安装 OpenStack 了,任何人都可以快速的发布自己的私有云。

今天在 VMware ESXi 上试玩了一下这套系统,安装过程非常简单顺利,在 VMware ESXi 5.1 上安装这套系统有几点需要注意:

  • 因为 Alamo 使用了 KVM,所以确定 VMware ESXi 虚拟机上可以运行 KVM,如果直接在物理服务器上安装这一步就省了,不过要确定 CPU 支持虚拟化;
  • 到 Rackspace 官网注册后会收到下载链接,需要在24小时内下载 alamo-v1.0.0.iso,否则下载链接会失效;
  • 按照 Installing Rackspace Private Cloud – VMWare ESXi 教程在 VMware ESXi 上安装需要注意两个参数 vcpu.hotadd = FALSE, hypervisor.cpuid.v0 = FALSE. 可以 ssh 到 VMware ESXi 服务器后直接修改 vmx 配置文件(同样,在物理服务器上忽略这一步骤):
    $ ssh [email protected]
    
    # vi /vmfs/volumes/localstore/alamo00/alamo00.vmx
    ...
    vcpu.hotadd = FALSE
    hypervisor.cpuid.v0 = FALSE
    ...
    

安装完成后界面如下(咋看上去还以为是 XenServer 呢):

rackspace openstack

用浏览器打开 IP 地址后出现 OpenStack Dashboard 的标准界面:
rackspace openstack dashboard

调整 KVM 虚拟硬盘大小

在 OpenNebula 上创建 KVM 虚拟机如果没有事先规划好虚拟机硬盘,运行一段时间后可能过小的硬盘会成为麻烦,需要能自由的增加虚拟机硬盘容积,有两个办法:一是可以在 OpenNebula 上动态加入第二块硬盘解决第一块硬盘过小的问题;二是直接在第一块硬盘上扩大容积。第一种办法好办,直接用 virsh attach-disk 就可以。如果和调整 Xen 虚拟硬盘大小一样,不想加第二块硬盘,只想在第一块硬盘上扩大容积呢?这里只讨论虚拟机文件形式的硬盘,LVM 形式的 “硬盘” 更容易一些,可以用 lvextend + fsck 调整硬盘大小。

最简单的办法是使用 GParted,挂载 gparted-live iso 文件后启动图形化界面操作分区,很容易:

# kvm -m 512 -hda disk.0 -cdrom /root/gparted-live-0.12.1-5.iso -boot d -vnc :1

这里主要介绍不用 GParted 的办法,分区用 fdisk 就可以了,没有必要也不适合在服务器上使用图形化工具。扩大硬盘镜像:

# qemu-img resize disk.0 +100GB

找一个空闲的 loop 设备并挂上硬盘镜像:

# losetup -f
/dev/loop0

# losetup /dev/loop0 disk.0

用 fdisk 把以前的分区都删除,然后重新创建分区,如果有 swap 区依然要用类型 82 标注,boot 区要标明 bootable,要非常小心:

# fdisk /dev/loop0

挂载硬盘里面的 LVM 分区、强制校验文件系统并扩大文件系统:

# kpartx -av /dev/loop0 
# e2fsck -f /dev/mapper/loop0p1 
# resize2fs -f /dev/mapper/loop0p1 

用 mount 测试一下扩大后的文件系统是否能正常 mount:

# mount /dev/mapper/loop0p1 /mnt
# ls /mnt

卸载和清理:

# umount /mnt
# kpartx -dv /dev/loop0 
# losetup -d /dev/loop0

把上面的步骤弄个小脚本,只对 http://cloud-images.ubuntu.com/ 下载的镜像有效,如果是自己做的镜像需要调整 fdisk 分区时候的指令。注意这里 fdisk 分区的时候 d 是删除分区 n 是创建分区 p 是主分区 1 是第1个 2是第2个 w 是保存,具体看 fdisk 帮助:

#!/bin/bash

DISK=$1
SIZE=$2

qemu-img resize $DISK $SIZE

losetup /dev/loop0 $DISK
fdisk /dev/loop0 <<EOF
d
n
p
1
2

w
EOF

kpartx -av /dev/loop0
e2fsck -f /dev/mapper/loop0p1
resize2fs -f /dev/mapper/loop0p1
kpartx -dv /dev/loop0

losetup -d /dev/loop0