ZFS Pool 里增加硬盘做镜像

ZFS 第一次出现在 OpenSolaris 上是在2005年11月发布的 build 27 版本,因为稳定性、可靠性等原因直到最近 VPSee 才有考虑把它用在生产环境里,现在 VPSee 所有的 Solaris 服务器还是在用很古老的 UFS,UFS 仍是 Solaris 10 的默认文件系统。昨天简单玩了一下 ZFS,用6个文件模拟6个硬盘在 ZFS 上进行了一系列添加、删除、镜像的操作,立刻体会到了 ZFS 的强大,但这与实际操作物理硬盘还是有点差别。VPSee 当时安装 OpenSolaris 的时候只用了一块 250GB 的硬盘,现在可以增加一块 250GB 的硬盘做镜像,试验一下 ZFS 强大的 mirror,相当于做 RAID1.

检查 pool

要在服务器上增加一块实际硬盘,先要看看系统原来的 pool 有什么:

# zpool status
  pool: rpool
 state: ONLINE
 scrub: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          c8t0d0s0  ONLINE       0     0     0

errors: No known data errors

上面显示 c8t0d0s0 是里面唯一的一块硬盘。现在插上一块新硬盘后(必要时需要重启)运行 format 工具:

# format
Searching for disks...

The device does not support mode page 3 or page 4,
or the reported geometry info is invalid.
WARNING: Disk geometry is based on capacity data.

The current rpm value 0 is invalid, adjusting it to 3600
done

c8t1d0: configured with capacity of 232.87GB


AVAILABLE DISK SELECTIONS:
       0. c8t0d0 
          /pci@0,0/pci108e,534c@5/disk@0,0
       1. c8t1d0 
          /pci@0,0/pci108e,534c@5/disk@1,0
Specify disk (enter its number):

按 “Ctrl + C” 退出。c8t0d0 是原来的硬盘,c8t1d0 是后来加上去的新硬盘。

分区和 label

现在用 -e 参数再次运行 format,然后选择 partition,创建一个 Solaris 分区后打印出分区表看看,只有 s0, s2, s8 有内容。完成分区后退到 format 菜单,接着选择 label,因为大多数的 PC BIOS 都不支持 EFI labels,所以要选择 SMI:

# format -e c8t1d0

format> partition
SELECT ONE OF THE FOLLOWING:
   1. Create a partition
...

partition> print
Current partition table (original):
Total disk cylinders available: 30398 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders         Size            Blocks
  0       root    wm       1 - 30396      232.85GB    (30396/0/0) 488311740
  1 unassigned    wu       0                0         (0/0/0)             0
  2     backup    wu       0 - 30396      232.85GB    (30397/0/0) 488327805
  3 unassigned    wu       0                0         (0/0/0)             0
  4 unassigned    wu       0                0         (0/0/0)             0
  5 unassigned    wu       0                0         (0/0/0)             0
  6 unassigned    wu       0                0         (0/0/0)             0
  7 unassigned    wu       0                0         (0/0/0)             0
  8       boot    wu       0 -     0        7.84MB    (1/0/0)         16065
  9 unassigned    wu       0                0         (0/0/0)             0
partition>quit

format> label
[0] SMI Label
[1] EFI Label
Specify Label type[0]: 0
Ready to label disk, continue? y

做镜像

退出 format,在 rpool 里增加新硬盘作为第1一块硬盘 mirror,会出现以下报错:

# zpool attach -f rpool c8t0d0 c8t1d0
cannot label 'c8t1d0': EFI labeled devices are not supported on root pools.

我们必须把 VTOC 从第1块硬盘拷贝到第2块硬盘,注意这里 s2 是 slice(分区),c8t0d0s2 是 c8t0d0 的 s2 分区,注意上面打印的分区显示 s2 代表整个硬盘,看 Blocks 发现 s2 = s0 + s8,s0 是 root 分区,s8 是 boot 分区:

# prtvtoc /dev/rdsk/c8t0d0s2 | fmthard -s - /dev/rdsk/c8t1d0s2 
fmthard: Partition 2 specifies the full disk and is not equal
full size of disk.  The full disk capacity is 488343870 sectors.
fmthard:  New volume table of contents now in place.

新硬盘的 c8t1d0s0 分区做成 c8t0d0s0 的镜像,注意上面打印的分区显示 s0 是 root 分区,有 232.85GB 空间,也是我们想 mirror 的分区:

# zpool attach -f rpool c8t0d0s0 c8t1d0s0
Please be sure to invoke installgrub(1M) to make 'c8t1d0s0' bootable.

安装 grub

这一步非常重要,需要把 grub 安装在第二块硬盘上:

