去年,我需要创建有关安装Ubuntu 18.04操作系统的说明。 顺便说一句,安装Ubuntu并不复杂,但有一个细微差别:我想使用ZFS文件系统作为基础。 一方面,Ubuntu在内核级别支持ZFS,但尚无安装程序,但有一条说明,可以:
https://github.com/zfsonlinux/zfs/wiki/Ubuntu-18.04-Root-on-ZFS
本手册中的操作顺序通常是正确的,但某些方面需要调整。 因此,以下内容不是对说明的直接翻译,而是免费的,并考虑到更正,我在ZFS方面的经验和其他方面。 我也不考虑磁盘加密问题,而是使用MBR引导加载程序。 我的安装说明可以在这里获得。
0.服务器准备
指令中缺少的第一件事是,无论如何都没有考虑到ZFS不能与硬件RAID阵列很好地配合,特别是它与Write cache连接在一起,这是可以理解的:ZFS文件系统已记录日记并且需要对写操作进行完全控制。 同样,当使用现成的硬件RAID阵列时,ZFS功能在缓存,备用等方面也会丢失。 因此,必须将所有磁盘都转移到HBA模式,如果不可能,则为每个磁盘创建单独的RAID并禁用写缓存控制器。
另外,在使用网络端口聚合时,可以在安装阶段将其禁用,以免使其复杂化(我将执行所有进一步的操作而无需绑定)。
1.准备安装环境
1.1。 直播光盘
如前所述,不幸的是,在ZFS上没有使用root的现成的Ubuntu安装程序,因此使用LiveCD光盘进行安装:
从此处下载: http : //releases.ubuntu.com/18.04/ubuntu-18.04.1-desktop-amd64.iso
同时,我与同事一起尝试使用各种磁盘映像,因为我确实不想使用图形化外壳,但这并没有带来什么好处。
我们从LiveCD启动,选择Try Ubuntu,然后打开终端(Ctrl + Alt + T)。
1.2。 更新和安装存储库
''
sudo apt-add-repository universe sudo apt update
如果服务器的网络设置不是由DHCP确定的,则在这里等待第一个失败者。 更新存储库将不起作用,因此让我们设置网络。
我们查看网络接口,并找到用于连接的接口:
sudo ip a
配置网络接口:
sudo echo "auto {{ NAME }}" >> /etc/network/interfaces sudo echo "iface {{ NAME }} inet static" >> /etc/network/interfaces sudo echo " address {{ IP }}" >> /etc/network/interfaces sudo echo " netmask {{ NETMASK }}" >> /etc/network/interfaces sudo echo " gateway {{ GATEWAY }}" >> /etc/network/interfaces sudo service networking restart
和DNS解析器:
sudo echo 'nameserver 8.8.8.8' >> /etc/resolv.conf
更新存储库:
sudo apt update
1.3。 SSH服务器(可选)
为了便于安装,您可以提升OpenSSH服务器并通过SSH客户端执行所有进一步的操作
设置ubuntu用户的密码:
passwd
这很重要! 否则,将通过不带sudo权限的密码进行ssh访问。 但是,您无法设置简单的密码。
安装并运行OpenSSH:
sudo apt install openssh-server sudo service ssh start
在工作站的终端中:
ssh ubuntu@{{ ip server }}
1.4。 成为根
sudo -s
1.5。 在LiveCD环境中安装ZFS支持
apt install --yes debootstrap gdisk zfs-initramfs
2.分区和格式化硬盘
2.0。 定义磁盘阵列
主要说明不包含有关如何确定磁盘阵列的重点。
通常,服务器上的磁盘数为:
我们不考虑1个磁盘,因为它通常是异常的。
2.0.1。 2碟
这里的一切都很简单,只有一个MIRROR阵列(RAID1)。 如果还有另一个驱动器,则可以将其放入热备用(SPARE)或组装RAIDZ阵列(RAID5)。 但是服务器中只有3个磁盘很少。
2.0.2。 4碟
如果所有驱动器都相同,则只有三个选项(我基本上不考虑第四个RAID0):
- MIRROR + MIRROR是RAID10(更确切地说是RAID01)的类似物,因为在ZFS中它是mirror + mirror。 50%的可用磁盘空间;
- RAIDZ是RAID5的类似物。 75%的可用磁盘空间;
- RAIDZ2是RAID6的类似物。 50%的可用磁盘空间;
在实践中,我使用MIRROR + MIRROR阵列,但很显然RAIDZ阵列最有利可图,因为它提供了更多的磁盘空间,但是有细微差别
在容错方面,阵列按以下顺序排列(从最佳到最差):
- RAIDZ2-两个磁盘可能会丢失而不会丢失数据;
- MIRROR + MIRROR-一个磁盘可能会丢失而不会丢失数据,而另一磁盘有66%的概率可能会丢失而不会丢失数据;
- RAIDZ-只有一个磁盘可以丢失而不会丢失数据;
在速度方面,数组按以下顺序排列:
- MIRROR + MIRROR-在写作和阅读方面;
- RAIDZ-在记录方面较慢,因为除了记录外,还需要计算校验和;
- RAIDZ2 –就写入而言甚至更慢,因为它需要计算更复杂的校验和;
就一个磁盘降级期间的阵列速度而言:
- MIRROR + MIRROR(镜像+镜像)-当一个驱动器掉线时,基本上只有一个镜像的并行读取丢失,第二个镜像正常工作而性能不会降低;
- RAIDZ2-性能下降的幅度更高,因为它需要从校验和中向后分配1/4的数据+块搜索;
- RAIDZ-降级要大得多,因为它需要从1/3的数据+块搜索的校验和中重新计算块;
比较特性是主观的,但足以反映出我作为中间立场的选择。
同时,您需要了解“慢”和“甚至慢”并非有时,但在最坏的情况下只有10%到20%,因此,如果未优化用于磁盘的数据库或应用程序,则会降低速度原则上,不要注意。 仅在真正需要时才考虑记录速度因数。
2.0.2。 许多碟片
主要问题是,如果我们有很多磁盘,并且想要为所有磁盘创建一个通用阵列,那么我们将需要在每个磁盘上标记引导扇区,或者对我们的耳朵做些伪装。 在实践中,对于多碟平台,我尝试构建此配置:
- 2个SSD磁盘-我们创建一个镜像,并作为第二引导磁盘阵列的操作系统和ZFS高速缓存的主引导阵列;
- 其余的都被SATA或SAS磁盘阻塞,并且没有标记,我们收集了ZFS磁盘阵列。
如果我们要获得一个相当通用的平台,则同样适用于4磁盘服务器。
如果磁盘都是相同的,并且没有必要为单独的阵列分配两个磁盘(例如,每个磁盘6个磁盘,每个磁盘8 Tb),则可以使阵列第一组的磁盘可引导。 也就是说,如果您要创建一个数组,例如:MIRROR + MIRROR + MIRROR或RAIDZ + RAIDZ,那么我们仅标记第一组的引导扇区。 原则上,即使对于MIRROR和RAIDZ,也可以只对一个驱动器进行分区,并以原始形式替换其余驱动器,ZFS会通过较小的元素本身来创建阵列,但是在这种情况下,如果第一个驱动器发生故障,则您将丢失唯一的启动磁盘,因此值得这样做。
重要的是要了解,在ZFS-条带文件系统中,这并非完全是RAID0,它的工作方式略有不同,并且不需要相同的磁盘大小,因此为天气的引导扇区分配较小的空间不会有太大作用,主要是在BIOS中指示从中引导的正确磁盘。
2.1。 分区和磁盘清理
mdadm软件包用于标记磁盘,将其放入:
apt install --yes mdadm
我们看一下可用的光盘:
lsblk
并清洁它们:
sgdisk --zap-all /dev/{{ disk name }}
2.2。 磁盘布局
实际上,引导分区:
sgdisk -a1 -n1:34:2047 -t1:EF02 /dev/{{ disk name }}
主要部分。
这里可能会有变化:如果您需要分配额外的SSD磁盘分区(例如,用于ZFS Cache或Aerospike),则将主分区设为有限的卷:
sgdisk -n2:0:+100GB -t2:BF01 /dev/{{ disk name }} sgdisk -n3:0:0 -t2:BF01 /dev/{{ disk name }}
如果我们使用了所有空间,那么只需为剩余空间创建一个部分:
sgdisk -n2:0:0 -t2:BF01 /dev/{{ disk name }}
不要忘记检查结果:
lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 1.8T 0 disk ├─sda1 8:1 0 1007K 0 part └─sda2 8:2 0 1.8T 0 part sdb 8:16 0 1.8T 0 disk ├─sdb1 8:17 0 1007K 0 part └─sdb2 8:18 0 1.8T 0 part ...
2.3。 创建一个ZFS阵列
zpool create \ -o ashift=12 \ -O atime=off \ -O canmount=off \ -O compression=lz4 \ -O checksum=fletcher4 \ -O normalization=formD \ -m legacy \ -R /mnt \ -f \ tank \ mirror \ /dev/{{ disk a part 2}} \ /dev/{{ disk b part 2}}
我熟悉的管理员立即介入的第一个步骤是,在创建ZFS阵列时,如果不是专门为此创建磁盘,则需要指定磁盘而不是磁盘分区。
接下来,依次:
- ashift = 12-使用4K的块大小,原则上,我仍然不明白为什么在操作系统中实际上没有这样的磁盘时,默认的块大小通常为512字节;
- atime = off-禁止更新对文件的访问日期,我总是将其关闭,因为我从未真正需要此信息,并且不需要再次加载内核;
- canmount = off-禁用挂载根分区的功能;
- compression = lz4-使用LZ4算法启用数据压缩。 建议包含此参数,不仅可以节省磁盘空间,还可以减少I / O操作的数量。 同时,对于这种压缩算法,CPU利用率极低;
- checksum = fletcher4-默认的校验和算法,因此fletcher4值得再次检查;
- 标准化= formD-用于改进UTF-8的工作,实际上限制了使用非UTF-8文件名的可能性。 在这里,每个人都可以自己决定,在我们的工作中,我们始终仅使用UTF-8编码;
- xattr = sa-使用扩展属性加速工作。 由于不使用此选项,因此禁用了与其他OpenZFS实现的兼容性(例如:FreeBSD),因此我不使用该选项。 与Windows兼容,顺便说一下,我需要。 此外,可以在最后一节中启用此选项。
- -m legacy-挂载点到无处,无需挂载根分区;
- -R / mnt-用于安装内核的临时分区安装前缀;
- -f-强制创建数组。 如果ZFS阵列以前是在磁盘上收集的,那么create命令将无法工作,您永远不会知道,也许您犯了一个错误并且想要擦除重要数据;
我习惯性地将根系统磁盘阵列的名称表示为tank,尽管目前他们更喜欢在Linux环境中使用名称rpool(根池)。 在我的实践中,我通常使用以下数组命名:
- tank-主系统阵列;
- 存储-具有大磁盘的另一个阵列,用于存储数据;
- 缓存-主磁盘不在主分区上时,SSD磁盘的另一个阵列;
总的来说,我强烈建议立即开发一种命名方式,以免混淆。
3.系统安装
3.1。 和3.2。 创建一个根文件系统
我专门合并了第3.1款。 和3.2。 因为我认为在第三级指定根分区绝对是多余的。 没错,在使用ZFS的几年中,我从未需要对根分区进行任何操作。 此外,有些图片可用于控制点。 因此,我的根部分是tank / root:
zfs create -o mountpoint=/ tank/root
同时,在原始指令中检测到第一个致命错误,即磁盘阵列缺少启动分区:
zpool set bootfs=tank/root tank
3.3。 创建其他分区
在这部分基本说明中,您可以丢掉一切而忘记。 伙计们显然在压榨和选择上超过了它,因此,在此过程中,我不得不解决一些问题。 没错,没什么用。 由于后来又出现了问题,最终证明这一切都不起作用,因此在第4.11段中。 再次纠正。
为/ var / games分开一个单独的部分看起来很史诗。 我不介意,但这显然太多了。
仅在ZFS中创建分区并支持层次结构的事实并不意味着应该放弃经典目录。 一个简单的例子:服务器组上曾经有多个4K ZFS分区,这是必要的,但是由于安装了这些分区,服务器重启速度降低了几分钟。
让我们从一个干净的开始。
有静态和动态文件分区。
静态文件部分包括带有程序及其设置的部分,它们被填充一次,并且在操作期间不会更改。 同时,早期的静态分区被划分为系统分区和用户分区(/ usr),但目前它们混在Linux操作系统中,没有任何区分的余地,并且无法解决。
动态文件部分包括存储以下部分:
- 临时数据-eq.:tmp、swap;
- 工作日志-eq。:var / log;
- 用户数据-eq .: home;
- 数据-eq .: var / db以及如何幸运;
- 其他程序结果以文件形式出现;
在Linux家族中,动态分区包括/ tmp和/ var,但这并不准确,因为它们可以进入/ var / lib,程序和库,一般来说,所有内容都是混杂的,但是...
首先,您需要确定是在磁盘上还是在内存中将/ tmp分区创建为tmpfs。 如果我们在磁盘上创建,则为其创建一个单独的分区:
zfs create -o mountpoint=legacy tank/tmp
选项com.sun:自动快照=错误的setuid =很好,无论天气如何,都不会变得复杂。 但是,使用SWAP,我们将在后面的步骤7中进行操作。
分别将var部分分开:
zfs create -o mountpoint=legacy tank/var
和用户部分:
zfs create -o mountpoint=/home tank/home zfs create -o mountpoint=legacy tank/home/root
分配用户分区是很有意义的,因为实际上它们会定期被不同的工件阻塞,并且为了便于监视它们,最好为它们创建单独的分区以及根用户的主目录(尤其是对于那些以root身份工作的用户)。 在用户目录上使用配额不仅无助于阻塞磁盘空间,而且会造成干扰,因为在这种情况下,用户开始将工件留在任何地方,以后很难找到它们。 这没有得到处理,因此您只需要控制并击败双手。
mount point tank / home / root被列为旧版,而不是/ root。 这是正确的,因为本节的安装在第4.11节中进行
现在我们需要在/ mnt中临时挂载动态分区:
cd /mnt/ mkdir var tmp root mount -t zfs tank/var /mnt/var/ mount -t zfs tank/tmp /mnt/tmp/ mount -t zfs tank/home/root /mnt/root/
3.4安装内核
在主要指令中,还有另外两个不必要的命令,我们没有注意,显然是实验工件:
debootstrap bionic /mnt
结果,您应该获得如下信息:
zfs list NAME USED AVAIL REFER MOUNTPOINT tank 213M 1.76T 96K legacy tank/home 208K 1.76T 96K /mnt/home tank/home/root 112K 1.76T 112K legacy tank/root 147M 1.76T 147M /mnt tank/tmp 96K 1.76T 96K legacy tank/var 64.6M 1.76T 64.6M legacy
空的96K分区的大小分别只有tank / tmp保持为空,其余的则在内核安装过程中记录下来,这意味着分区已正确安装。
4.系统配置
4.1。 配置主机和主机名
echo HOSTNAME > /mnt/etc/hostname echo “127.0.0.1 localhost” > /mnt/etc/hosts echo “127.0.0.1 HOSTNAME” >> /mnt/etc/hosts
4.2。 配置网络接口
是的,我们已经在这里使用了netplan:
nano /mnt/etc/netplan/setup.yaml network: version: 2 renderer: networkd ethernets: eno2: dhcp4: no dhcp6: no addresses: [ {{ IP }}/{{ netmask }}, ] gateway4: {{ gateway IP }} nameservers: addresses: [8.8.8.8]
4.3。 配置apt存储库
nano /mnt/etc/apt/sources.list deb http://archive.ubuntu.com/ubuntu/ bionic main restricted universe deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted universe deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe
src-大多不需要
4.4。 我们将虚拟文件部分LiveCD装入并“转到”新系统
mount --rbind /dev /mnt/dev mount --rbind /proc /mnt/proc mount --rbind /sys /mnt/sys chroot /mnt /bin/bash --login
需要使用-rbind,但不使用-绑定
我们已经在新系统中...
4.5。 设置基础环境
ln -s /proc/self/mounts /etc/mtab chmod 1777 /tmp apt update
地区和时间:
dpkg-reconfigure locales * en_US.UTF-8 * ru_RU.UTF-8 dpkg-reconfigure tzdata
以及喜欢以下内容的其他编辑:
apt install --yes vim nano
4.6。 安装ZFS支持
apt install --yes --no-install-recommends linux-image-generic apt install --yes zfs-initramfs
4.8。 安装引导程序
如前所述,我使用的是过时的MBR:
apt install --yes grub-pc
在安装引导加载程序的过程中,需要选择我们确定为可引导的所有磁盘,而安装程序会在除第一个磁盘以外的所有其他磁盘上发誓,我们同意并执行第5步(尚不清楚为什么其余磁盘留待以后使用):
4.8.1。 (5.1)检查是否已识别根文件系统:
grub-probe / zfs
4.8.2。 (5.2)更新initrd
update-initramfs -u -k al
4.8.3。 (5.3)简化GRUB调试
vi /etc/default/grub ... GRUB_CMDLINE_LINUX_DEFAULT="" GRUB_CMDLINE_LINUX="console" ...
4.8.4。 (5.4。)更新引导程序配置
update-grub
4.8.5。 (5.5。)在标记为可引导的每个磁盘上安装引导加载程序
grub-install /dev/sda grub-install /dev/sdb ...
这些命令必须正常工作,这一点很重要。 老实说,我至少不会遇到相反的情况,所以我不知道该怎么做,但是最有可能的是,如果遇到错误,则标记磁盘时可能做错了什么(第2.2节)。
4.8.6。 (5.6。)检查是否已安装ZFS模块
ls /boot/grub/*/zfs.mod /boot/grub/i386-pc/zfs.mod
4.10。 设置根密码(很难!)
passwd
是的,我们将立即安装openssh,否则,如果我们进行远程工作,则重启后会感到惊讶:
apt install --yes openssh-server
不要忘记更正sshd配置:
vi /etc/ssh/sshd_config ... PermitRootLogin yes ... PasswordAuthentication yes ...
4.11。 修复挂载文件系统
在这里,我们得到了最有趣的东西。 事实是,ZFS分区是在某些守护程序启动后挂载的(我们还在/ etc / default / zfs中摇摆了ZFS_INITRD_ADDITIONAL_DATASETS),这反过来又在/ var中自行创建了一些结构,从而开始填充系统日志。 挂载ZFS分区的时间到了,事实证明挂载点不是空的,没有挂载,数据分散了,一切都不好了。 因此,您需要在/ etc / fstab中指定安装点,因为systemd在访问文件夹时主要关注它们:
vi /etc/fstab tank/var /var zfs noatime,nodev 0 0 tank/tmp /tmp zfs noatime,nodev 0 0 tank/home/root /root zfs noatime,nodev 0 0
其余的取决于第6条。 已经完成
6.第一次重启
6.1。 拍下根分区的照片
zfs snapshot tank/root@setup
他没有道理,在实践中我从未动摇过系统的根分区,也从未使用过该分区的快照,但是尽管如此,它可能会派上用场
6.2。 退出chroot
exit
6.3。 卸载LiveCD分区并导出ZFS阵列
cd mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {} umount /mnt/root umount /mnt/var umount /mnt/tmp zpool export tank
需要磁盘阵列导出以清除zfs缓存
6.4重启
重新启动最好在LiveCD终端中完成,因为如果通过ssh客户端进行工作,则通过它重新启动可能导致服务器“冻结”。
reboot
但是,如果出了什么问题并且服务器没有重新引导,则可以以任何方式重新引导,因为ZFS阵列已导出并且很难损坏它。
6.5。 我们正在等待重新启动并以root身份进入
6.6。 创建您的用户帐户
zfs create tank/home/{{ LOGIN }} useradd -u {{ UID }} -G adm,sudo -d /home/{{ LOGIN }}/ -s /bin/bash {{ LOGIN }} cp -a /etc/skel/.[!.]* /home/{{ LOGIN }} chown -R {{ LOGIN }}:{{ LOGIN }} /home/{{ LOGIN }}
将公共ssh密钥添加到用户并为其设置密码:
su - {{ LOGIN }} mkdir .ssh chmod 0700 .ssh vi .ssh/authorized_keys exit passwd {{ LOGIN }}
在OpenSSH中,我们删除了以root和密码身份验证登录的功能:
vi /etc/ssh/sshd_config ... PermitRootLogin no ... PubkeyAuthentication yes ... PasswordAuthentication no ... service ssh restart
6.7。 6.8。 不再需要
7.配置交换
7.1。 创建一个ZFS分区
zfs create \ -V 32G \ -b $(getconf PAGESIZE) \ -o compression=zle \ -o logbias=throughput \ -o sync=always \ -o primarycache=metadata \ -o secondarycache=none \ tank/swap
- -V 32G-我们SWAP的大小,您可以确定真正需要的那个;
- -b $(getconf PAGESIZE)-块大小(ashift = 12时为4K);
- 压缩= zle-选择在资源消耗方面最小的压缩算法,因为实际上块大小为4K,因此这样的压缩将不允许利用输入输出,但是有可能节省零块;
- logbias =吞吐量-设置带宽以优化同步操作;
- sync = always-始终同步记录。 这会稍微降低性能,但是会完全保证数据的可靠性。
- primarycache =元数据-仅缓存元数据,因为交换不会多次读取同一块数据;
- secondarycache = none-由于上述原因,完全禁用辅助缓存;
7.2。 设置交换分区
mkswap -f /dev/zvol/tank/swap echo /dev/zvol/tank/swap none swap defaults 0 0 >> /etc/fstab echo RESUME=none > /etc/initramfs-tools/conf.d/resume
7.3。 开启交换
swapon -av
进一步讲解并没有太多有趣的地方,因为它很大程度上取决于特定管理员的偏好以及整个服务器的任务,只有一点,即:“紧急启动”
并且不要忘记放防火墙
R.紧急启动
我们准备安装环境(项目1)。
在准备过程中,将导入ZFS阵列,因此您需要使用正确的安装点重新导入它:
zpool export -a zpool import -N -R /mnt tank zfs mount -a
, , , fstab, :
mount -t zfs tank/var /mnt/var/ mount -t zfs tank/tmp /mnt/tmp/ mount -t zfs tank/home/root /mnt/root/
, , chroot .4.4., . 6.3.
D.
3.3. . , : , /spool, /data. ZFS .
总结
- ZFS , , ;
- ZFS, , . ZFS — , ;
- .