主机引导加载程序

{pve} 当前根据安装程序中选择的磁盘设置使用两种引导程序之一。

对于安装了ZFS作为根文件系统的EFI系统,除非启用了安全启动,否则使用`systemd-boot`。所有其他部署使用标准的GRUB引导加载程序(这通常也适用于在Debian之上安装的系统)。

安装程序使用的分区方案

{pve} 安装程序在所有选定的安装磁盘上创建3个分区。

创建的分区是:

  • 一个1 MB的BIOS启动分区(gdisk类型EF02)

  • 一个512 MB EFI系统分区(ESP,gdisk类型EF00)

  • 一个跨越设置中 hdsize 参数或剩余空间的第三个分区 用于所选的存储类型

使用ZFS作为根文件系统的系统通过存储在512 MB EFI系统分区上的内核和initrd镜像启动。对于传统的BIOS系统以及启用安全启动的EFI系统,使用GRUB;对于未启用安全启动的EFI系统,则使用`systemd-boot`。这两者都安装并配置为指向ESPs。

在BIOS模式下(--target i386-pc),GRUB被安装到所有选定磁盘的BIOS启动分区上,适用于所有使用GRUB引导的系统。脚注:[这包括所有根目录安装在`ext4`或`xfs`上的安装,以及非EFI系统上根目录安装在ZFS上的安装]。

同步ESP的内容与`proxmox-boot-tool

proxmox-boot-tool` 是一个用于保持EFI系统分区内容正确配置和同步的实用工具。它将特定的内核版本复制到所有的ESP并配置相应的引导加载程序从`vfat`格式的ESP引导启动。在以ZFS作为根文件系统的上下文中,这意味着你可以在你的根池上使用所有可选功能,而不仅仅是那些同时存在于GRUB的ZFS实现中的子集,或者不得不创建一个单独的小型启动池[1]

在具有冗余设置的系统中,安装程序会对所有磁盘进行分区,并创建ESP。这确保了即使第一个启动设备失败或BIOS只能从特定磁盘启动,系统仍然能够启动。

ESP在常规操作期间不保持挂载状态。这有助于在系统崩溃的情况下防止对`vfat`格式的ESP文件系统造成损坏,并且在主启动设备故障的情况下,去除了手动调整`/etc/fstab`的需要。

proxmox-boot-tool` 处理以下任务:

  • 格式化和设置一个新的分区

  • 将新的内核映像和initrd映像复制并配置到所有列出的ESP中

  • 在内核升级和其他维护任务中同步配置

  • 管理与之同步的内核版本列表

  • 配置启动加载程序以启动特定的内核版本(固定)

你可以通过运行以下命令来查看当前配置的ESP及其状态:

# proxmox-boot-tool status
为同步ESP设置新分区

要格式化并初始化分区为同步的ESP,例如,在替换rpool中的失败vdev之后,或者在转换一个存在于同步机制之前的旧系统时,可以使用`proxmox-kernel-helper`中的`proxmox-boot-tool`。

Warning
format`命令将格式化`<partition>`,确保传入正确的设备/分区!

例如,要将空分区`/dev/sda2`格式化为ESP,请运行以下命令:

# proxmox-boot-tool format /dev/sda2

要将位于 /dev/sda2 上的现有未挂载ESP(EFI系统分区)设置为包含在{pve}的内核更新同步机制中,请使用以下方法:

# proxmox-boot-tool init /dev/sda2

或者

# proxmox-boot-tool init /dev/sda2 grub

为了支持Secure Boot,例如强制使用GRUB而不是`systemd-boot`进行初始化。

之后,/etc/kernel/proxmox-boot-uuids 应该包含一个新行,其中包含新添加分区的 UUID。init 命令也会自动触发所有已配置 ESP 的刷新。

更新所有ESP上的配置

要复制并配置所有可启动的内核,并保持`/etc/kernel/proxmox-boot-uuids`中列出的所有ESP同步,你只需运行:

# proxmox-boot-tool refresh

(相当于在根目录下具有`ext4`或`xfs`的系统上运行`update-grub`)。

如果您需要修改内核命令行或希望同步所有内核和initrds,这是必要的。

Note
update-initramfs` 和 apt(在必要时)会自动触发刷新。
proxmox-boot-tool`考虑的内核版本