# installgrub -m /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c8t1d0s0 
Updating master boot sector destroys existing boot managers (if any).
continue (y/n)?y

校验 pool

校验 pool 后查看校验后状态:

# zpool scrub rpool

# zpool status
  pool: rpool
 state: ONLINE
 scrub: scrub in progress for 0h0m, 0.95% done, 0h26m to go
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          c8t0d0s0  ONLINE       0     0     0
          c8t1d0s0  ONLINE       0     0     0

errors: No known data errors

ZFS 的简单使用

ZFS 被 Sun 称为史上最后一个文件系统,说得一点都不夸张,在 VPSee 看来 ZFS 至少要比现有的其他文件系统领先五年。开发一个全新的文件系统非常耗时,ext4 从2006开始到现在都三年了而且还是在前人的基础上(ext3)开发的,最近 RedHat 发布的 RHEL 5.4 还只是把 ext4 列入 technical preview 的状态,默认的安装文件系统还是 ext3,可见要开发一个可靠的文件系统多么困难,ext4 仍然不够稳定,在系统崩溃时某些条件下可能会造成数据丢失现象。虽然 ZFS 是开放源代码的,由于版权是 CDDL 与 Linux kernel 的 GPL2 冲突,导致 ZFS 不能移植到 Linux 上,FreeBSD 上的 ZFS 移植不完整而且不是很稳定,如果想用 ZFS 的话,建议安装和使用 OpenSolaris,以下操作在 OpenSolaris 2009.06 上执行。

准备工作

先创建6个普通文件充当6个硬盘,来看看 ZFS 是如何方便的添加、删除、镜像硬盘的:

# cd /var/tmp
# mkfile 100m c0d0 c0d1 c0d2 c1d0 c1d1 c1d2

创建 pool

使用第1块硬盘(c0d0)创建一个 pool:

# zpool create mypool /var/tmp/c0d0 
# zpool status
  pool: mypool
 state: ONLINE
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        mypool           ONLINE       0     0     0
          /var/tmp/c0d0  ONLINE       0     0     0

errors: No known data errors

创建镜像

在 pool 里添加第2块硬盘(c0d1),并且做成第1块硬盘(c0d0)的镜像:

# zpool attach mypool /var/tmp/c0d0 /var/tmp/c0d1
# zpool status
  pool: mypool
 state: ONLINE
 scrub: resilver completed after 0h0m with 0 errors on Sun Nov  1 15:08:42 2009
config:

        NAME               STATE     READ WRITE CKSUM
        mypool             ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            /var/tmp/c0d0  ONLINE       0     0     0
            /var/tmp/c0d1  ONLINE       0     0     0  73K resilvered

errors: No known data errors

替换硬盘

假设上面第2块硬盘(c0d1)坏了,想用另一块硬盘(c1d0)替换:

# zpool replace mypool /var/tmp/c0d1 /var/tmp/c1d0 
# zpool status
  pool: mypool
 state: ONLINE
 scrub: resilver completed after 0h0m with 0 errors on Sun Nov  1 15:11:33 2009
config:

        NAME               STATE     READ WRITE CKSUM
        mypool             ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            /var/tmp/c0d0  ONLINE       0     0     0
            /var/tmp/c1d0  ONLINE       0     0     0  83.5K resilvered

errors: No known data errors

增加硬盘

如果发现上面两块硬盘不够用了,想在 pool 里增加第3块硬盘(c0d1)只需要简单的 zpool add,这时候需要用到 -f 强制选项,因为 pool 里硬盘类型是 mirror 的,而想要增加的硬盘是 file 的,类型不同所以报错,需要强制执行:

# zpool add mypool /var/tmp/c0d1
invalid vdev specification
use '-f' to override the following errors:
mismatched replication level: pool uses mirror and new vdev is file

# zpool add -f mypool /var/tmp/c0d1
# zpool status
  pool: mypool
 state: ONLINE
 scrub: resilver completed after 0h0m with 0 errors on Sun Nov  1 15:11:33 2009
config:

        NAME               STATE     READ WRITE CKSUM
        mypool             ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            /var/tmp/c0d0  ONLINE       0     0     0
            /var/tmp/c1d0  ONLINE       0     0     0  83.5K resilvered
          /var/tmp/c0d1    ONLINE       0     0     0

errors: No known data errors

现在用第4块硬盘(c1d1)对第3块硬盘(c0d1)做一个镜像;然后加上第5块硬盘(c0d2)和第6块硬盘(c1d0),其中第6块是第5块的镜像:

