doc:z:zfsonly

从头安装纯 ZFS 的系统 (适用于 8.x, 9.x 及 CURRENT 系统)

系统需求

ZFS 要求至少 8GB 内存的 amd64 (也称做 x86_64, x64 或 EM64T 的 AMD 或 Intel 处理器)。使用更少的内存或 FreeBSD/i386 运行 ZFS 是可能的,但出问题自己想办法。

使用 ZFS 时应启用 swap。swap的容量对于超过2GB内存的机器来说,使用大致相当于内存容量的 swap 就可以了。与内存需求类似,不使用 swap 运行 ZFS 也是可能的,但出问题请自己想办法。

存储规划

一般来说应根据实际的需要进行规划。ZFS 并不要求系统中存在多个 zpool,但用于引导系统的 zpool 最好是独立的,这样做主要的考虑是:

  • 这个 zpool 通常比较重要,因而可以在多个磁盘上做跨盘镜像(mirror),从而在系统出现问题时交换磁盘位置即可引导系统;
  • 这个 zpool 通常至少会有一个文件系统希望以 / 作为挂点,因而可能要在其中一个或全部 zfs 上设置挂点,而设置了挂点的 zfs 在复制时需要特别小心。分开的 zpool 可以方便进行备份;
  • 这个 zpool 以及其上的文件系统不能够随便升级。引导区可能暂时不支持新版本的 zpool 或 zfs,分开的 zpool 有助于减少出现这类问题的机会。

以下分区方案仅供参考:

在系统中的每一个磁盘上进行下面的分区:

序号容量类型用途
164KiBfreebsd-boot引导系统的第二部分boot,尺寸必须大于 /boot/gptzfsboot 按扇区尺寸向上取整的容量;实际使用时,由于对齐的原因,我们使用94个扇区而不是128个扇区
2大约2GBfreebsd-zfs用于引导系统的zpool
3大约内存容量/磁盘数或1GB,两者中较多的那一个数字freebsd-swap交换区
4余下容量freebsd-zfs用于存放数据的zpool

下面对前面的设计进行简单的说明:

引导区:引导区是引导过程中找到 zpool 的必要组件。实际上,只有第一块硬盘上的引导区是必须存在的,但每块硬盘上都有引导区的好处是系统可以从任意一块硬盘启动,从而方便恢复系统。注意,在升级系统时,应同时升级全部引导区。 系统zpool:这个配置假定基本系统需要的容量不超过 2GB (正常情况下 1GB 是绝对足够的),而几块磁盘上的这些部分采用 mirror 方式。这样可以保证系统在至少有一块硬盘可以访问的情况下也可以启动。 交换区:交换区必须存在。对于内存超过4G的系统,通常推荐交换区总容量与内存尺寸相同。交换区的另一个作用是当更换的硬盘容量略有差异时(有时硬盘厂商的硬盘可能与标称容量有若干MB的差异),可以通过适当减少交换区容量来确保后面两个分区的尺寸不变。注意,如果需要热插拔,则应对交换区做适当处理,例如在移除磁盘之前做swapoff等。 数据zpool:这些分区将最终构成保存数据的 zpool。

脚本化

个人建议将磁盘初始化的过程使用脚本来完成。下面是一个简单的例子:

#!/bin/sh
 
if [ -z "$1" ]; then
        echo "Usage: $0 device"
        exit 1
fi
 
DRIVE=$1
gpart destroy -F ${DRIVE} > /dev/null 2>&1 || true
gpart create -s gpt ${DRIVE}
gpart add -a 4k -s 64k -t freebsd-boot ${DRIVE}
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ${DRIVE}
gpart add -a 4k -s 2g -t freebsd-zfs ${DRIVE}
gpart add -a 4k -s 2g -t freebsd-swap ${DRIVE}
gpart add -a 4k -t freebsd-zfs ${DRIVE}
# 对于4k硬盘,增加下面两行:
# gnop create -S 4096 ${DRIVE}p2
# gnop create -S 4096 ${DRIVE}p4

其中,gpart add -a 4k表示令系统按4K扇区对齐。对于非4K扇区的硬盘来说并不一定需要,但并不会对性能产生负面影响。

这个例子会创建必要的分区并安装引导记录。

全新安装之具体操作

使用 LiveFS 光盘引导系统,选择 LiveFS,以 root 身份登录(9.x和更高版本;对8.x是在 sysintall 中选择 Fix It,然后进入 Live FS)。

接下来,首先初始化系统的 hostid:

# /etc/rc.d/hostid onestart

在此之后,我们可以初始化分区,使用前面的脚本的话,操作大致是:

# sh initdisk.sh ada0
 
