最乏味、最可怕的系统管理任务之一是系统升级。
新内核可能无法启动系统,但这是最不需要担心的问题。
有时问题一开始并不明显,但一两周后,当倒退变得更加困难时,问题才会更严重。
无论采取什么预防措施或执行多少测试,任何升级都可能出错。
引导加载程序可以帮助你快速从坏内核中恢复。备份可能帮助你从不良用户环境中缓慢恢复。但这些都不能帮你准确理解问题所在并复制问题。
除非你用的是ZFS。
通过结合快照和克隆,可以创建操作系统内核和用户区的可引导备份。
先克隆操作系统数据集然后再升级,如果升级不顺利,可从克隆中启动系统。
使用zfs diff命令可以确定哪些文件发生了更改以及哪些文件出了问题,这可以恢复服务。
可以手动完成这些操作,但FreeBSD将此功能捆绑到引导环境中。使用引导环境管理工具,可以轻松创建、销毁和部署引导环境。
每次要升级时,都要创建一个新的启动环境。如果升级出现问题,无论是立即还是几周后,都可以恢复到旧的操作系统版本。
失败的版本仍然存在,因此可以将其部署到另一台机器上,以研究到底出了什么问题。
然而,要很好地使用引导环境,你需要了解你是如何安装FreeBSD的。
在FreeBSD10.1及以后版本上,基于ZFS的安装创建了专门为引导环境设计的数据集。
乍一看,这似乎有违直觉。看看默认安装上的一些数据集:
xxxxxxxxxx
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
…
zroot/var 703K 188G 128K /var
zroot/var/crash 128K 188G 128K /var/crash
zroot/var/log 192K 188G 192K /var/log
zroot/var/mail 128K 188G 128K /var/mail
zroot/var/tmp 128K 188G 128K /var/tmp
我们有/var/crash、/var/log、/var/mail、/var/tmp的某些子目录的数据集。
但/var下的所有其他目录呢?/var/db目录包含关键的系统信息,如包数据库。这至少跟/var/tmp一样重要吧?
默认安装不会根据目录中数据的重要性创建数据集。它创建数据集来分离数据。
现在检查zfs mount,看看这些数据集是如何挂载的:
xxxxxxxxxx
# zfs mount
zroot/ROOT/default /
…
zroot/var/crash /var/crash
zroot/var/log /var/log
zroot/var/mail /var/mail
zroot/var/tmp /var/tmp
请注意缺少的数据集:/var。该数据集存在,但未挂载(canmount属性设置为no)。
直接在/var中的文件实际上会以root身份挂载到数据集中,zroot/ROOT/default。
/var下有自己数据集的文件,如/var/log/messages,会放在一个单独的数据集中。在/var下但没有自己的数据集的文件,如/var/db,会进入根数据集。
数据的位置对引导环境至关重要。可能受引导环境影响的数据位于根数据集上。
在引导环境中管理的数据不应该有自己的数据集。
考虑/var/db。这包含关键信息,如数据库、定义数据库、freebsd-update记录等。所有这些都与操作系统版本紧密相关。
将主机升级到新的操作系统版本需要使用freebsd-update,这可能意味着在使用时更新附加软件。如果必须还原升级,也需要还原这些文件。
将其与/var/log进行比较。如果我们必须还原升级,可能不希望日志文件也回滚。日志涵盖的不仅仅是操作系统。同样,/var/mail中的主目录和其中包含的邮件卷轴(mail spool)最好不要随操作系统回滚。
FreeBSD升级会影响特定目录。核心程序隐藏在/bin、/sbin、/usr/bin和/usr/sbin中,库位于/lib和/usr/lib中。
得益于非挂载的/usr数据集,这些目录现在位于根数据集上。
软件包安装在/usr/local下,但它也是根数据集的一部分。同样,由于没有挂载/var,包含所有关键系统信息的/var/db目录实际上也是根数据集的一部分。
不属于核心系统的文件,如日志、用户主目录等,都有自己的数据集。
这将核心系统和官方包与主机的其他部分隔离开,让我们可以将它们作为一个实体进行管理。FreeBSD开发人员正在打包基础系统和附加包,这可能需要重新审视这里讨论的系统。
ZFS的快照和克隆功能允许保存、复制和拷贝文件系统。
使用ZFS,在执行系统维护(如升级)之前对数据集进行快照是一个好主意。如果升级或更改失败,可以回滚到最后一个已知的工作版本。
要调试失败的升级,可将快照复制到测试系统上并在那里进行调试,而生产机则可以继续在稍旧的操作系统版本上运行。
“引导环境”(boot environment)将维护前的快照打包成一个整洁的包,通常带有引导环境管理程序。
在系统管理中使用快照不需要启动环境管理器,但管理器使维护所有这些快照变得更加容易。
FreeBSD有一个引导环境管理器——beadm,特意设计成类似Solaris的beadm。
使用pkg安装beadm:
xxxxxxxxxx
# pkg install -y beadm
现在可以使用引导环境了。
每个引导环境是zroot/ROOT下面的一个数据集。使用beadm list查看所有引导环境:
xxxxxxxxxx
# beadm list
BE Active Mountpoint Space Created
default NR / 649.9M 2016-02-15 14:47
在现有安装或环境之后命名每个启动环境。如果正在创建引导环境以准备升级软件包,可附加当前日期或其他一些标识信息。使用freebsd-version检查当前运行的FreeBSD版本:
xxxxxxxxxx
# freebsd-version
10.3-RELEASE
使用beadm create命令创建引导环境。引导环境的名称不限制大小写字母。
xxxxxxxxxx
# beadm create 10.3-release
Created successfully
现在我们有两个相同的引导环境了:
xxxxxxxxxx
# beadm list
BE Active Mountpoint Space Created
default NR / 650.1M 2016-02-15 14:47
10.3-release - - 140.0K 2016-02-16 09:07
当前正在使用default启动环境,下次启动时也会启动相同的启动环境。
10.3-release的环境是可用的。随时可以告诉系统启动10.3-release版本的环境,并获得与创建环境时完全相同的系统。
10.3-release的环境和default环境非常相似。注意,它只占用了140KB空间。这是很明显的快照特征。
然后,我们运行freebsd-update,将环境更新到最新的补丁级别。default启动环境会获取补丁,而10.3-release的环境保持不变。
应用补丁会改变引导环境的磁盘使用情况:
xxxxxxxxxx
# beadm list
BE Active Mountpoint Space Created
default NR / 650.1M 2016-02-15 14:47
10.3-release - - 69.7M 2016-02-16 09:07
10.3-release引导环境使用了69.7MB空间。这是10.3-release引导环境和当前引导环境10.3-release-p3之间应用的补丁所使用的空间。
假设你应用了最新的补丁,机器就疯了。你的服务器软件出现故障,或者内核出现恐慌,或者小精灵从USB端口跳出来,开始偷你的勺子。
通过激活引导环境并重启来回退到早期版本。使用beadm activate命令激活开机环境:
xxxxxxxxxx
# beadm activate 10.3-release
Activated successfully
# beadm list
BE Active Mountpoint Space Created
default N / 308.1M 2015-06-19 10:04
10.3-release R - 457.1M 2015-06-19 14:13
默认启动环境的Active标志设置为N,这表示它现在正在运行。10.3-release的Active标志设置为R,这意味着重启系统后它将处于活动状态。
重新启动系统,回到10.3-release的启动环境,没有任何安全更新,也没有以前安装的任何软件包。
这种回退的风险比从备份还原低得多。
使用beadm rename命令可以重命名启动环境:
xxxxxxxxxx
# beadm rename install 10.3-release
Renamed successfully
以上命令将install引导环境重命名为10.3-release。
如果你创建了一大堆引导环境,将消耗掉越来越多的磁盘空间。其中一些引导环境可能永远都用不上。
xxxxxxxxxx
# beadm list
BE Active Mountpoint Space Created
default NR / 3.6G 2015-04-28 11:53
install - - 126.0M 2015-04-28 12:19
10.3-p9 - - 209.0M 2015-05-14 08:01
10.3-p10 - - 169.0M 2015-05-24 11:02
10.3-p10-10Jun - - 150.0M 2015-06-10 14:24
10.3-p10-13Jun - - 47.3M 2015-06-13 06:19
10.3-p12 - - 7.7M 2015-06-19 07:06
使用beadm destroy命令删除指定的引导环境:
xxxxxxxxxx
# beadm destroy 10.3-release
Are you sure you want to destroy '10.3-release'?
This action cannot be undone (y/[n]): y
Destroyed successfully
销毁某个引导环境会同时销毁它对应的数据集。
引导环境利用ZFS快照和克隆。以下是首次安装的主机上的快照:
xxxxxxxxxx
# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot/ROOT/default@2016-02-16-08:35:22 25.9M - 479M -
这台主机有一个快照,以创建的引导环境命名。
默认的引导环境是当前正在运行的环境,因此它不需要快照。
现在看看zroot/ROOT下面的数据集:
xxxxxxxxxx
# zfs list -r zroot/ROOT
NAME USED AVAIL REFER MOUNTPOINT
zroot/ROOT 765M 283G 96K none
zroot/ROOT/10.3-release 457M 283G 457M /
每个引导环境在zroot/ROOT下都有一个数据集,由源快照克隆而来。
默认的引导环境是zroot/ROOT/default,而10.3-release引导环境为zroot/ROOT/10.3-release。
虽然所有引导环境数据集的装载点属性都是/,但除了活动数据集外,每个引导环境数据集中的canmount都设置为off。
如果愿意,可以挂载这些数据集,但需要指定一个新的挂载点。
销毁引导环境会销毁关联的快照和克隆。
一种方法是检查创建引导环境的快照。引导环境可以在隐藏的.zfs目录中访问,这便于快速检查。
如果要以读写方式挂载这些引导环境,可使用beadm mount命令指定引导环境名称。引导环境将以读写方式挂载在/tmp下的某个位置:
xxxxxxxxxx
# beadm mount 10.3-p19
Mounted successfully on '/tmp/BE-10.3-p19.DmtRWZGf'
操作完成后,可使用beadm umount卸载它:
xxxxxxxxxx
# beadm umount 10.3-p19
Unmounted successfully.
可以使用canmount和mountpoint属性挂载和卸载引导环境快照。但是如果操作不正确,有可能在正在运行的引导环境之上挂载旧的引导环境。
虽然FreeBSD文件系统是可堆叠的,但更改正在运行的系统上的所有系统二进制文件可能会使人陷入困境。
更安全的方法是使用beadm内置的快照挂载和卸载功能。
如果彻底改变了操作系统,甚至可能无法进入单用户模式进行维护。
FreeBSD10.3以及其后版本允许在加载程序提示符处更改引导环境。这需要控制台访问权限。
启动主机,会得到一个类似如下情况的加载器菜单:
xxxxxxxxxx
+============Welcome to FreeBSD===========+
| |
| 1. Boot Multi User [Enter] |
| 2. Boot [S]ingle User |
| 3. [Esc]ape to loader prompt |
| 4. Reboot |
| |
| Options: |
| 5. [K]ernel: kernel (1 of 2) |
| 6. Configure Boot [O]ptions... |
| 7. Select Boot [E]nvironment... |
| |
| |
+=========================================+
选择第七项就会得到一个新的菜单:
xxxxxxxxxx
+============Welcome to FreeBSD===========+
| |
| 1. Active: |
| 2. bootfs: zfs:zroot/ROOT/default |
| 3. [P]age: 1 of 1 |
| |
| Boot Environments: |
| 4. 10.3-release |
| 5. default |
| |
+=========================================+
选择你喜欢的启动环境。
Mysql将数据存储在/var/db/mysql中,PostgreSQL则将其记录保留在/usr/local/pgsql中。
在使用引导环境时,这些可能会带来问题。
以MySQL为例,目录/var/db/mysql是跟数据集的一部分。它包含在引导环境中。如果将数据库数据存储在引导环境中,则回退引导环境也会将数据库还原到较早的版本。这可能不是我们想要的效果。
其他服务器软件也会有同样的问题。
处理这些问题并不难,但这要求你了解你的软件。这有两个选择:更改应用程序数据位置,或在旧应用程序目录中创建数据集。
移动应用程序数据需要为应用程序数据创建一个数据集,并告诉应用程序使用该位置。
本例中,我们决定将MySQL数据放在/var/mysql中。
xxxxxxxxxx
# zfs create zroot/var/mysql
然后必须告诉MySQL使用这个数据目录。检查/usr/local/etc/rc.d/mysql-server中的变量会知道,需要配置/etc/rc.conf中的mysql_dbdir选项:
xxxxxxxxxx
mysql_dbdir="/var/mysql"
必须将现有数据和配置文件从/var/db/mysql移动到/var/mysql中,然后重启服务器。
引导环境仅影响根文件系统数据集。如果要将应用程序数据保留在常规位置,则必须为该数据创建一个新的数据集。
以下以PostgreSQL为例。PostgreSQL将数据存储在/usr/local/pgsql中,所以我们要给它创建一个数据集:
xxxxxxxxxx
# zfs create zroot/usr/local/pgsql
cannot create 'zroot/usr/local/pgsql': parent does not exist
新系统默认安装时并没有创建/var/local数据集,所以不能创建/usr/local/pgsql数据集。
但是系统默认有一个/usr/local目录,它只是/usr数据集中的一个目录。所以,如果创建了一个标准的/usr/local数据集,要么将/usr/local中的文件从引导环境中拉出来,要么将一个空文件系统覆盖在已填充的/usr/local目录中。与/usr一样,解决方案是创建一个canmount属性设置为off的文件系统,然后创建子数据集:
xxxxxxxxxx
# zfs create -o canmount=off zroot/usr/local
# zfs create zroot/usr/local/pgsql
现在我们有了/usr/local/pgsql数据集,并可以安全运行PostreSQL,隔离于引导环境。
这两种解决方案都没有解决像Apache那样混乱的软件包。
Apache2.4在/usr/local/www和/usr/local/etc/apache24中保留了大量内容。系统管理员会编辑其中的一些文件,但不会是全部。这使得ZFS数据集的分离变得复杂。
对于Apache和类似的程序,建议创建一个全新的数据集,如/var/www,并将活动的网站文件放在那里。
标准的beadm引导环境管理器仅适用于单个根文件系统数据集。安装到GELI加密磁盘的FreeBSD与beadm不兼容。
在加密磁盘设备上安装默认的FreeBSD和ZFS需要一个小的、未加密的分区来存储引导内核。
默认安装程序为此创建池bootpool,并将/boot放在bootpool/boot中。
在运行中的系统上,/boot是另一个池的符号链接。系统的其余部分进入zroot池。
可以在加密磁盘上使用引导环境。只是没有得到引导环境管理器的便利。
在升级系统之前拍摄快照。克隆快照以创建旧环境。为每个引导环境保留一份内核副本。使用zroot池的bootfs属性更改FreeBSD用作根文件系统的环境。
然而,启动内核需要一个完全不同的过程。在修复内核之前,必须创建一个以启动环境命名的内核版本。在从10.3-RELEASE升级到10.3-p5之前,需要将10.3-RELEASE内核从/boot/kernel复制到/boot/kernel.10.3R。如果必须还原引导环境,请在加载器菜单中选择旧内核。
PC-BSD10确实支持在GELI加密磁盘上使用引导环境,但它们使用GRUB引导加载程序和一些特殊的技巧。
FreeBSD11.0预计将支持从GELI加密的ZFS引导,而无需单独的引导池,从而允许引导环境与在未加密的磁盘上一样工作。
对于大多数FreeBSD用户来说,引导环境省去了很多麻烦。