# zpool attach mypool /var/tmp/c0d1 /var/tmp/c1d1
# zpool add mypool mirror /var/tmp/c0d2 /var/tmp/c1d2 

完成上面的操作以后就会得到类似下面这样的结构,很清晰易懂,c0d0 和 c1d0 是镜像,c0d1 和 c1d1 是镜像,c0d2 和 c1d2 是镜像:

# zpool status
  pool: mypool
 state: ONLINE
 scrub: resilver completed after 0h0m with 0 errors on Sun Nov  1 15:24:51 2009
config:

        NAME               STATE     READ WRITE CKSUM
        mypool             ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            /var/tmp/c0d0  ONLINE       0     0     0
            /var/tmp/c1d0  ONLINE       0     0     0
          mirror           ONLINE       0     0     0
            /var/tmp/c0d1  ONLINE       0     0     0
            /var/tmp/c1d1  ONLINE       0     0     0  14.5K resilvered
          mirror           ONLINE       0     0     0
            /var/tmp/c0d2  ONLINE       0     0     0
            /var/tmp/c1d2  ONLINE       0     0     0

errors: No known data errors

是不是要比 RAID + LVM + EXT3 简单多了?

校验 pool

最好经常时不时的用 zpool scrub 检查一下 pool 和 checksums:

# zpool scrub mypool

删除 pool

# zpool destroy mypool
# rm /var/tmp/c[01]d[012]

在 OpenSolaris 上安装和配置 Xen

OpenSolaris 的一个杀手级应用就是 ZFS,很多人也是为了 ZFS 而 ”不得不“ 用 OpenSolaris/Solaris,虽然现在 FreeBSD 上也有 ZFS 的移植,但不是很稳定。ZFS 把存储管理(volume management)和文件系统(file system)两个功能结合在一起,提供了一种全新的存储管理方式,磁盘管理简单,想增加磁盘加到 pool 里就可以了;基于事务,保证数据完整、一致;自动修复,没有 fsck 的痛苦;自由伸缩,自由增减磁盘;快照,轻松而快速地创建快照;海量存储,几乎无限的存储容量等这些优点使得 ZFS 很适合做存储、文件服务器。这也是 VPSee 想用 OpenSolaris 做 dom0 的一个主要原因,ZFS 将会给 domUs 的备份、扩展带来极大方便,现在正在测试,将来会用 ZFS 来存储 10GB×2×400=8TB 的虚拟机镜像(400个人,每个人2种桌面系统 ubuntu 和 windows,每种系统占用 10GB)。下面的安装步骤和配置过程基于 OpenSolaris 2009.06 版本,Ubuntu,Debian 和 CentOS 版本可以分别看这里:在 Ubuntu 上安装和配置 Xen在 Debian 上安装和配置 Xen在 CentOS 上安装和配置 Xen,NetBSD 版本参看:在 NetBSD 上安装和配置 Xen.

安装 xVM

Sun 把 Xen 移植到 OpenSolaris 后改叫 xVM. 首先创建一个单独的启动环境,这一步不是必须的:

# beadm create -a -d xvm xvm

安装必要的软件包:

# beadm mount xvm /tmp/xvm-be 
# pkg -R /tmp/xvm-be install SUNWvirt-manager SUNWxvm SUNWvdisk SUNWvncviewer 
# beadm umount xvm

安装成功后,检查 Xen 内核是否已经加到 grub 启动文件里:

# vi /rpool/boot/grub/menu.lst

title xvm
findroot (pool_rpool,0,a)
bootfs rpool/ROOT/xvm
kernel$ /boot/$ISADIR/xen.gz
module$ /platform/i86xpv/kernel/$ISADIR/unix /platform/i86xpv/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=text
module$ /platform/i86pc/$ISADIR/boot_archive

# bootadm list-menu
the location for the active GRUB menu is: /rpool/boot/grub/menu.lst
default 1
timeout 2
0 OpenSolaris 2009.06
1 xvm

打开 xVM 服务:

# svcadm enable -r xvm/virtd ; svcadm enable -r xvm/domains

重启系统后看一下 Xen 的内核(i86xpv)以及 xend 是否启动:

# uname -a
SunOS vpsee 5.11 snv_111b i86pc i386 i86xpv

# xm list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0  1879     2     r-----     24.0

创建和安装 guest

用 zfs 工具创建一个 volume 保存 guest 操作系统的 image:

# zfs create -o compression=on -V 5G rpool/vm

# zfs list
NAME                     USED  AVAIL  REFER  MOUNTPOINT
...
rpool/vm               5G   222G    16K  -
...

# ls -l /dev/zvol/dsk/rpool/
total 3
...
lrwxrwxrwx 1 root root 35 Oct 28 09:56 vm->../../../../devices/pseudo/zfs@0:3c
...