# sh initdisk.sh ada1
 
# sh initdisk.sh ada2
 
# sh initdisk.sh ada3
 
...

接下来启用 swap。通常,这一步并不是必需的,但推荐做一下:

# swapon /dev/ada*p3

下一步,创建引导系统使用的 zpool,我们把它命名为 zboot:

# mkdir /tmp/mnt
# zpool create -O mountpoint=/tmp/mnt -O atime=off -O setuid=off -O compression=on -O canmount=off zboot mirror /dev/ada*p2
## 对于4k硬盘,把ada*p2换成ada*p2.nop

这里, atime=off 不是必需的,但通常 / 并不需要 atime,它可以减少少量的不必要的写操作;setuid=off会令整个文件系统默认禁止 setuid,整个系统中绝大多数部分都不需要 setuid;canmount=off表示默认不挂载这个文件系统;compression=on表示启用压缩,这个也不是必需的,但由于现在 CPU 的速度通常都很快,它可以节省一些启动时间。

然后创建用于引导系统的那个 ZFS,我们给他起名叫 sysroot,这将是系统未来的 /。注意,在创建 zboot 这个 zpool 的时候,它有一个同名的叫做 zboot 的 ZFS,我们并不直接使用这个文件系统,因为那样会丧失很多灵活性。

# zfs create -o mountpoint=legacy -o setuid=on zboot/sysroot
# zpool set bootfs=zboot/sysroot zboot
# mount -t zfs zboot/sysroot /tmp/mnt

现在,/tmp/mnt 就是未来的 / 了。

创建其他必需的文件系统

到目前为止,在 / 上的任何地方都是允许 setuid 的。一般说来,/tmp 和 /var 并不需要允许 setuid,但它们确实需要出现在从 / 算起的位置。前面我们将 zboot 的 mountpoint 设为 /tmp/mnt,但设为 canmount=off,这会让系统默认不挂这个文件系统,但令其下的其他 dataset 的默认挂点都从此开始。考虑到我们已经将 zboot/sysroot 挂到了 /tmp/mnt,我们接下来在 zboot 上创建的 dataset 也会挂到它下面。

未来挂点数据集名称备注
无挂点zboot存储池的起点,暂时设为 /tmp/mnt,最后一步将其改为 /
/zboot/sysroot系统的根目录,明确指定挂点为legacy
/tmpzboot/tmp临时目录,权限必须为1777,不需要setuid
/varzboot/var不需要setuid

注意事项:

  • /tmp 不一定需要放在磁盘上;此外如果有需要的话也可以把它放到存数据的 zpool 上,把 mountpoint 设为 legacy 并用 fstab 来挂。
  • /var 通常并不需要太大,除非准备不做任何jail直接做应用服务器来用,这种情况可以用类似 tmp 的方法来把它拆到另外的 zpool 上去。
  • /usr/local 最好保存到另外的 zpool。通常可以在对应的 zpool 上建立文件系统,并符号链接过去,同时在 /etc/make.conf 中加入 LOCALBASE=/dpool/local 之类的设置。

具体操作大致如下:

zfs create zboot/tmp
zfs create zboot/var

安装系统

这个操作非常简单:

tar xvf /usr/freebsd-dist/base.txz -C /tmp/mnt
tar xvf /usr/freebsd-dist/kernel.txz -C /tmp/mnt

然后编辑 /tmp/mnt/etc/fstab 使其包括下面内容:

# Device                Mountpoint      FStype  Options         Dump    Pass#
zboot/sysroot           /               zfs     rw,noatime      0       0
/dev/ada0p3             none            swap    sw              0       0
/dev/ada1p3             none            swap    sw              0       0
/dev/ada2p3             none            swap    sw              0       0
/dev/ada3p3             none            swap    sw              0       0

fstab 非常重要。loader 需要根据它来找到 /。

做一个简单的 /etc/rc.conf 配置,编辑 /tmp/mnt/etc/rc.conf,加入一些最基本的内容:

zfs_enable="YES"                        # 在适当的时候做 zfs mount -a 挂载全部 ZFS 文件系统
hostname="你的机器名"                     # RFC 1123
defaultrouter="10.0.0.1"    # 默认网关,根据实际情况修改
ifconfig_em0="inet 10.0.0.1 netmask 255.255.255.0"    # 网卡IP配置,根据实际情况修改
sshd_enable="YES"                       # 启用 sshd
ntpd_enable="YES"                       # 启用 ntpd
ntpd_sync_on_start="YES"                # 令 ntpd 在系统引导时一次性调整时钟
syslogd_flags="-ss"                     # 禁止 syslogd 的网络监听,这不是必需的

配置 resolv.conf (/tmp/mnt/etc/resolv.conf):