以下内核版本是默认配置的:

  • 当前运行的内核

  • 在包更新时新安装的版本

  • 已经安装的两个最新内核

  • 如果适用,最新版本的倒数第二个内核系列(例如 5.0, 5.3)

  • 任何手动选择的核心

手动保持一个内核可引导

如果您希望将某个内核和initrd映像添加到可启动内核列表中,请使用`proxmox-boot-tool kernel add`。

例如,运行以下命令将带有ABI版本`5.0.15-1-pve`的内核添加到要保持安装并同步到所有ESP的内核列表中:

# proxmox-boot-tool kernel add 5.0.15-1-pve

proxmox-boot-tool kernel list``` 会列出当前选定用于启动的所有内核版本:

# proxmox-boot-tool kernel list
Manually selected kernels:
5.0.15-1-pve

自动选择的内核:
5.0.12-1-pve
4.15.18-18-pve

执行`proxmox-boot-tool kernel remove`以从手动选择的内核列表中移除一个内核,例如:

# proxmox-boot-tool kernel remove 5.0.15-1-pve
Note
在手动添加或删除内核后,需要运行 proxmox-boot-tool refresh 来更新所有 EFI 系统分区(ESP)。

确定使用了哪种引导加载程序

确定使用哪种引导程序的最简单也是最可靠的方法,是观察 {pve} 节点的启动过程。

你将会看到GRUB的蓝色盒子或者简单的白底黑字的`systemd-boot`。

从正在运行的系统中确定引导程序可能不会百分之百准确。最安全的方法是运行以下命令:

# efibootmgr -v

如果它返回一条消息说EFI变量不受支持,那么GRUB是在BIOS/Legacy模式下使用的。

如果输出包含一行看起来类似于以下内容,那么GRUB是在UEFI模式下使用的。

Boot0005* proxmox	[...] File(\EFI\proxmox\grubx64.efi)

如果输出包含一个类似于以下的行,那么使用的是`systemd-boot`。

Boot0006* Linux Boot Manager	[...] File(\EFI\systemd\systemd-bootx64.efi)

通过运行:

# proxmox-boot-tool status

你可以通过查看`proxmox-boot-tool`是否已配置来了解系统的启动方式,这是判断系统启动方式的一个好方法。

GRUB

GRUB多年来一直是启动Linux系统的事实标准,并且有相当完备的文档记录脚注:[GRUB手册 https://www.gnu.org/software/grub/manual/grub/grub.html]。

配置

对GRUB配置的更改是通过默认文件`/etc/default/grub`或在`/etc/default/grub.d`中的配置片段来完成的。在配置更改后重新生成配置文件,请运行:[2]

# update-grub

Systemd-boot

systemd-boot`是一个轻量级的EFI启动加载程序。它直接从安装它的EFI服务分区(ESP)读取内核和initrd镜像。直接从ESP加载内核的主要优点是它不需要重新实现访问存储的驱动程序。在{pve} proxmox-boot-tool中使用,用于保持ESP上的配置同步。

配置