从 ISO 文件(osol-0906-x86.iso)安装 OpenSoaris Guest 操作系统,注意这里 -p 选项是 paravirtualized 安装,paravirtualized 不能安装 windows:

# virt-install --nographics -p -r 1024 -n vm01 -f /dev/zvol/dsk/rpool/vm \
-l /export/home/vpsee/osol-0906-x86.iso

要安装 windows 需要使用 fully virtualized 选项并且要有 CPU 的支持(Intel VT or AMD V)。服务器上面通常没有图形界面,所以图形化安装 windows 需要打开 vnc 服务,并给 vnc 设置一个密码,然后从 vnc client 登录后就可以看到 windows 的安装界面了:

# svccfg -s xvm/xend setprop config/vnc-listen = astring: \"0.0.0.0\"
# svccfg -s xvm/xend setprop config/vncpasswd = astring: \"password\"

# virt-install -v --vnc -n vm02 -r 512 -f /dev/zvol/dsk/rpool/vm \
-c /export/home/vpsee/windowsxp.iso --os-type=windows

进入 guest

Guest 安装成功后就可以登进去了:

# xm console vm01

如果要退出 guest 的话,用 Ctrl + ] 就会回到 host。

Troubleshooting

ZFS 很容易就耗光 dom0 的可用内存,所以要对 ZFS ARC 的内存使用做限制,如下设定最大可用内存为 256MB:

# vi /etc/system
...
set zfs:zfs_arc_max = 0x10000000

限制 dom0 内存也对系统的安全有所帮助,在 gurb/menu.lst 加一行可以设定 Xen dom0 的最大可用内存为 1GB:

# vi /rpool/boot/grub/menu.lst
...
kernel$ /boot/$ISADIR/xen.gz dom0_mem=1024M
...

最小化安装 OpenSolaris 2009.06

opensolaris

OpenSolaris 有一些令其他系统羡慕的创新技术,比如:ZFS, DTrace, Containers, Crossbow 等。因为版权原因有些技术还不能直接移植到 Linux 上,Mac 已经在其新发行的 Mac OS X Snow Leopard 中应用了 DTrace,但是最近 Apple 突然关闭了 ZFS 项目并停止了对 ZFS 的支持,据外界猜测和 NetApp 的版权有关。OpenSolaris 的这些很酷的技术只有在服务器端才能发挥最大价值,但是感觉 OpenSolaris 面向的是桌面用户,我们在桌面已经有了 Mac OS X/Ubuntu/Windows 7,OpenSolaris 要想进入桌面市场难度很大,VPSee 一直认为 Sun 和 OpenSolaris 社区应该好好利用 Solaris 的强大技术优势把 OpenSolaris 的发展重点放在服务器端,特别是高端服务器。OpenSolaris 在安装过程中没有提供最小化安装选择,可定义的选项也很少,这里提供一种最小化安装 OpenSolaris 的方法,可供服务器安装。

安装系统

OpenSoaris 的安装很傻瓜,甚至比多数 Linux 版本还简单,只需按几下鼠标就可完成。

最小化

默认安装完的 OpenSolaris 是一个拥有丰富功能的全桌面系统,对于服务器来说太过庞大,很多服务、软件包、图形界面,Office 套件等都不需要,既占 CPU/RAM 资源又霸占硬盘。这里用一个 Immutable Service Container 项目提供的脚本来自动删除不必要的软件包和服务。首先下载这个脚本然后运行:

$ hg clone https://kenai.com/hg/isc~source isc

$ pfexec svcadm disable gdm
$ pfexec isc/opt/samples/minimization.ksh

运行脚本后会删除237个软件包停止11个服务,OpenSolaris 占据的硬盘空间由 2.92GB 减少到 1.28GB.

Troubleshooting

那个脚本可能删除了一些软件包关联和配置文件,导致系统会可能会出现一点小问题:1)DHCP 不停的得到 IP 释放 IP;2)DNS client 不能正确工作,可以 ping IP 但是不能 ping 域名。根据具体情况修改下面一些 OpenSolaris 网络设置。

使用静态 IP 地址:

$ pfexec vi /etc/nwam/llp
pcn0    172.16.38.10

$ pfexec svcadm restart nwam

检查 DNS 设置:

$ pfexec cp /etc/nsswitch.dns /etc/nsswitch.conf 
$ svcs -a | grep dns 

$ pfexec vi /etc/resolv.conf

检查 Routing:

$ pfexec vi /etc/defaultrouter
172.16.38.1

$pfexec svcadm restart network/routing-setup