search 希望自动搜索的域名
nameserver DNS服务器

配置时区:

mount -t devfs devfs /tmp/mnt/dev
chroot /tmp/mnt /usr/sbin/tzsetup -s /usr/share/zoneinfo/Asia/Shanghai
umount /tmp/mnt/dev

注意!/boot必须是/的一部分,不要使用 zfs create 来创建它!

接着在 /tmp/mnt/boot/loader.conf 中添加下列内容:

zfs_load="YES"

将 zpool.cache 写到合适的位置:

zpool set cachefile=/tmp/mnt/boot/zfs/zpool.cache zboot

至此,可以引导系统的基本系统就装好了。此时,从硬盘应该可以引导系统了。

配置系统

从硬盘引导系统之后,我们接着对系统进行一些必要的配置。首先是初始化用于保存数据的文件系统。

根据硬盘的数量,下面是推荐的冗余情况(硬盘个数为除备盘之外的硬盘个数):

硬盘个数推荐的冗余形式实际保存数据的盘数
1无冗余 *-
2mirror2
3raidz2
4两对mirror或raidz2 *4或2
5raidz4
6raidz24
7不推荐 *-
8四对mirror8
9raidz8
10raidz28

总体的原则是:任意 vdev 中实际保存数据的盘数应为2的整数次方幂,如果有多个 vdev,则 vdev 数量也应是2的整数次方幂。

通常,4块硬盘应配置为2对mirror,而不是 raidz2 或 raidz。使用 raidz2 的好处是可以坏任意两块硬盘(两对mirror时,要求mirror内部只能坏最多1块硬盘),但读性能会比两对 mirror 差。raidz则会导致实际保存数据的盘的数量为3,从而影响性能。

ZFS 本身可以在某些文件系统上通过设置 copies 为 2 或 3 来增加其冗余,如果只有一块硬盘,而数据又比较重要,则可以在这些数据集上设置 copies=2。这个配置会降低性能,而且不会在磁盘彻底坏掉时产生任何帮助,但可以改善恢复数据的机会。

根据实际情况创建文件系统。例如,对于有 4 块硬盘的系统,创建一对 mirror 并命名为 tank:

# zpool create -O atime=off -O setuid=off -O compression=on tank mirror /dev/ada0p4 /dev/ada1p4 mirror /dev/ada2p4 /dev/ada3p4
## 对于4k扇区的硬盘,把上面的p4改为p4.nop;如果已经重启系统,这些.nop设备会消失,需要重做 gnop create -S 4096 ada*p4

新的 zpool 会被挂在 /tank。与 zboot 类似,我们并不使用这个文件系统,而是在其中创建其他用途的文件系统:

# zfs create -o canmount=off tank/usr
# zfs create -o setuid=on tank/usr/local
# ln -s /tank/usr/local /usr/local
# echo 'LOCALBASE=/tank/usr/local' >> /etc/make.conf
# zfs create tank/usr/ports
# zfs create -o compression=off tank/usr/ports/distfiles
# echo 'PORTSDIR=/tank/usr/ports' >> /etc/make.conf
# sed -i '' -e 's,^.*PORTSDIR=.*$,PORTSDIR=/tank/usr/ports,g' /etc/portsnap.conf
# ln -sf /tank/usr/ports /usr/ports
# zfs create tank/usr/home
# ln -sf /tank/usr/home /home
# ln -sf /tank/usr/home /usr/home
# zfs create -o canmount=off tank/var
# zfs create tank/var/db
# zfs create -o compression=off tank/var/db/portsnap
# tar cf - /var/db | tar xf - -C /tank
# sed -i '' -e 's,^.*WORKDIR=.*$,WORKDIR=/tank/var/db/portsnap,g' /etc/portsnap.conf
# zfs create tank/var/log
# /etc/rc.d/syslogd stop
# tar cf - /var/log | tar xf - -C /tank
# rm -fr /var/db /var/log
# ln -sf /tank/var/db /var/db
# ln -sf /tank/var/log /var/log
# /etc/rc.d/syslogd start

说明:上面并不是非常详尽的例子,需要根据实际需求进行适当的调整。比较常见的需求是为每个用户使用不同的 ZFS 作为其 /home 目录,或者希望把 /usr/src, /usr/obj 拆到数据 zpool 上,等等。注意,如果需要把系统引导时需要的文件系统单独做一个dataset或卷,应将其mountpoint设为legacy并在fstab中写入对应的配置,这种方法并不推荐,故此处略去具体写法。

/data/vhosts/wiki-data/pages/doc/z/zfsonly.txt · 最后更改: 2013/03/23 11:33 由 alphachi