systemd-boot`通过EFI系统分区(ESP)根目录下的文件`loader/loader.conf`进行配置。详细信息请参见`loader.conf(5)`手册页。

每个引导加载器条目都被放置在目录`loader/entries/`中的一个单独文件里。

一个示例的entry.conf看起来像这样(`/`指的是ESP的根目录):

title    Proxmox
version  5.0.15-1-pve
options   root=ZFS=rpool/ROOT/pve-1 boot=zfs
linux    /EFI/proxmox/5.0.15-1-pve/vmlinuz-5.0.15-1-pve
initrd   /EFI/proxmox/5.0.15-1-pve/initrd.img-5.0.15-1-pve

编辑内核命令行

你可以根据所使用的引导加载程序,在以下位置修改内核命令行:

GRUB

内核命令行需要被放置在文件`/etc/default/grub`中的变量`GRUB_CMDLINE_LINUX_DEFAULT`里。运行`update-grub`会将其内容附加到`/boot/grub/grub.cfg`中所有的`linux`条目上。

Systemd-boot

内核命令行需要作为一行放置在 /etc/kernel/cmdline 中。要应用你的更改,请运行 proxmox-boot-tool refresh,它会将其设置为 loader/entries/proxmox-*.conf 中所有配置文件的 option 行。

你可以通过检查网络界面('节点 → 概览'),或者运行以下命令来找到你的内核版本

# uname -r

使用输出前面的前两个数字。

为下一次启动覆盖内核版本

要选择一个当前不是默认内核的内核,你可以:

  • 使用在启动过程开始时显示的启动加载程序菜单

  • 使用`proxmox-boot-tool`来将系统固定在一个内核版本上,可以是一次性的,也可以是永久的(直到重置固定)。

这应该能帮助你解决新内核版本与硬件之间的不兼容问题。

Note
这样的固定应该尽快移除,以便系统也应用最新内核的所有当前安全补丁。

例如:要永久选择版本 5.15.30-1-pve 作为引导版本,你需要运行:

# proxmox-boot-tool kernel pin 5.15.30-1-pve
Tip
固定功能适用于所有{pve}系统,不仅仅是那些使用`proxmox-boot-tool`来同步ESP内容的系统。如果你的系统没有使用`proxmox-boot-tool`进行同步,你也可以跳过最后的`proxmox-boot-tool refresh`调用。

您也可以设置内核版本,使其仅在下一次系统启动时被引导。这在测试更新后的内核是否解决了导致您首次“固定”版本的问题时非常有用:

# proxmox-boot-tool kernel pin 5.15.30-1-pve --next-boot

要删除任何固定版本配置,请使用`unpin`子命令:

# proxmox-boot-tool kernel unpin

虽然`unpin`也有一个`--next-boot`选项,但它用于清除用`--next-boot`设置的固定版本。由于这已经在启动时自动发生,因此手动调用它的用处不大。

在设置或清除固定版本后,您还需要通过运行 refresh 子命令来同步ESP上的内容和配置。

Tip
如果您以交互方式调用该工具,将被提示自动为`proxmox-boot-tool`管理的系统执行操作。
# proxmox-boot-tool refresh

安全引导

自 {pve} 8.1 版本开始,通过签名包和在 proxmox-boot-tool 中的集成实现了对 Secure Boot 的支持。

要启用安全启动,需要安装以下软件包:

  • shim-signed`(由微软签名的shim引导加载程序)

  • shim-helpers-amd64-signed`(由Proxmox签名的后备引导程序和MOKManager)

  • grub-efi-amd64-signed`(由Proxmox签名的GRUB EFI引导程序)

  • proxmox-kernel-6.X.Y-Z-pve-signed`(由Proxmox签名的内核镜像)

只有GRUB作为启动引导程序是默认支持的,因为没有其他预签名的引导加载程序包可用。任何新的{pve}安装都将自动包含上述所有包。

关于Secure Boot的工作原理以及如何自定义设置的更多详情,请参见我们的wiki:https://pve.proxmox.com/wiki/Secure_Boot_Setup。

将现有安装切换到安全启动

Warning
如果操作不当,这在某些情况下可能导致安装无法启动。如果可用的话,重新安装宿主机会自动设置安全启动,无需任何额外操作。确保你有一个可用并且经过良好测试的{pve}宿主机备份!

如果需要,可以将现有的UEFI安装切换到Secure Boot模式,而无需从头开始重新安装{pve}。

首先,确保你的系统是最新的。接下来,安装上面列出的所有所需的预签名包。GRUB会自动创建所需的EFI启动项,用于通过默认的shim启动。

systemd-boot

如果使用`systemd-boot`作为引导加载程序(参见确定使用了哪个引导加载程序),则需要一些额外的设置。这只有在使用ZFS-on-root安装{pve}的情况下才会出现。

要检查后者,请运行:

# findmnt /

如果主机确实使用ZFS作为根文件系统,那么`FSTYPE`列应该包含`zfs`:

TARGET SOURCE           FSTYPE OPTIONS
/      rpool/ROOT/pve-1 zfs    rw,relatime,xattr,noacl,casesensitive

接下来,必须找到一个合适的潜在ESP(EFI系统分区)。这可以通过使用`lsblk`命令来完成,如下所示:

# lsblk -o +FSTYPE

输出应该看起来像这样:

NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS FSTYPE
sda      8:0    0   32G  0 disk
├─sda1   8:1    0 1007K  0 part
├─sda2   8:2    0  512M  0 part             vfat
└─sda3   8:3    0 31.5G  0 part             zfs_member
sdb      8:16   0   32G  0 disk
├─sdb1   8:17   0 1007K  0 part
├─sdb2   8:18   0  512M  0 part             vfat
└─sdb3   8:19   0 31.5G  0 part             zfs_member

在这种情况下,分区`sda2`和`sdb2`是目标。它们可以通过它们512M的大小以及它们的`FSTYPE`是`vfat`来识别,在这种情况下是在ZFS RAID-1安装上。

这些分区必须通过使用`proxmox-boot-tool`正确设置以通过GRUB引导。这个命令(以`sda2`为例)必须对每个单独的ESP分别运行:

# proxmox-boot-tool init /dev/sda2 grub

之后,您可以通过运行以下命令来进行环境的健全性检查:

# efibootmgr -v

这个列表中应该包含一个类似于此的条目:

[..]
Boot0009* proxmox       HD(2,GPT,..,0x800,0x100000)/File(\EFI\proxmox\shimx64.efi)
[..]
Note
旧的`systemd-boot`引导程序将被保留,但GRUB将被优先使用。这样,如果出于任何原因使用GRUB在安全启动模式下启动不成功,系统仍然可以通过关闭安全启动来使用`systemd-boot`启动。

现在可以重启主机,并在UEFI固件设置工具中启用Secure Boot。

重启后,UEFI固件启动菜单中应该可以选择一个名为`proxmox`的新条目,该条目通过预签名的EFI shim启动。

如果由于任何原因,在UEFI启动菜单中找不到`proxmox`条目,您可以尝试手动添加(如果固件支持),方法是添加文件`\EFI\proxmox\shimx64.efi`作为自定义启动项。

Note
一些UEFI固件已知会在重启时删除`proxmox`启动选项。如果`proxmox`启动项指向的是一个磁盘上的GRUB安装,而该磁盘本身不是一个启动选项,这种情况就可能发生。如果可能的话,尝试在UEFI固件设置工具中添加该磁盘作为启动选项,并再次运行`proxmox-boot-tool`。
Tip
要注册自定义密钥,请参阅随附的[安全启动wiki页面](https://pve.proxmox.com/wiki/Secure_Boot_Setup#Setup_instructions_for_db_key_variant)。

使用DKMS/第三方模块与安全启动

在启用了安全启动的系统上,内核将拒绝加载没有被可信密钥签名的模块。与内核包一同发行的默认模块集合是用嵌入在内核映像中的一次性密钥签名的,该密钥只被特定版本的内核映像所信任。

为了加载其他模块,例如那些通过DKMS构建或手动构建的模块,它们需要用安全启动堆栈信任的密钥进行签名。实现这一点最简单的方法是将它们作为机器所有者密钥(MOK)使用`mokutil`注册。

dkms`工具会自动在`/var/lib/dkms/mok.key`和`/var/lib/dkms/mok.pub`生成一对密钥和证书,并用它来签名它构建和安装的内核模块。

你可以查看证书的内容与此

# openssl x509 -in /var/lib/dkms/mok.pub -noout -text

并使用以下命令在您的系统上注册它:

# mokutil --import /var/lib/dkms/mok.pub
input password:
input password again:

mokutil`命令会要求输入一个(临时的)密码两次,这个密码需要在下一步骤中再输入一次!重启系统后,应该会自动启动进入`MOKManager` EFI二进制文件,这允许您验证密钥/证书,并使用在使用`mokutil`开始注册时选择的密码来确认注册。之后,内核应该允许加载使用DKMS构建的模块(这些模块已经使用注册的`MOK`签名)。如果需要,`MOK`也可以用来对自定义EFI二进制文件和内核映像进行签名。

同样的程序也可以用于不通过DKMS管理的自定义/第三方模块,但在这种情况下,密钥/证书的生成和签名步骤需要手动完成。


1. 使用GRUB在根上引导ZFS https://github.com/zfsonlinux/zfs/wiki/Debian-Stretch-Root-on-ZFS
2. 使用`proxmox-boot-tool`的系统会在`update-grub`时调用`proxmox-boot-tool refresh`。