以下章节将重点介绍常见虚拟化任务,并说明 Proxmox VE 在主机管理和运维方面的特定内容。

Pxvirt 基于 OpenEuler GNU/Linux,并通过额外仓库提供 Proxmox VE 相关软件包。这意味着可以使用完整的 OpenEuler 软件包体系,包括安全更新和错误修复。

Pxvirt提供基于 OpenEuler kernel 的自有 Linux kernel,并启用了所有必要的虚拟化和容器功能, 同时包含 ZFS 以及若干额外硬件驱动。

对于以下章节未涵盖的其他主题,请参考 OpenEuler 文档。在线版

软件包仓库

Proxmox VE 基于 openEuler,使用 RPM 软件包格式,并通过 dnf 管理软件包和仓库。

Proxmox VE 每天自动检查软件包更新。root@pam 用户会通过电子邮件收到可用更新通知。 在 GUI 中,可以使用 Changelog 按钮查看所选更新的更多详细信息。

Proxmox VE 中的软件仓库

仓库是一组软件包集合,可用于安装新软件,也是获取安全更新、错误修复和新功能的重要来源。

Note 需要配置有效的 openEuler 基础仓库和 PXVIRT 仓库,才能获得完整的软件包依赖和更新。

DNF 仓库定义在 /etc/yum.repos.d/ 目录下的 .repo 文件中。每个仓库通常包含 baseurlenabledgpgcheckgpgkey 等字段。

仓库管理

screenshot/gui-node-repositories.png

在 Web 界面中,可以通过节点的更新相关面板查看当前仓库状态和可用更新。 也可以使用命令行工具 dnf 管理仓库和执行系统更新。

PXVIRT 仓库

PXVIRT 软件包通过梨儿方 PXVIRT 仓库发布。请在每个 Proxmox VE 节点上创建 /etc/yum.repos.d/pxvirt.repo

文件 /etc/yum.repos.d/pxvirt.repo
[pxvirt]
name=Lierfang PxVirt Repo
baseurl=https://mirrors.lierfang.com/pxcloud/pxvirt/repo/openeuler/24.03/$basearch
enabled=1
gpgcheck=1
gpgkey=https://mirrors.lierfang.com/pxcloud/lierfang.gpg

也可以使用编辑器创建该文件:

# editor /etc/yum.repos.d/pxvirt.repo
[pxvirt]
name=Lierfang PxVirt Repo
baseurl=https://mirrors.lierfang.com/pxcloud/pxvirt/repo/openeuler/24.03/$basearch
enabled=1
gpgcheck=1
gpgkey=https://mirrors.lierfang.com/pxcloud/lierfang.gpg

配置完成后,刷新软件包元数据:

# chmod 0600 /etc/yum.repos.d/pxvirt.repo
# dnf makecache

如果需要确认仓库是否已经启用,可以运行:

# dnf repolist

Ceph 软件包仓库

PXVIRT 的 openEuler 版本不使用 Proxmox 的独立 Ceph 仓库。 不要沿用 Proxmox 文档中的 enterpriseno-subscriptiontest Ceph 仓库地址。

如需安装或更新 Ceph 相关软件包,请使用已配置的 openEuler 基础仓库和 PXVIRT 仓库。 如果使用外部 Ceph 集群,只需要按存储章节配置客户端连接信息。

软件包签名验证

PXVIRT 仓库启用了 gpgcheck=1,DNF 会使用 gpgkey 指定的 GPG 公钥验证软件包签名。 如果密钥尚未导入,首次安装或更新软件包时,DNF 会提示导入该密钥。

也可以手动导入仓库密钥:

# rpm --import https://mirrors.lierfang.com/pxcloud/lierfang.gpg

ßß ==== 常用命令示例 ß 以下命令可用于刷新软件包索引、查看可升级软件包,并检查 Proxmox VE 软件包版本:

# dnf makecache
# dnf check-update
# pveversion -v

安装所有可用更新:

# dnf update

系统软件更新

Proxmox 会定期为所有软件仓库提供更新。要安装更新,可以使用基于 Web 的 GUI,或使用以下 CLI 命令:

# dnf makecache
# dnf update
Note DNF 包管理系统非常灵活,并提供许多功能;更多信息请参见 man dnf
Tip 定期更新对于获取最新补丁和安全相关修复至关重要。重大系统升级会在 Pxvirt Community Forum 中公告。

固件更新

在裸金属服务器上运行 Proxmox VE 时,应应用本章所述的固件更新。是否适合在客户机内部配置固件更新 (例如使用设备直通时)高度依赖具体部署,因此不在本章讨论范围内。

除了常规软件更新,固件更新对于可靠、安全的运行同样重要。

在获取并应用固件更新时,建议结合使用可用的多种方法,以便尽早获得更新,或确保能够获得更新。

从术语上看,firmware 通常分为微码(用于 CPU)和固件(用于其他设备)。

持久化固件

本节适用于所有设备。更新后的微码通常包含在 BIOS/UEFI 更新中,并存储在主板上; 其他固件则存储在相应设备上。这种持久化方式对 CPU 尤其重要,因为它允许在启动时尽早按常规流程加载更新后的微码。

Caution 某些更新(例如 BIOS/UEFI 或存储控制器更新)可能会重置设备配置。请仔细遵循厂商说明,并备份当前配置。

请向厂商确认可用的更新方法。

  • 服务器的便捷更新方法可能包括 Dell 的 Lifecycle Manager 或 HPE 的 Service Packs。

  • 有时也可以使用 Linux 实用工具。例如,NVIDIA ConnectX 可使用 mlxup,Broadcom 网卡可使用 bnxtnvm/niccli

  • 如果正在使用的 硬件厂商LVFS 合作,并且硬件属于 受支持硬件,那么 LVFS 也是一种选择。 其技术要求是系统制造于 2014 年之后,并通过 UEFI 启动。

在 openEuler 中,可以通过 fwupd 软件包使用 LVFS 提供的固件更新。 如果系统未能自动识别 EFI 分区位置,可以在 /etc/fwupd/daemon.conf 中显式配置正确的挂载点,例如:

文件 /etc/fwupd/daemon.conf
# Override the location used for the EFI system partition (ESP) path.
EspLocation=/boot/efi
Tip 如果更新说明要求重启主机,请确保可以安全执行。另请参见 节点维护

运行时固件文件

此方法将固件存储在 Proxmox VE 操作系统中;如果设备的 持久化固件版本较旧,则会将该固件传递给设备。 该方法受网络卡、显卡等设备支持,但不适用于依赖持久化固件的设备,例如主板和硬盘。

在 Proxmox VE 中,常见硬件所需的运行时固件由 openEuler 的 linux-firmware 软件包提供。因此,通过常规的 系统更新, 常见硬件所包含的固件会自动保持最新。

如需额外固件,请确认已经启用相应的 openEuler 软件源。

如果尝试安装额外固件软件包但发生冲突,DNF 将中止安装。特定固件也许可以通过其他方式获取。

CPU 微码更新

微码更新用于修复已发现的安全漏洞和其他严重 CPU 缺陷。虽然 CPU 性能可能受到影响, 但已打补丁的微码通常仍然比由内核自行执行缓解措施的未打补丁微码具有更好的性能。 根据 CPU 类型不同,如果不有意让 CPU 运行在不安全状态,可能无法再达到存在缺陷的出厂状态下的性能结果。

要查看当前 CPU 漏洞及其缓解措施概览,请运行 lscpu。只有当 Proxmox VE 主机 保持最新、版本尚未 结束生命周期,并且自上次内核更新以来至少重启过一次时, 当前真实世界中已知的漏洞才会显示出来。

除了推荐通过 持久化 BIOS/UEFI 更新来更新微码之外, 还可以使用一种独立方式:早期 OS 微码更新。这种方式使用方便, 在主板厂商不再提供 BIOS/UEFI 更新时也很有帮助。无论使用哪种方法,应用微码更新都始终需要重启。

设置早期 OS 微码更新

要设置由 Linux 内核在启动早期应用的微码更新,需要:

  1. 确认已经启用相应的 openEuler 软件源

  2. 获取最新可用软件包:dnf makecache(也可以使用 Web 界面中的 Node → Updates)

  3. 安装 CPU 微码软件包:dnf install microcode_ctl

  4. 重启 Proxmox VE 主机

之后的任何微码更新也都需要重启后才能加载。

微码版本

要获取当前正在运行的微码修订版以便比较或调试:

# grep microcode /proc/cpuinfo | uniq
microcode       : 0xf0

一个微码软件包包含许多不同 CPU 的更新。但专门适用于你的 CPU 的更新可能并不频繁。 因此,仅查看软件包日期并不能说明厂商何时实际为你的特定 CPU 发布了更新。

如果已安装新的微码软件包并重启 Proxmox VE 主机,且这个新微码同时比 CPU 内置版本和主板固件提供的版本更新, 系统日志中会出现 "microcode updated early" 消息。

# dmesg | grep microcode
[    0.000000] microcode: microcode updated early to revision 0xf0, date = 2021-11-12
[    0.896580] microcode: Microcode Update Driver: v2.2.

故障排查

出于调试目的,可以按如下方式临时禁用系统启动时常规应用的早期 OS 微码更新:

  1. 确保主机可以 安全重启

  2. 重启主机以进入 GRUB 菜单(如果菜单隐藏,请按住 SHIFT

  3. 在所需的 Proxmox VE 启动项上按 E

  4. 转到以 linux 开头的行,并以空格分隔追加 dis_ucode_ldr

  5. CTRL-X,本次启动将不使用早期 OS 微码更新

如果怀疑问题与最近的微码更新有关,应考虑软件包降级,而不是移除软件包 (dnf remove microcode_ctl)。否则,可能会加载过旧的 持久化微码,即使较新的微码本可以正常运行。

如果 openEuler 软件源中存在较早版本的微码软件包,则可以降级,如以下示例所示:

# dnf --showduplicates list microcode_ctl
Installed Packages
microcode_ctl.x86_64 4:2.1-53.oe2203sp4 @OS
Available Packages
microcode_ctl.x86_64 4:2.1-51.oe2203sp4 OS
# dnf downgrade microcode_ctl
...
Downgrading:
 microcode_ctl x86_64 4:2.1-51.oe2203sp4 OS
...
Complete!
...

再次确认主机可以 安全重启。要应用该微码软件包中可能包含的、 适用于你 CPU 类型的较旧微码,请立即重启。

Tip

将降级后的软件包保持一段时间,然后稍后再尝试更新版本,是合理的做法。即使未来软件包版本相同, 期间的系统更新也可能已经修复曾遇到的问题。

# dnf versionlock add microcode_ctl
# dnf versionlock delete microcode_ctl
# dnf makecache
# dnf update

常用命令示例

查看 CPU 漏洞和缓解状态概览:

# lscpu

查看当前正在运行的微码修订版:

# grep microcode /proc/cpuinfo | uniq

网络配置

Proxmox VE 使用 Linux 网络栈。这使 Proxmox VE 节点上的网络设置具备很高的灵活性。可以通过 GUI 完成配置,也可以手动编辑包含完整网络配置的 /etc/network/interfaces 文件。interfaces(5) 手册页包含完整的格式说明。所有 Proxmox VE 工具都会尽量保留用户的直接修改,但仍然更建议使用 GUI,因为它可以帮助避免错误。

需要使用 Linux bridge 接口(通常称为 vmbrX)将客户机连接到底层物理网络。可以将其理解为一个虚拟交换机,客户机和物理接口都连接到该交换机。本节提供一些网络设置示例,以适配不同使用场景,例如通过 bond 实现冗余、使用 vlans,或采用 routedNAT 配置。

Software Defined Network 可用于 Proxmox VE 集群中更复杂的虚拟网络。

Warning 如果不确定其影响,不建议使用传统 Debian 工具 ifupifdown,因为它们存在一些容易踩到的问题。例如执行 ifdown vmbrX 会中断所有客户机流量,但之后对同一 bridge 执行 ifup 时不会重新连接这些客户机。

应用网络更改

Proxmox VE 不会将更改直接写入 /etc/network/interfaces。相反,系统会写入名为 /etc/network/interfaces.new 的临时文件,这样可以一次完成多项相关更改。这也允许在应用前确认更改是否正确,因为错误的网络配置可能导致节点无法访问。

使用 ifupdown2 实时重新加载网络

使用推荐的 ifupdown2 软件包(自 Proxmox VE 7.0 起为新安装的默认选择),可以在不重启的情况下应用网络配置更改。如果通过 GUI 修改网络配置,可以点击 Apply Configuration 按钮。该操作会将更改从暂存的 interfaces.new 文件移动到 /etc/network/interfaces,并实时应用。

如果直接手动修改了 /etc/network/interfaces 文件,可以运行 ifreload -a 来应用这些更改。

常用命令示例

查看当前网络接口配置:

ip address show

在使用 ifupdown2 的系统上实时重新加载网络配置:

ifreload -a

重启节点以应用

应用新网络配置的另一种方式是重启节点。在这种情况下,systemd 服务 pvenetcommit 会在 networking 服务应用配置前,先激活暂存的 interfaces.new 文件。

命名约定

当前设备名称使用以下命名约定:

  • Ethernet 设备:en*,即 systemd 网络接口名称。自 5.0 版本起,新的 Proxmox VE 安装使用此命名方案。

  • Ethernet 设备:eth[N],其中 0 ≤ N(eth0eth1 等)。该命名方案用于 5.0 发布前安装的 Proxmox VE 主机。升级到 5.0 时,名称会保持不变。

  • Bridge 名称:通常为 vmbr[N],其中 0 ≤ N ≤ 4094(vmbr0 - vmbr4094),但也可以使用任意以字符开头、最长 10 个字符的字母数字字符串。

  • Bonds:bond[N],其中 0 ≤ N(bond0bond1 等)。

  • VLAN:直接在设备名称后追加 VLAN 编号,并用句点分隔(eno1.50bond1.30)。

这样更容易调试网络问题,因为设备名称能够体现设备类型。

Systemd 网络接口名称

Systemd 为网络设备名称定义了带版本的命名方案。该方案对 Ethernet 网络设备使用两个字符的前缀 en。后续字符取决于设备驱动、设备位置和其他属性。可能的模式包括:

  • o<index>[n<phys_port_name>|d<dev_port>] — 板载设备

  • s<slot>[f<function>][n<phys_port_name>|d<dev_port>] — 按热插拔 ID 标识的设备

  • [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>] — 按总线 ID 标识的设备

  • x<MAC> — 按 MAC 地址标识的设备

以下是最常见模式的一些示例:

  • eno1 — 第一块板载 NIC

  • enp3s0f1 — PCI 总线 3、插槽 0 上 NIC 的功能 1

有关所有可能设备名称模式的完整列表,请参见 systemd.net-naming-scheme(7) 手册页

新版本的 systemd 可能会定义新版网络设备命名方案,并默认使用该方案。因此,更新到较新的 systemd 版本时,例如进行 Proxmox VE 大版本升级期间,网络设备名称可能发生变化,并需要调整网络配置。为避免因命名方案新版本导致名称变化,可以手动固定特定命名方案版本(见 下文)。

但是,即使命名方案版本已固定,网络设备名称仍可能因内核或驱动更新而变化。要彻底避免特定网络设备名称变化,可以使用 link 文件手动覆盖其名称(见 下文)。

有关网络接口名称的更多信息,请参见 Predictable Network Interface Names

固定特定命名方案版本

可以通过向 内核命令行 添加 net.naming-scheme=<version> 参数,固定网络设备命名方案的特定版本。有关命名方案版本列表,请参见 systemd.net-naming-scheme(7) 手册页

例如,要固定版本 v252(这是全新安装 Proxmox VE 8.0 时使用的最新命名方案版本),请添加以下内核命令行参数:

net.naming-scheme=v252

另请参见 本节,了解如何编辑内核命令行。需要重启后更改才会生效。

覆盖网络设备名称

使用 pve-network-interface-pinning 工具

Proxmox VE 提供了一个工具,可自动生成用于覆盖网络设备名称的 .link 文件。它还会自动替换以下文件中出现的旧接口名称:

  • /etc/network/interfaces

  • /etc/pve/nodes/<nodename>/host.fw

  • /etc/pve/sdn/controllers.cfg

Note 由于生成的映射只属于生成它的本地节点,Firewall Datacenter 配置(/etc/pve/firewall/cluster.fw)中包含的接口名称不会自动更新。

生成的 link 文件存放在 /usr/local/lib/systemd/network 中。对于配置文件,会在相同位置生成带 .new 后缀的新文件。这样可以使用 diff(或你选择的其他 diff 查看器)检查对配置所做的更改:

diff -y /etc/network/interfaces /etc/network/interfaces.new

如果发现任何有问题的更改,或希望在重启前撤销 pinning 工具所做的更改,只需删除所有 .new 文件以及 /usr/local/lib/systemd/network 中对应的 link 文件。

以下命令会为尚未拥有 .link 文件的所有物理网络接口生成 .link 文件,并更新选定的 Proxmox VE 配置文件(见上文)。生成的名称将使用默认前缀 nic,因此得到的接口名称会是 nic1nic2 等。

pve-network-interface-pinning generate

可以使用 --prefix 标志覆盖默认前缀:

pve-network-interface-pinning generate --prefix myprefix

也可以只固定特定接口:

pve-network-interface-pinning generate --interface enp1s0

固定特定接口时,可以指定该接口应固定为的精确名称:

pve-network-interface-pinning generate --interface enp1s0 --target-name if42

要将 pve-network-interface-pinning 所做更改应用到网络配置,需要重启节点。

手动方法

可以使用自定义 systemd.link 文件为特定网络设备手动分配名称。这会覆盖按最新网络设备命名方案原本会分配的名称。通过这种方式,可以避免因内核更新、驱动更新或命名方案新版本导致名称变化。

自定义 link 文件应放在 /etc/systemd/network/ 中,并命名为 <n>-<id>.link,其中 n 是小于 99 的优先级,id 是某个标识符。link 文件包含两个小节:[Match] 决定该文件应用到哪些接口;[Link] 决定这些接口应如何配置,包括其命名。

要为特定网络设备分配名称,需要在 [Match] 小节中以唯一且持久的方式标识该设备。一种做法是使用 MACAddress 选项匹配设备的 MAC 地址,因为它通常不会变化。

[Match] 小节还应包含 Type 选项,以确保只匹配预期的物理接口,而不是具有相同 MAC 地址的 bridge/bond/VLAN 接口。在大多数配置中,Type 应设置为 ether,以便只匹配 Ethernet 设备,但某些配置可能需要其他选择。更多细节请参见 systemd.link(5) 手册页

然后,可以在 [Link] 小节中使用 Name 选项分配名称。

link 文件会被复制到 initramfs,因此建议在添加、修改或移除 link 文件后刷新 initramfs

# update-initramfs -u -k all

例如,要将名称 enwan0 分配给 MAC 地址为 aa:bb:cc:dd:ee:ff 的 Ethernet 设备,请创建文件 /etc/systemd/network/10-enwan0.link,内容如下:

[Match]
MACAddress=aa:bb:cc:dd:ee:ff
Type=ether

[Link]
Name=enwan0

不要忘记调整 /etc/network/interfaces 以使用新名称,并按上文所述刷新 initramfs。需要重启节点后更改才会生效。

Note 建议分配以 eneth 开头的名称,使 Proxmox VE 能够将该接口识别为物理网络设备,并通过 GUI 进行配置。同时,应确保该名称未来不会与其他接口名称冲突。一种做法是分配一个不匹配 systemd 网络接口任何命名模式的名称(见上文),例如上例中的 enwan0

有关 link 文件的更多信息,请参见 systemd.link(5) 手册页

选择网络配置

可以根据当前网络组织方式和可用资源,选择 bridged、routed 或 masquerading 网络配置。

位于私有 LAN 中、通过外部网关访问互联网的 Proxmox VE 服务器

在这种情况下,Bridged 模型最合适,这也是新安装 Proxmox VE 的默认模式。每个客户机系统都会有一个虚拟接口连接到 Proxmox VE bridge。其效果类似于将客户机网卡直接连接到 LAN 中的一台新交换机,而 Proxmox VE 主机承担该交换机的角色。

位于托管服务提供商处、为客户机提供公网 IP 段的 Proxmox VE 服务器

对于这种配置,可以根据提供商允许的方式使用 BridgedRouted 模型。

位于托管服务提供商处、只有单个公网 IP 地址的 Proxmox VE 服务器

在这种情况下,要让客户机系统访问外部网络,唯一方式是使用 Masquerading。如果需要外部访问客户机,则需要配置 Port Forwarding

为了获得更高灵活性,可以配置 VLAN(IEEE 802.1q)和网络 bonding,也称为 "link aggregation"。这样可以构建复杂且灵活的虚拟网络。

使用 Bridge 的默认配置

default-network-setup-bridge.svg

Bridge 类似于用软件实现的物理网络交换机。所有虚拟客户机可以共享一个 bridge,也可以创建多个 bridge 来隔离网络域。每台主机最多可以拥有 4094 个 bridge。

安装程序会创建一个名为 vmbr0 的 bridge,并将其连接到第一块 Ethernet 网卡。/etc/network/interfaces 中的对应配置可能如下:

auto lo
iface lo inet loopback

iface eno1 inet manual

auto vmbr0
iface vmbr0 inet static
        address 192.168.10.2/24
        gateway 192.168.10.1
        bridge-ports eno1
        bridge-stp off
        bridge-fd 0

虚拟机的行为就像直接连接到物理网络一样。反过来,网络会将每台虚拟机视为拥有自己的 MAC,即使所有这些虚拟机实际只通过一根网络线缆连接到网络。

路由配置

大多数托管服务提供商不支持上述配置。出于安全原因,一旦检测到单个接口上存在多个 MAC 地址,它们就会禁用网络。

Tip 某些提供商允许通过其管理界面注册额外 MAC。这可以避免该问题,但配置起来可能比较繁琐,因为需要为每台虚拟机注册一个 MAC。

可以通过将所有流量经由单个接口“路由”来避免该问题。这可以确保所有网络数据包都使用同一个 MAC 地址。

default-network-setup-routed.svg

常见场景是拥有一个公网 IP(本例假设为 198.51.100.5),并为虚拟机拥有一个额外 IP 段(203.0.113.16/28)。对于此类情况,建议使用以下配置:

auto lo
iface lo inet loopback

auto eno0
iface eno0 inet static
        address  198.51.100.5/29
        gateway  198.51.100.1
        post-up echo 1 > /proc/sys/net/ipv4/ip_forward
        post-up echo 1 > /proc/sys/net/ipv4/conf/eno0/proxy_arp


auto vmbr0
iface vmbr0 inet static
        address  203.0.113.17/28
        bridge-ports none
        bridge-stp off
        bridge-fd 0

使用 iptables 的 Masquerading(NAT)

Masquerading 允许只有私有 IP 地址的客户机通过主机 IP 地址作为出站流量来源来访问网络。每个出站数据包都会由 iptables 重写,使其看起来像是源自主机;响应也会相应重写,以便路由回原始发送方。

auto lo
iface lo inet loopback

auto eno1
#real IP address
iface eno1 inet static
        address  198.51.100.5/24
        gateway  198.51.100.1

auto vmbr0
#private sub network
iface vmbr0 inet static
        address  10.10.10.1/24
        bridge-ports none
        bridge-stp off
        bridge-fd 0

        post-up   echo 1 > /proc/sys/net/ipv4/ip_forward
        post-up   iptables -t nat -A POSTROUTING -s '10.10.10.0/24' -o eno1 -j MASQUERADE
        post-down iptables -t nat -D POSTROUTING -s '10.10.10.0/24' -o eno1 -j MASQUERADE
Note 在某些启用了防火墙的 masquerade 配置中,出站连接可能需要 conntrack zones。否则防火墙可能阻止出站连接,因为它们会优先匹配虚拟机 bridge 的 POSTROUTING,而不是 MASQUERADE

/etc/network/interfaces 中添加以下行可以修复此问题:

post-up   iptables -t raw -I PREROUTING -i fwbr+ -j CT --zone 1
post-down iptables -t raw -D PREROUTING -i fwbr+ -j CT --zone 1

有关此问题的更多信息,请参考以下链接:

Linux Bond

Bonding(也称为 NIC teaming 或 Link Aggregation)是一种将多个 NIC 绑定为单个网络设备的技术。它可以实现不同目标,例如提升网络容错能力、提高性能,或同时实现二者。

Fibre Channel 等高速硬件及其配套交换硬件可能非常昂贵。通过链路聚合,两块 NIC 可以呈现为一个逻辑接口,从而获得双倍速度。这是 Linux 内核原生功能,并受大多数交换机支持。如果节点有多个 Ethernet 端口,可以将网络线缆连接到不同交换机,以分散故障点;当网络出现问题时,bonded 连接会故障转移到其中一条线缆。

聚合链路可以降低在线迁移延迟,并提高 Proxmox VE 集群节点之间的数据复制速度。

Bonding 有 7 种模式:

  • Round-robin (balance-rr): 按顺序从第一个可用的从属网络接口(NIC)到最后一个接口传输网络数据包。该模式提供负载均衡和容错能力。

  • Active-backup (active-backup): bond 中只有一个从属 NIC 处于活动状态。仅当活动从属接口失败时,另一个从属接口才会变为活动状态。单个逻辑 bonded 接口的 MAC 地址在外部只会出现在一个 NIC(端口)上,以避免网络交换机产生混乱。该模式提供容错能力。

  • XOR (balance-xor): 根据 [(源 MAC 地址 XOR 目标 MAC 地址) modulo 从属 NIC 数量] 传输网络数据包。该模式会为每个目标 MAC 地址选择相同的从属 NIC,提供负载均衡和容错能力。

  • Broadcast (broadcast): 在所有从属网络接口上传输网络数据包。该模式提供容错能力。

  • IEEE 802.3ad Dynamic link aggregation (802.3ad)(LACP): 创建共享相同速率和双工设置的聚合组。根据 802.3ad 规范使用活动聚合组中的所有从属网络接口。

  • Adaptive transmit load balancing (balance-tlb): Linux bonding 驱动模式,不需要网络交换机提供任何特殊支持。出站网络数据包流量会按照每个从属网络接口当前负载(相对于速率计算)进行分配。入站流量由当前指定的一个从属网络接口接收。如果该接收从属接口失败,另一个从属接口会接管故障接收从属接口的 MAC 地址。

  • Adaptive load balancing (balance-alb): 包含 balance-tlb,并为 IPV4 流量提供接收负载均衡(rlb),不需要网络交换机提供任何特殊支持。接收负载均衡通过 ARP 协商实现。bonding 驱动会拦截本地系统发出的 ARP Replies,并将源硬件地址重写为单个逻辑 bonded 接口中某个从属 NIC 的唯一硬件地址,使不同网络对端使用不同 MAC 地址发送其网络数据包流量。

如果交换机支持 LACP(IEEE 802.3ad)协议,建议使用对应的 bonding 模式(802.3ad)。否则,通常应使用 active-backup 模式。

对于集群网络(Corosync),建议配置多个网络。Corosync 不需要通过 bond 实现网络冗余,因为当某个网络不可用时,它可以自行在网络之间切换。

以下 bond 配置可用作分布式/共享存储网络。其优势是可以获得更高速度,并让网络具备容错能力。

示例:使用具有固定 IP 地址的 bond
auto lo
iface lo inet loopback

iface eno1 inet manual

iface eno2 inet manual

iface eno3 inet manual

auto bond0
iface bond0 inet static
      bond-slaves eno1 eno2
      address  192.168.1.2/24
      bond-miimon 100
      bond-mode 802.3ad
      bond-xmit-hash-policy layer2+3

auto vmbr0
iface vmbr0 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1
        bridge-ports eno3
        bridge-stp off
        bridge-fd 0
default-network-setup-bond.svg

另一种做法是直接将 bond 用作 bridge port。这可用于让客户机网络具备容错能力。

示例:将 bond 用作 bridge port
auto lo
iface lo inet loopback

iface eno1 inet manual

iface eno2 inet manual

auto bond0
iface bond0 inet manual
      bond-slaves eno1 eno2
      bond-miimon 100
      bond-mode 802.3ad
      bond-xmit-hash-policy layer2+3

auto vmbr0
iface vmbr0 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1
        bridge-ports bond0
        bridge-stp off
        bridge-fd 0

VLAN 802.1Q

虚拟 LAN(VLAN)是在网络二层进行划分和隔离的广播域。因此,可以在一个物理网络中拥有多个彼此独立的网络(4096 个)。

每个 VLAN 网络由一个通常称为 tag 的数字标识。随后网络数据包会被“打标签”,用于标识其所属的虚拟网络。

客户机网络中的 VLAN

Proxmox VE 原生支持此配置。创建虚拟机时可以指定 VLAN tag。VLAN tag 是客户机网络配置的一部分。根据 bridge 配置不同,网络层支持不同模式来实现 VLAN:

  • Linux bridge 上的 VLAN awareness: 在这种情况下,每个客户机的虚拟网卡都会分配一个 VLAN tag,并由 Linux bridge 透明支持。也可以使用 Trunk 模式,但这需要在客户机内进行配置。

  • Linux bridge 上的“传统” VLAN: 与 VLAN awareness 方法不同,此方法不是透明的,并会为每个 VLAN 创建一个 VLAN 设备及其关联 bridge。也就是说,例如在 VLAN 5 上创建客户机时,会创建 eno1.5 和 vmbr0v5 两个接口,并一直保留到发生重启。

  • Open vSwitch VLAN: 此模式使用 OVS VLAN 功能。

  • 客户机内配置的 VLAN: VLAN 在客户机内部分配。在这种情况下,配置完全在客户机内完成,无法从外部影响。其优势是可以在单个虚拟 NIC 上使用多个 VLAN。

主机上的 VLAN

为了允许主机与隔离网络通信,可以将 VLAN tag 应用到任意网络设备(NIC、Bond、Bridge)。一般来说,应在自身与物理 NIC 之间抽象层最少的接口上配置 VLAN。

例如,在默认配置中,如果希望将主机管理地址放在单独的 VLAN 上。

示例:使用传统 Linux bridge,将 VLAN 5 用于 Proxmox VE 管理 IP
auto lo
iface lo inet loopback

iface eno1 inet manual

iface eno1.5 inet manual

auto vmbr0v5
iface vmbr0v5 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1
        bridge-ports eno1.5
        bridge-stp off
        bridge-fd 0

auto vmbr0
iface vmbr0 inet manual
        bridge-ports eno1
        bridge-stp off
        bridge-fd 0
示例:使用 VLAN aware Linux bridge,将 VLAN 5 用于 Proxmox VE 管理 IP
auto lo
iface lo inet loopback

iface eno1 inet manual


auto vmbr0.5
iface vmbr0.5 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1

auto vmbr0
iface vmbr0 inet manual
        bridge-ports eno1
        bridge-stp off
        bridge-fd 0
        bridge-vlan-aware yes
        bridge-vids 2-4094

下一个示例使用相同配置,但通过 bond 使该网络具备故障保护能力。

示例:使用传统 Linux bridge,通过 bond0 上的 VLAN 5 配置 Proxmox VE 管理 IP
auto lo
iface lo inet loopback

iface eno1 inet manual

iface eno2 inet manual

auto bond0
iface bond0 inet manual
      bond-slaves eno1 eno2
      bond-miimon 100
      bond-mode 802.3ad
      bond-xmit-hash-policy layer2+3

iface bond0.5 inet manual

auto vmbr0v5
iface vmbr0v5 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1
        bridge-ports bond0.5
        bridge-stp off
        bridge-fd 0

auto vmbr0
iface vmbr0 inet manual
        bridge-ports bond0
        bridge-stp off
        bridge-fd 0

在节点上禁用 IPv6

无论是否部署 IPv6,Proxmox VE 都能在所有环境中正常工作。建议保留所有设置的默认值。

如果仍需在节点上禁用 IPv6 支持,请创建适当的 sysctl.conf (5) 片段文件,并设置正确的 sysctls, 例如添加内容如下的 /etc/sysctl.d/disable-ipv6.conf

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

相比在 内核命令行 中禁用 IPv6 模块加载,更推荐使用此方法。

在 Bridge 上禁用 MAC Learning

默认情况下,bridge 上会启用 MAC learning,以确保虚拟客户机及其网络获得平稳体验。

但在某些环境中,这可能并非期望行为。自 Proxmox VE 7.3 起,可以在 /etc/network/interfaces 中为 bridge 设置 bridge-disable-mac-learning 1 配置,从而禁用该 bridge 上的 MAC learning,例如:

# ...

auto vmbr0
iface vmbr0 inet static
        address  10.10.10.2/24
        gateway  10.10.10.1
        bridge-ports ens18
        bridge-stp off
        bridge-fd 0
        bridge-disable-mac-learning 1

启用后,Proxmox VE 会手动将虚拟机和容器中配置的 MAC 地址添加到 bridge 的 forwarding database,以确保客户机仍可使用网络,但前提是它们使用自身实际的 MAC 地址。

时间同步

Proxmox VE 集群栈本身高度依赖所有节点之间精确同步的时间。其他一些组件(如 Ceph) 也要求所有节点的本地时间保持同步,否则无法正常工作。

节点之间的时间同步可以通过“网络时间协议”(NTP)实现。从 Proxmox VE 7 开始, 默认 NTP 守护进程为 chrony,而 Proxmox VE 6 使用 systemd-timesyncd。 两者都预配置为使用一组公共服务器。

Important 如果将系统升级到 Proxmox VE 7,建议手动安装 chronyntpopenntpd 之一。

使用自定义 NTP 服务器

在某些情况下,可能需要使用非默认 NTP 服务器。例如,如果 Proxmox VE 节点由于受限的 防火墙规则无法访问公网,则需要设置本地 NTP 服务器,并指示 NTP 守护进程使用它们。

对于使用 chrony 的系统:

/etc/chrony/chrony.conf 中指定 chrony 应使用的服务器:

server ntp1.example.com iburst
server ntp2.example.com iburst
server ntp3.example.com iburst

重启 chrony

# systemctl restart chronyd

检查 journal,确认新配置的 NTP 服务器正在被使用:

# journalctl --since -1h -u chrony
...
Aug 26 13:00:09 node1 systemd[1]: Started chrony, an NTP client/server.
Aug 26 13:00:15 node1 chronyd[4873]: Selected source 10.0.0.1 (ntp1.example.com)
Aug 26 13:00:15 node1 chronyd[4873]: System clock TAI offset set to 37 seconds
...

对于使用 systemd-timesyncd 的系统:

/etc/systemd/timesyncd.conf 中指定 systemd-timesyncd 应使用的服务器:

[Time]
NTP=ntp1.example.com ntp2.example.com ntp3.example.com ntp4.example.com

然后重启同步服务(systemctl restart systemd-timesyncd),并通过检查 journal (journalctl --since -1h -u systemd-timesyncd)确认新配置的 NTP 服务器正在使用:

...
Oct 07 14:58:36 node1 systemd[1]: Stopping Network Time Synchronization...
Oct 07 14:58:36 node1 systemd[1]: Starting Network Time Synchronization...
Oct 07 14:58:36 node1 systemd[1]: Started Network Time Synchronization.
Oct 07 14:58:36 node1 systemd-timesyncd[13514]: Using NTP server 10.0.0.1:123 (ntp1.example.com).
Oct 07 14:58:36 node1 systemd-timesyncd[13514]: interval/delta/delay/jitter/drift 64s/-0.002s/0.020s/0.000s/-31ppm
...

常用命令示例:

timedatectl status
chronyc tracking
systemctl status chrony

外部指标服务器

screenshot/gui-datacenter-metric-server-list.png

在 Proxmox VE 中,可以定义外部指标服务器,用于周期性接收主机、虚拟客户机和存储的各类统计信息。

当前支持:

外部指标服务器定义保存在 /etc/pve/status.cfg 中,也可以通过 Web 界面编辑。

Graphite 服务器配置

screenshot/gui-datacenter-metric-server-graphite.png

默认端口为 2003,默认 Graphite 路径为 proxmox

默认情况下,Proxmox VE 通过 UDP 发送数据,因此 Graphite 服务器必须配置为接受 UDP 数据。在这里也可以为未使用标准 1500 MTU 的环境配置最大传输单元(MTU)。

也可以将插件配置为使用 TCP。为了避免阻塞重要的 pvestatd 统计采集守护进程,需要设置超时时间以应对网络问题。

InfluxDB 插件配置

screenshot/gui-datacenter-metric-server-influxdb.png

Proxmox VE 通过 UDP 发送数据,因此 InfluxDB 服务器也必须为此进行配置。必要时,也可以在这里配置 MTU。

以下是在 InfluxDB 服务器上的 InfluxDB 配置示例:

[[udp]]
   enabled = true
   bind-address = "0.0.0.0:8089"
   database = "proxmox"
   batch-size = 1000
   batch-timeout = "1s"

使用该配置时,服务器会在所有 IP 地址的 8089 端口监听,并将数据写入 proxmox 数据库。

也可以将插件配置为使用 InfluxDB 2.x 的 http(s) API。InfluxDB 1.8.x 也包含与该 v2 API 向前兼容的 API endpoint。

要使用该方式,请根据配置将 influxdbproto 设置为 httphttps。默认情况下,Proxmox VE 使用组织 proxmox 和 bucket/db proxmox(可分别通过 organizationbucket 配置项设置)。

由于 InfluxDB 的 v2 API 只能在认证后使用,因此必须生成一个能够写入正确 bucket 的 token 并进行设置。

在 1.8.x 的 v2 兼容 API 中,如有需要,可以使用 user:password 作为 token;由于 organization 在 InfluxDB 1.x 中没有意义,因此可以省略。

还可以通过 timeout 设置 HTTP 超时时间(默认 1s),并通过 max-body-size 设置最大批量大小(默认 25000000 字节)。后者对应 InfluxDB 中同名设置。

常用命令示例

查看外部指标服务器配置文件:

# cat /etc/pve/status.cfg

确认统计采集守护进程正在运行:

# systemctl status pvestatd

磁盘健康监控

虽然建议使用健壮且具备冗余能力的存储,但监控本地磁盘的健康状况仍然非常有用。

从 Proxmox VE 4.3 开始,系统会安装并依赖 smartmontools
[smartmontools homepage https://www.smartmontools.org]
软件包。这是一组用于监控和控制本地硬盘 S.M.A.R.T. 系统的工具。

可以通过执行以下命令获取磁盘状态:

# smartctl -a /dev/sdX

其中 /dev/sdX 是某块本地磁盘的路径。

如果输出显示:

SMART support is: Disabled

可以使用以下命令启用:

# smartctl -s on /dev/sdX

有关 smartctl 用法的更多信息,请参见 man smartctl

默认情况下,smartmontools 守护进程 smartd 处于启用和运行状态,并每 30 分钟扫描 /dev/sdX/dev/hdX 下的磁盘以检查错误和警告;如果检测到问题,会向 root 发送电子邮件。

有关如何配置 smartd 的更多信息,请参见 man smartdman smartd.conf

常用命令示例

查看某块磁盘的 SMART 摘要信息:

# smartctl -H /dev/sdX

查看 smartd 服务状态:

# systemctl status smartmontools

如果硬盘通过硬件 RAID 控制器使用,通常需要使用控制器厂商提供的工具来监控 RAID 阵列中的磁盘以及阵列本身。有关详细信息,请参考 RAID 控制器厂商的文档。

逻辑卷管理器 (LVM)

多数用户会将 Proxmox VE 直接安装到本地磁盘上。Proxmox VE 安装 CD 为本地磁盘管理提供了多种选项, 当前默认配置使用 LVM。安装程序允许你为这种配置选择一块单独的磁盘,并将该磁盘作为 卷组Volume Group,VG)pve 的物理卷。以下输出来自一套使用小型 8GB 磁盘的测试安装:

# pvs
  PV         VG   Fmt  Attr PSize PFree
  /dev/sda3  pve  lvm2 a--  7.87g 876.00m

# vgs
  VG   #PV #LV #SN Attr   VSize VFree
  pve    1   3   0 wz--n- 7.87g 876.00m

安装程序会在该 VG 中分配三个逻辑卷Logical Volumes,LV):

# lvs
  LV   VG   Attr       LSize   Pool Origin Data%  Meta%
  data pve  twi-a-tz--   4.38g             0.00   0.63
  root pve  -wi-ao----   1.75g
  swap pve  -wi-ao---- 896.00m
root

格式化为 ext4,并包含操作系统。

swap

交换分区。

data

该卷使用 LVM-thin,用于存储虚拟机镜像。LVM-thin 更适合这类用途,因为它能高效支持快照和克隆。

对于 Proxmox VE 4.1 及更早版本,安装程序会创建名为 “data” 的标准逻辑卷,并挂载到 /var/lib/vz

从 4.2 版本开始,逻辑卷 “data” 是一个 LVM-thin 池,用于存储基于块的客户机镜像, 而 /var/lib/vz 只是根文件系统上的一个目录。

硬件

强烈建议在此类配置中使用硬件 RAID 控制器(带 BBU)。这可以提升性能、提供冗余, 并让磁盘更换更容易(支持热插拔)。

LVM 本身不需要任何特殊硬件,内存需求也很低。

引导加载器

默认会安装两个引导加载器。第一个分区包含标准 GRUB 引导加载器。第二个分区是 EFI System Partition(ESP),用于在 EFI 系统上启动,并允许从用户空间应用 持久化固件更新

创建卷组

假设有一块空磁盘 /dev/sdb,我们希望在其上创建名为 “vmdata” 的卷组。

Caution 请注意,以下命令会销毁 /dev/sdb 上的所有现有数据。

首先创建一个分区。

# sgdisk -N 1 /dev/sdb

创建一个物理卷Physical Volume,PV),不要求确认,并使用 250K 元数据大小。

# pvcreate --metadatasize 250k -y -ff /dev/sdb1

/dev/sdb1 上创建名为 “vmdata” 的卷组。

# vgcreate vmdata /dev/sdb1

/var/lib/vz 创建额外 LV

可以通过创建新的 thin LV 轻松完成。

# lvcreate -n <Name> -V <Size[M,G,T]> <VG>/<LVThin_pool>

实际示例:

# lvcreate -n vz -V 10G pve/data

现在必须在该 LV 上创建文件系统。

# mkfs.ext4 /dev/pve/vz

最后需要将其挂载。

Warning 请确保 /var/lib/vz 为空。在默认安装中,它并不是空目录。

要使其始终可访问,请将以下行添加到 /etc/fstab

# echo '/dev/pve/vz /var/lib/vz ext4 defaults 0 2' >> /etc/fstab

调整 thin 池大小

使用以下命令调整 LV 和元数据池大小:

# lvresize --size +<size[\M,G,T]> --poolmetadatasize +<size[\M,G]> <VG>/<LVThin_pool>
Note 扩展数据池时,也必须同时扩展元数据池。

创建 LVM-thin 池

thin 池必须创建在卷组之上。关于如何创建卷组,请参见 LVM 章节。

# lvcreate -L 80G -T -n vmstore vmdata

常用命令示例

以下命令可用于查看本地 LVM 状态和 thin 池使用情况:

# pvs
# vgs
# lvs
# lvs -a

Linux 上的 ZFS

ZFS 是由 Sun Microsystems 设计的文件系统与逻辑卷管理器组合。从 Proxmox VE 3.4 开始,ZFS 文件系统的原生 Linux 内核移植版本作为可选文件系统引入,同时也可作为根文件系统的额外选择。无需手动编译 ZFS 模块,所有软件包均已包含。

通过使用 ZFS,可以在低预算硬件上获得丰富的企业级功能,也可以借助 SSD 缓存甚至纯 SSD 部署构建高性能系统。ZFS 可以用适度的 CPU 和内存负载以及易于管理的方式,替代成本较高的硬件 RAID 卡。

ZFS 的一般优势
  • 可通过 Proxmox VE GUI 和 CLI 轻松配置和管理。

  • 可靠。

  • 防止数据损坏。

  • 文件系统级数据压缩。

  • 快照。

  • 写时复制克隆。

  • 多种 RAID 级别:RAID0、RAID1、RAID10、RAIDZ-1、RAIDZ-2、RAIDZ-3、 dRAID, dRAID2, dRAID3

  • 可使用 SSD 作为缓存。

  • 自愈能力。

  • 持续完整性检查。

  • 面向大容量存储设计。

  • 通过网络进行异步复制。

  • 开源。

  • 加密。

硬件

ZFS 对内存依赖较高,因此起步至少需要 8GB。实践中,应在硬件和预算允许的范围内尽量配置更多内存。为防止数据损坏,建议使用高质量 ECC RAM。

如果使用专用缓存盘和/或日志盘,应使用企业级 SSD。这可以显著提升整体性能。

Important 不要在带有自身缓存管理的硬件 RAID 控制器之上使用 ZFS。ZFS 需要直接与磁盘通信。HBA 适配器,或刷入 “IT” 模式的 LSI 控制器一类设备更合适。

如果是在虚拟机中实验安装 Proxmox VE(嵌套虚拟化),不要为该虚拟机的磁盘使用 virtio,因为 ZFS 不支持这种磁盘。请改用 IDE 或 SCSI(也可使用 virtio SCSI 控制器类型)。

作为根文件系统安装

使用 Proxmox VE 安装程序安装时,可以为根文件系统选择 ZFS。安装时需要选择 RAID 类型:

RAID0

也称为 “striping”。此类卷的容量是所有磁盘容量之和。但 RAID0 不提供任何冗余,因此单块磁盘故障就会导致该卷不可用。

RAID1

也称为 “mirroring”。数据会以相同方式写入所有磁盘。此模式至少需要 2 块同等大小的磁盘,最终容量等同于单块磁盘。

RAID10

RAID0 与 RAID1 的组合。至少需要 4 块磁盘。

RAIDZ-1

RAID-5 的变体,单校验。至少需要 3 块磁盘。

RAIDZ-2

RAID-5 的变体,双校验。至少需要 4 块磁盘。

RAIDZ-3

RAID-5 的变体,三重校验。至少需要 5 块磁盘。

安装程序会自动对磁盘分区,创建名为 rpool 的 ZFS pool,并将根文件系统安装到 ZFS 子卷 rpool/ROOT/pve-1 上。

安装程序还会创建名为 rpool/data 的子卷用于存储虚拟机镜像。为了让 Proxmox VE 工具使用该子卷,安装程序会在 /etc/pve/storage.cfg 中创建以下配置项:

zfspool: local-zfs
        pool rpool/data
        sparse
        content images,rootdir

安装完成后,可以使用 zpool 命令查看 ZFS pool 状态:

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

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sda2    ONLINE       0     0     0
            sdb2    ONLINE       0     0     0
          mirror-1  ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0

errors: No known data errors

zfs 命令用于配置和管理 ZFS 文件系统。以下命令会列出安装后的所有文件系统:

# zfs list
NAME               USED  AVAIL  REFER  MOUNTPOINT
rpool             4.94G  7.68T    96K  /rpool
rpool/ROOT         702M  7.68T    96K  /rpool/ROOT
rpool/ROOT/pve-1   702M  7.68T   702M  /
rpool/data          96K  7.68T    96K  /rpool/data
rpool/swap        4.25G  7.69T    64K  -

ZFS RAID 级别考量

选择 ZFS pool 布局时,需要考虑几个因素。ZFS pool 的基本构建块是虚拟设备,即 vdev。pool 中的所有 vdev 都会被均衡使用,数据会在它们之间条带化(RAID0)。有关 vdev 的更多详情,请查看 zpoolconcepts(7) manpage。

性能

每种 vdev 类型都有不同的性能行为。主要关注的两个参数是 IOPS(每秒输入/输出操作数)以及数据读写带宽。

写入数据时,mirror vdev(RAID1)在这两个参数上的表现大致类似单块磁盘。读取数据时,性能会随 mirror 中磁盘数量线性扩展。

一种常见场景是有 4 块磁盘。将其设置为 2 个 mirror vdev(RAID10)时,从 IOPS 和带宽角度看,该 pool 的写入特性相当于两块单盘。读取操作则接近 4 块单盘。

任意冗余级别的 RAIDZ 在 IOPS 方面大致类似单块磁盘,但具有较高带宽。具体带宽取决于 RAIDZ vdev 的大小和冗余级别。

dRAID pool 的性能应与等价的 RAIDZ pool 相当。

对于运行虚拟机而言,在多数情况下 IOPS 是更重要的指标。

大小、空间使用和冗余

mirror vdev 组成的 pool 具有最佳性能特性,但可用空间只有可用磁盘容量的 50%。如果一个 mirror vdev 由超过 2 块磁盘组成,例如 3-way mirror,则可用空间更少。每个 mirror 至少需要一块健康磁盘,pool 才能保持可用。

由 N 块磁盘组成的 RAIDZ 类型 vdev 可用空间大致为 N-P,其中 P 为 RAIDZ 级别。RAIDZ 级别表示在不丢失数据的情况下可任意故障的磁盘数量。4 块磁盘的 RAIDZ2 pool 是一个特殊场景;这种情况下通常最好使用 2 个 mirror vdev,因为可用空间相同但性能更好。

使用任意 RAIDZ 级别时,另一个重要因素是用于虚拟机磁盘的 ZVOL dataset 的行为。对于每个数据块,pool 都需要校验数据,其大小至少为 pool 的 ashift 值所定义的最小块大小。ashift 为 12 时,pool 块大小为 4k。ZVOL 的默认块大小为 8k。因此,在 RAIDZ2 中,每写入一个 8k 块,就会额外写入两个 4k 校验块,即 8k + 4k + 4k = 16k。当然这是简化说明,实际情况会因元数据、压缩等因素而略有不同,本示例未将这些因素计入。

检查 ZVOL 的以下属性时,可以观察到这种行为:

  • volsize

  • refreservation(如果 pool 未使用 thin provisioning)

  • used(如果 pool 使用 thin provisioning 且不存在快照)

# zfs get volsize,refreservation,used <pool>/vm-<vmid>-disk-X

volsize 是呈现给虚拟机的磁盘大小,而 refreservation 显示 pool 上的预留空间,其中包含校验数据预计需要的空间。如果 pool 使用 thin provisioning,则 refreservation 会设置为 0。另一种观察方式是比较虚拟机内部已用磁盘空间与 used 属性。请注意,快照会影响该值。

有几种方式可以抵消空间使用增加的问题:

  • 增大 volblocksize 以改善数据与校验的比例

  • 使用 mirror vdev 替代 RAIDZ

  • 使用 ashift=9(块大小为 512 字节)

volblocksize 属性只能在创建 ZVOL 时设置。默认值可以在存储配置中修改。这样做时,需要对客户机进行相应调优;并且根据使用场景,写放大问题可能只是从 ZFS 层转移到了客户机内部。

创建 pool 时使用 ashift=9 可能会导致性能较差,具体取决于底层磁盘,并且之后无法更改。

Mirror vdev(RAID1、RAID10)对虚拟机工作负载更友好。除非环境有特定需求和特性,且 RAIDZ 性能特征可以接受,否则应优先使用 mirror vdev。

ZFS dRAID

在 ZFS dRAID(declustered RAID)中,热备盘会参与 RAID。其备用容量会被保留,并在某块磁盘故障时用于重建。根据配置不同,发生磁盘故障时,这可以比 RAIDZ 提供更快的重建速度。更多信息请参见官方 OpenZFS 文档。
[OpenZFS dRAID https://openzfs.github.io/openzfs-docs/Basic%20Concepts/dRAID%20Howto.html]

Note dRAID 适用于一个 dRAID 中包含超过 10-15 块磁盘的场景。在大多数使用场景中,磁盘数量较少时 RAIDZ 配置通常更合适。
Note GUI 要求的磁盘数量比最低要求多一块(例如 dRAID1 需要 3 块)。它会假定同时添加一块备用磁盘。
  • dRAID1dRAID:至少需要 2 块磁盘,可在丢失数据前容忍 1 块磁盘故障

  • dRAID2:至少需要 3 块磁盘,可在丢失数据前容忍 2 块磁盘故障

  • dRAID3:至少需要 4 块磁盘,可在丢失数据前容忍 3 块磁盘故障

更多信息可在 manual page 中找到:

# man zpoolconcepts

Spares 和 Data

spares 的数量告诉系统在磁盘故障时应预留多少块磁盘。默认值为 0 spares。没有 spare 时,重建不会获得速度优势。

data 定义冗余组中的设备数量。默认值为 8。除非 disks - parity - spares 小于 8,此时会使用较小值。通常,较少的 data 设备会带来更高 IOPS、更好的压缩率和更快的 resilvering,但定义较少 data 设备会降低 pool 的可用存储容量。

Bootloader

Proxmox VE 使用 proxmox-boot-tool 管理 bootloader 配置。详情请参见 Proxmox VE 主机 bootloader 章节。

ZFS 管理

本节给出一些常见任务的使用示例。ZFS 本身功能非常强大,并提供大量选项。管理 ZFS 的主要命令是 zfszpool。这两个命令都带有完善的 manual page,可以通过以下命令阅读:

# man zpool
# man zfs

创建新的 zpool

创建新 pool 至少需要一块磁盘。ashift 应与底层磁盘的扇区大小(2 的 ashift 次方)相同或更大。

# zpool create -f -o ashift=12 <pool> <device>
Tip

Pool 名称必须遵循以下规则:

  • 以字母开头(a-z 或 A-Z)

  • 仅包含字母数字、-_.: 或 ` `(空格)字符

  • 不得以 mirrorraidzdraidspare 开头

  • 不得为 log

要启用压缩(参见 ZFS 中的压缩 章节):

# zfs set compression=lz4 <pool>

创建带 RAID-0 的新 pool

至少 1 块磁盘

# zpool create -f -o ashift=12 <pool> <device1> <device2>

创建带 RAID-1 的新 pool

至少 2 块磁盘

# zpool create -f -o ashift=12 <pool> mirror <device1> <device2>

创建带 RAID-10 的新 pool

至少 4 块磁盘

# zpool create -f -o ashift=12 <pool> mirror <device1> <device2> mirror <device3> <device4>

创建带 RAIDZ-1 的新 pool

至少 3 块磁盘

# zpool create -f -o ashift=12 <pool> raidz1 <device1> <device2> <device3>

创建带 RAIDZ-2 的新 pool

至少 4 块磁盘

# zpool create -f -o ashift=12 <pool> raidz2 <device1> <device2> <device3> <device4>

设置 pool 前,请阅读 ZFS RAID 级别考量 章节,以粗略估算 IOPS 和带宽预期,特别是在计划使用 RAID-Z 模式时。

创建带缓存(L2ARC)的新 pool

可以使用专用设备或分区作为二级缓存以提升性能。此类缓存设备尤其有助于大部分为静态数据的随机读取工作负载。由于它作为实际存储与内存中 ARC 之间的额外缓存层,如果由于内存约束必须降低 ARC,也能提供帮助。

创建带磁盘缓存的 ZFS pool
# zpool create -f -o ashift=12 <pool> <device> cache <cache-device>

这里仅使用了单个 <device> 和单个 <cache-device>,但也可以使用更多设备,如 创建带 RAID 的新 pool 中所示。

请注意,缓存设备不存在 mirror 或 RAID 模式,它们只是简单累加。

如果任何缓存设备在读取时产生错误,ZFS 会透明地将该请求转向底层存储层。

创建带日志(ZIL)的新 pool

可以为 ZFS Intent Log(ZIL)使用专用磁盘或分区。它主要用于提供安全的同步事务,因此常用于数据库等性能关键路径,或其他频繁发出 fsync 操作的程序。

pool 是默认的 ZIL 位置。将 ZIL I/O 负载转移到独立设备,可以在减轻主 pool 负载的同时降低事务延迟,从而提升整体性能。

对于直接作为日志设备或通过分区作为日志设备的磁盘,建议:

  • 使用具备掉电保护的快速 SSD,因为这类设备的提交延迟更低。

  • 为分区(或整个设备)至少使用几 GB 空间,但超过已安装内存的一半不会带来实际优势。

创建带独立日志设备的 ZFS pool
# zpool create -f -o ashift=12 <pool> <device> log <log-device>

上例使用了单个 <device> 和单个 <log-device>,但也可以结合其他 RAID 变体使用,如 创建带 RAID 的新 pool 章节所述。

也可以将日志设备 mirror 到多个设备。这主要用于确保单个日志设备故障时,性能不会立即下降。

如果所有日志设备均故障,ZFS 会重新使用主 pool 本身,直到日志设备被替换。

向现有 pool 添加缓存和日志

如果某个 pool 没有缓存和日志,也可以在任何时候添加二者或其中之一。

例如,假设有一块具备掉电保护的优质企业级 SSD,并希望用它提升 pool 的整体性能。

由于日志设备最大大小应约为已安装物理内存的一半,这意味着 ZIL 很可能只占用 SSD 的一小部分,剩余空间可以用作缓存。

首先需要使用 partedgdisk 在 SSD 上创建两个 GPT 分区。

然后即可将它们添加到 pool:

向现有 pool 同时添加独立日志设备和二级缓存
# zpool add -f <pool> log <device-part1> cache <device-part2>

只需将 <pool><device-part1><device-part2> 替换为 pool 名称以及两个分区的 /dev/disk/by-id/ 路径。

也可以分别添加 ZIL 和缓存。

向现有 ZFS pool 添加日志设备
# zpool add <pool> log <log-device>

更换故障设备

# zpool replace -f <pool> <old-device> <new-device>
更换故障的可启动设备

根据 Proxmox VE 的安装方式,它会通过 proxmox-boot-tool
[Systems installed with Proxmox VE 6.4 or later, EFI systems installed with Proxmox VE 5.4 or later]
使用 systemd-boot 或 GRUB,或者使用普通 GRUB 作为 bootloader(参见 主机 Bootloader)。可以通过运行以下命令检查:

# proxmox-boot-tool status

复制分区表、重新生成 GUID 并替换 ZFS 分区的前几个步骤相同。为了让系统能够从新磁盘启动,还需要根据所使用的 bootloader 执行不同步骤。

# sgdisk <healthy bootable device> -R <new device>
# sgdisk -G <new device>
# zpool replace -f <pool> <old zfs partition> <new zfs partition>
Note 使用 zpool status -v 命令监控新磁盘 resilvering 过程的进度。
使用 proxmox-boot-tool
# proxmox-boot-tool format <new disk's ESP>
# proxmox-boot-tool init <new disk's ESP> [grub]
Note ESP 表示 EFI System Partition。从版本 5.4 起,使用 Proxmox VE 安装程序时,它会在可启动磁盘上设置为第 2 个分区。详情请参见 设置新分区以用作同步 ESP
Note 如果 proxmox-boot-tool status 表明当前磁盘使用 GRUB,请确保将 grub 作为模式传递给 proxmox-boot-tool init,尤其是在启用 Secure Boot 时。
使用普通 GRUB:
# grub-install <new disk>
Note 普通 GRUB 仅用于使用 Proxmox VE 6.3 或更早版本安装且尚未手动迁移到 proxmox-boot-tool 的系统。

配置电子邮件通知

ZFS 带有事件守护进程 ZED,用于监控 ZFS 内核模块生成的事件。该守护进程也可以在发生 pool 错误等 ZFS 事件时发送电子邮件。较新的 ZFS 软件包将该守护进程放在独立的 zfs-zed 软件包中,该软件包应已在 Proxmox VE 中默认安装。

可以使用喜欢的编辑器通过 /etc/zfs/zed.d/zed.rc 文件配置该守护进程。电子邮件通知所需设置为 ZED_EMAIL_ADDR,默认设置为 root

ZED_EMAIL_ADDR="root"

请注意,Proxmox VE 会将发往 root 的邮件转发到为 root 用户配置的电子邮件地址。

限制 ZFS 内存使用

默认情况下,ZFS 使用主机内存的 50 % 作为 Adaptive Replacement Cache (ARC)。从 Proxmox VE 8.1 开始的新安装中,ARC 使用上限会设置为已安装物理内存的 10 %,最大限制为 16 GiB。该值写入 /etc/modprobe.d/zfs.conf

为 ARC 分配足够内存对 I/O 性能至关重要,因此降低该值时应谨慎。一般经验是至少分配 2 GiB Base + 1 GiB/TiB-Storage。例如,如果 pool 有 8 TiB 可用存储空间,则应为 ARC 使用 10 GiB 内存。

ZFS 还会强制执行 64 MiB 的最小值。

可以通过直接写入 zfs_arc_max 模块参数,为当前启动周期修改 ARC 使用上限(重启会重置该更改):

 echo "$[10 * 1024*1024*1024]" >/sys/module/zfs/parameters/zfs_arc_max

要*永久更改* ARC 限制,请在 /etc/modprobe.d/zfs.conf 中添加(或修改已有的)以下行:

options zfs zfs_arc_max=8589934592

此示例设置会将使用量限制为 8 GiB(8 * 230)。

Important 如果期望的 zfs_arc_max 值小于或等于 zfs_arc_min(默认为系统内存的 1/32),则 zfs_arc_max 会被忽略,除非同时将 zfs_arc_min 设置为至多 zfs_arc_max - 1
echo "$[8 * 1024*1024*1024 - 1]" >/sys/module/zfs/parameters/zfs_arc_min
echo "$[8 * 1024*1024*1024]" >/sys/module/zfs/parameters/zfs_arc_max

在总内存超过 256 GiB 的系统上,此示例设置会将使用量(临时)限制为 8 GiB(8 * 230)。在这种情况下,单独设置 zfs_arc_max 不会生效。

Important

如果根文件系统是 ZFS,每次该值变化后都必须更新 initramfs:

# update-initramfs -u -k all

必须*重启*才能激活这些更改。

ZFS 上的 SWAP

在 zvol 上创建的 swap 空间可能会产生一些问题,例如阻塞服务器或造成高 I/O 负载,这种情况常见于开始向外部存储执行备份时。

强烈建议使用足够内存,使系统通常不会遇到低内存情况。如果需要或希望添加 swap,首选是在物理磁盘上创建分区并将其用作 swap 设备。可以在安装程序高级选项中为此预留一些空间。此外,还可以降低 “swappiness” 值。服务器上的一个较好取值是 10:

# sysctl -w vm.swappiness=10

要使 swappiness 持久化,请使用喜欢的编辑器打开 /etc/sysctl.conf 并添加以下行:

vm.swappiness = 10
Table 1. Linux 内核 swappiness 参数值
策略

vm.swappiness = 0

内核只会为了避免 out of memory 情况而使用 swap

vm.swappiness = 1

在不完全禁用 swap 的情况下,尽量减少 swap 使用量。

vm.swappiness = 10

当系统内存充足时,有时建议使用该值以改善性能。

vm.swappiness = 60

默认值。

vm.swappiness = 100

内核会积极使用 swap。

加密的 ZFS Dataset

Warning Proxmox VE 中的原生 ZFS 加密仍处于实验阶段。已知限制和问题包括加密 dataset 的复制
[Bugzilla #2350]
,以及使用快照或 ZVOL 时的 checksum 错误。
[OpenZFS issue #11688]

ZFS on Linux 0.8.0 版本引入了对 dataset 原生加密的支持。从较早 ZFS on Linux 版本升级后,可以按 pool 启用加密特性:

# zpool get feature@encryption tank
NAME  PROPERTY            VALUE            SOURCE
tank  feature@encryption  disabled         local

# zpool set feature@encryption=enabled

# zpool get feature@encryption tank
NAME  PROPERTY            VALUE            SOURCE
tank  feature@encryption  enabled         local
Warning 目前不支持使用 GRUB 从包含加密 dataset 的 pool 启动,并且对启动时自动解锁加密 dataset 仅提供有限支持。不支持加密的旧版 ZFS 将无法解密已存储数据。
Note 建议在启动后手动解锁存储 dataset,或编写自定义 unit,在启动时将解锁所需 key material 传递给 zfs load-key
Warning 在为生产数据启用加密前,请建立并测试备份流程。如果相关 key material/passphrase/keyfile 丢失,将无法再访问加密数据。

加密需要在创建 dataset/zvol 时设置,并默认由子 dataset 继承。例如,要创建加密 dataset tank/encrypted_data 并将其配置为 Proxmox VE 中的存储,请运行以下命令:

# zfs create -o encryption=on -o keyformat=passphrase tank/encrypted_data
Enter passphrase:
Re-enter passphrase:

# pvesm add zfspool encrypted_zfs -pool tank/encrypted_data

在该存储上创建的所有客户机卷/磁盘都会使用父 dataset 的共享 key material 加密。

要实际使用该存储,需要加载关联的 key material 并挂载 dataset。可以通过以下命令一步完成:

# zfs mount -l tank/encrypted_data
Enter passphrase for 'tank/encrypted_data':

也可以通过设置 keylocationkeyformat 属性,使用(随机)keyfile 替代交互式输入 passphrase。这既可以在创建时设置,也可以通过 zfs change-key 对现有 dataset 设置:

# dd if=/dev/urandom of=/path/to/keyfile bs=32 count=1

# zfs change-key -o keyformat=raw -o keylocation=file:///path/to/keyfile tank/encrypted_data
Warning 使用 keyfile 时,必须特别注意保护 keyfile,避免未授权访问或意外丢失。没有 keyfile,就无法访问明文数据。

在加密 dataset 下创建的客户机卷会相应设置其 encryptionroot 属性。每个 encryptionroot 只需加载一次 key material,其下所有加密 dataset 即可使用。

更多详情和高级用法,请参见 encryptionrootencryptionkeylocationkeyformatkeystatus 属性,zfs load-keyzfs unload-keyzfs change-key 命令,以及 man zfs 中的 Encryption 章节。

ZFS 中的压缩

在 dataset 上启用压缩后,ZFS 会尝试在写入所有*新*块之前压缩它们,并在读取时解压缩。已存在的数据不会被追溯压缩。

可以使用以下命令启用压缩:

# zfs set compression=<algorithm> <dataset>

建议使用 lz4 算法,因为它只会带来很小的 CPU 开销。也可以使用其他算法,例如 lzjbgzip-N,其中 N 是从 1(最快)到 9(最佳压缩率)的整数。根据算法和数据可压缩性不同,启用压缩甚至可能提升 I/O 性能。

可以随时使用以下命令禁用压缩:

# zfs set compression=off <dataset>

同样,只有新块会受到该更改影响。

ZFS Special Device

自 0.8.0 版本起,ZFS 支持 special 设备。pool 中的 special 设备用于存储元数据、去重表,并可选择存储小文件块。

对于由慢速机械硬盘组成且存在大量元数据变更的 pool,special 设备可以提升速度。例如,涉及创建、更新或删除大量文件的工作负载会从 special 设备中受益。还可以配置 ZFS dataset,将整个小文件存储在 special 设备上,从而进一步提升性能。special 设备应使用快速 SSD。

Important special 设备的冗余级别应与 pool 保持一致,因为 special 设备是整个 pool 的故障点。
Warning 向 pool 添加 special 设备后无法撤销。
创建带 special 设备和 RAID-1 的 pool:
# zpool create -f -o ashift=12 <pool> mirror <device1> <device2> special mirror <device3> <device4>
向现有 RAID-1 pool 添加 special 设备:
# zpool add <pool> special mirror <device1> <device2>

ZFS dataset 暴露 special_small_blocks=<size> 属性。size 可以为 0,表示禁用在 special 设备上存储小文件块;也可以是 512B1M 范围内的 2 的幂。设置该属性后,小于 size 的新文件块会分配到 special 设备上。

Important 如果 special_small_blocks 的值大于或等于 dataset 的 recordsize(默认 128K),则*所有*数据都会写入 special 设备,因此请谨慎设置。

在 pool 上设置 special_small_blocks 属性会改变所有子 ZFS dataset 该属性的默认值(例如该 pool 中的所有容器都会选择使用小文件块)。

在整个 pool 范围内选择将小于 4K-blocks 的所有文件写入 special device:
# zfs set special_small_blocks=4K <pool>
为单个 dataset 选择使用小文件块:
# zfs set special_small_blocks=4K <pool>/<filesystem>
为单个 dataset 退出使用小文件块:
# zfs set special_small_blocks=0 <pool>/<filesystem>

ZFS Pool 特性

ZFS 磁盘格式的变更只会在主版本变更之间进行,并通过 features 指定。所有 feature 以及通用机制都在 zpool-features(5) manpage 中有详细记录。

由于启用新 feature 可能导致旧版 ZFS 无法导入 pool,因此必须由管理员主动在 pool 上运行 zpool upgrade 完成(参见 zpool-upgrade(8) manpage)。

除非需要使用某个新 feature,否则启用它们没有额外收益。

事实上,启用新 feature 存在一些缺点:

  • 如果 root on ZFS 系统仍使用 GRUB 启动,而 rpool 上激活了新 feature,由于 GRUB 中的 ZFS 实现不兼容,系统将无法启动。

  • 使用仍随附旧 ZFS 模块的旧内核启动时,系统将无法导入任何已升级的 pool。

  • 启动较旧的 Proxmox VE ISO 来修复无法启动的系统也同样不可行。

Important 如果系统仍使用 GRUB 启动,*不要*升级 rpool,因为这会导致系统无法启动。这包括在 Proxmox VE 5.4 之前安装的系统,以及使用 legacy BIOS boot 启动的系统(参见 如何判断所使用的 bootloader)。
为 ZFS pool 启用新 feature:
# zpool upgrade <pool>

常用命令示例

查看所有 ZFS pool 的状态:

# zpool status

列出 ZFS dataset:

# zfs list

BTRFS

Warning BTRFS 集成目前在 Proxmox VE 中仍是 technology preview

BTRFS 是 Linux 内核原生支持的现代写时复制文件系统,实现了快照、内置 RAID, 以及通过数据和元数据校验和进行自修复等特性。从 Proxmox VE 7.0 开始,BTRFS 作为根文件系统的可选项引入。

BTRFS 的一般优势
  • 主系统设置与传统基于 ext4 的设置几乎相同

  • 快照

  • 文件系统级数据压缩

  • 写时复制克隆

  • RAID0, RAID1 and RAID10

  • 防止数据损坏

  • 自修复

  • Linux 内核原生支持

注意事项
  • RAID 级别 5/6 仍处于实验阶段且存在风险,请参见 BTRFS Status

作为根文件系统安装

使用 Proxmox VE 安装程序安装时,可以为根文件系统选择 BTRFS。需要在安装时选择 RAID 类型:

RAID0

也称为`‘条带化’'。此类卷的容量是所有磁盘容量之和。但 RAID0 不提供 任何冗余,因此单个驱动器故障就会使该卷不可用。

RAID1

也称为`‘镜像’'。数据会以相同方式写入所有磁盘。此模式至少需要 2 块相同容量的磁盘。最终容量等同于单块磁盘容量。

RAID10

RAID0 和 RAID1 的组合。至少需要 4 块磁盘。

安装程序会自动对磁盘分区,并在 /var/lib/pve/local-btrfs 创建一个额外子卷。 为了让 Proxmox VE 工具使用该子卷,安装程序会在 /etc/pve/storage.cfg 中创建 以下配置条目:

dir: local
        path /var/lib/vz
        content iso,vztmpl,backup
        disable

btrfs: local-btrfs
        path /var/lib/pve/local-btrfs
        content iso,vztmpl,backup,images,rootdir

这会显式禁用默认的 local 存储,改用额外子卷上的 BTRFS 专用存储条目。

btrfs 命令用于配置和管理 BTRFS 文件系统。安装完成后,以下命令会列出所有 额外子卷:

# btrfs subvolume list /
ID 256 gen 6 top level 5 path var/lib/pve/local-btrfs

BTRFS 管理

本节给出一些常见任务的使用示例。

创建 BTRFS 文件系统

创建 BTRFS 文件系统时使用 mkfs.btrfs-d-m 参数分别用于设置数据和 元数据的 profile。可选的 -L 参数可用于设置标签。

通常支持以下模式:singleraid0raid1raid10

在单块磁盘 /dev/sdb 上创建标签为 My-Storage 的 BTRFS 文件系统:

 # mkfs.btrfs -m single -d single -L My-Storage /dev/sdb

或者在两个分区 /dev/sdb1/dev/sdc1 上创建 RAID1:

 # mkfs.btrfs -m raid1 -d raid1 -L My-Storage /dev/sdb1 /dev/sdc1

挂载 BTRFS 文件系统

随后可以手动挂载新的文件系统,例如:

 # mkdir /my-storage
 # mount /dev/sdb /my-storage

BTRFS 也可以像其他挂载点一样添加到 /etc/fstab,从而在启动时自动挂载。 建议避免使用块设备路径,而是使用 mkfs.btrfs 命令输出的 UUID 值, 尤其是在 BTRFS 设置中包含多块磁盘时。

例如:

文件 /etc/fstab
# ... 为简洁起见,省略其他挂载点

# 强烈建议使用 mkfs.btrfs 输出中的 UUID
UUID=e2c0c3ff-2114-4f54-b767-3a203e49f6f3 /my-storage btrfs defaults 0 0
Tip 如果不再持有 UUID,可以使用 blkid 工具列出块设备的所有属性。

之后可以通过执行以下命令触发首次挂载:

mount /my-storage

下一次重启后,系统会在启动时自动执行该挂载。

将 BTRFS 文件系统添加到 Proxmox VE

可以通过 Web 界面将现有 BTRFS 文件系统添加到 Proxmox VE,也可以使用 CLI,例如:

pvesm add btrfs my-storage --path /my-storage

创建子卷

创建子卷会将其关联到 BTRFS 文件系统中的某个路径,在该路径下它会表现为普通目录。

# btrfs subvolume create /some/path

之后 /some/path 会像普通目录一样工作。

删除子卷

与通过 rmdir 删除目录不同,使用 btrfs 命令删除子卷时,子卷不需要为空。

# btrfs subvolume delete /some/path

创建子卷快照

BTRFS 实际上并不区分快照和普通子卷,因此创建快照也可以理解为创建一个子卷的 任意副本。按照约定,Proxmox VE 在为客户机磁盘或子卷创建快照时会使用只读标志, 但该标志之后也可以更改。

# btrfs subvolume snapshot -r /some/path /a/new/path

这会在 /a/new/path 创建 /some/path 上该子卷的只读“克隆”。以后对 /some/path 的任何修改都会使被修改的数据在修改前先被复制。

如果省略只读(-r)选项,则两个子卷都将可写。

启用压缩

默认情况下,BTRFS 不会压缩数据。要启用压缩,可以添加 compress 挂载选项。 注意,已经写入的数据不会在事后被压缩。

默认情况下,rootfs 会在 /etc/fstab 中按如下方式列出:

UUID=<uuid of your root file system> / btrfs defaults 0 1

可以直接在上面的 defaults 后追加 compress=zstdcompress=lzocompress=zlib,如下所示:

UUID=<uuid of your root file system> / btrfs defaults,compress=zstd 0 1

该更改会在重启后生效。

检查空间使用情况

传统的 df 工具在某些 BTRFS 设置中可能会输出令人困惑的数值。要获得更好的 估算结果,请使用 btrfs filesystem usage /PATH 命令,例如:

# btrfs fi usage /my-storage

常用命令示例:

# btrfs subvolume list /
# btrfs filesystem usage /my-storage
# pvesm status

Proxmox 节点管理

Proxmox VE 节点管理工具(pvenode)允许你控制节点特定的设置和资源。

目前,pvenode 可用于设置节点描述、对节点上的客户机执行各种批量操作、查看节点 任务历史,以及管理节点 SSL 证书;这些证书会通过 pveproxy 用于 API 和 Web GUI。

常用命令示例

以下命令可用于查看节点任务、唤醒集群节点或批量启动已配置自启动的客户机:

pvenode task list
pvenode wakeonlan <node>
pvenode startall

Wake-on-LAN

Wake-on-LAN(WoL)允许你通过发送 magic packet 来启动网络中处于睡眠状态的计算机。 至少需要有一个 NIC 支持此功能,并且需要在计算机固件(BIOS/UEFI)配置中启用相应 选项。选项名称可能从 Enable Wake-on-LanPower On By PCIE Device 不等; 如果不确定,请查阅主板厂商手册。可以运行以下命令,使用 ethtool 检查 <interface> 的 WoL 配置:

ethtool <interface> | grep Wake-on

pvenode 允许你通过 WoL 唤醒集群中处于睡眠状态的成员,使用命令:

pvenode wakeonlan <node>

这会在 UDP 端口 9 上广播 WoL magic packet,其中包含从 wakeonlan 属性获取的 <node> MAC 地址。可以使用以下命令设置节点特定的 wakeonlan 属性:

pvenode config set -wakeonlan XX:XX:XX:XX:XX:XX

发送 WoL 数据包所使用的接口由默认路由决定。可以通过以下命令设置 bind-interface 来覆盖它:

pvenode config set -wakeonlan XX:XX:XX:XX:XX:XX,bind-interface=<iface-name>

发送 WoL 数据包时使用的广播地址(默认 255.255.255.255)还可以通过以下命令 显式设置 broadcast-address 来修改:

pvenode config set -wakeonlan XX:XX:XX:XX:XX:XX,broadcast-address=<broadcast-address>

任务历史

排查服务器问题时,例如备份作业失败,查看此前运行任务的日志通常很有帮助。在 Proxmox VE 中,可以通过 pvenode task 命令访问节点的任务历史。

可以使用 list 子命令获取节点已完成任务的过滤列表。例如,要获取与虚拟机 100 相关且以错误结束的任务列表,可使用:

pvenode task list --errors --vmid 100

随后可以使用任务的 UPID 打印该任务日志:

pvenode task log UPID:pve1:00010D94:001CA6EA:6124E1B9:vzdump:100:root@pam:

批量客户机电源管理

如果有许多虚拟机/容器,可以使用 pvenodestartallstopall 子命令对 客户机执行批量启动和停止操作。默认情况下,pvenode startall 只会启动已设置为 开机自动启动的虚拟机/容器(参见 虚拟机的自动启动和关闭);不过可以使用 --force 标志覆盖此行为。 这两个命令也都有 --vms 选项,可将停止/启动的客户机限制为指定 VMID。

例如,要启动虚拟机 100101102,无论它们是否设置了 onboot,可以使用:

pvenode startall --vms 100,101,102 --force

要停止这些客户机(以及可能正在运行的任何其他客户机),请使用命令:

pvenode stopall
Note stopall 命令会先尝试执行干净关机,然后等待所有客户机成功关闭,或等待可 覆盖的超时时间(默认 3 分钟)到期。到达该状态后,如果 force-stop 参数没有显式 设置为 0(false),所有仍在运行的虚拟客户机都会被强制停止。

首个客户机启动延迟

如果虚拟机/容器依赖启动较慢的外部资源,例如 NFS 服务器,也可以按节点设置延迟: 从 Proxmox VE 启动完成到第一个配置为自动启动的虚拟机/容器启动之间等待一段时间 (参见 虚拟机的自动启动和关闭)。

可以通过以下设置实现这一点(其中 10 表示以秒为单位的延迟):

pvenode config set --startall-onboot-delay 10

批量客户机迁移

如果升级场景要求将所有客户机从一个节点迁移到另一个节点,pvenode 也提供了用于 批量迁移的 migrateall 子命令。默认情况下,该命令会将系统上的每个客户机迁移到 目标节点;不过也可以设置为只迁移一组客户机。

例如,要将虚拟机 100101102 迁移到节点 pve2,并启用本地磁盘在线 迁移,可以运行:

pvenode migrateall pve2 --vms 100,101,102 --with-local-disks

Ballooning 的 RAM 使用率目标

自动内存分配的目标百分比默认为 80%。可以通过 设置 ballooning-target 属性按节点自定义此目标。例如,要改为以 90% 主机内存 使用率为目标:

pvenode config set --ballooning-target 90

证书管理

集群内部通信证书

每个 Proxmox VE 集群默认都会创建自己的(自签名)证书颁发机构(CA),并为每个节点生成由该 CA 签名的证书。 这些证书用于与集群的 pveproxy 服务进行加密通信,并在使用 SPICE 时用于 Shell/Console 功能。

CA 证书和密钥存储在 Proxmox Cluster File System (pmxcfs) 中。

API 和 Web GUI 证书

REST API 和 Web GUI 由运行在每个节点上的 pveproxy 服务提供。

对于 pveproxy 使用的证书,可以选择以下方式:

  1. 默认使用 /etc/pve/nodes/NODENAME/pve-ssl.pem 中特定于节点的证书。 该证书由集群 CA 签名,因此不会被浏览器和操作系统自动信任。

  2. 使用外部提供的证书(例如由商业 CA 签名的证书)。

  3. 使用 ACME(Let’s Encrypt)获取可信证书并自动续期;该功能也集成在 Proxmox VE API 和 Web 界面中。

对于方式 2 和 3,会使用文件 /etc/pve/local/pveproxy-ssl.pem(以及必须不带密码的 /etc/pve/local/pveproxy-ssl.key)。

Note 请记住,/etc/pve/local 是指向 /etc/pve/nodes/NODENAME 的节点专用符号链接。

证书通过 Proxmox VE 节点管理命令进行管理(参见 pvenode(1) 手册页)。

Warning 不要替换或手动修改 /etc/pve/local/pve-ssl.pem/etc/pve/local/pve-ssl.key 中自动生成的节点证书文件,也不要修改 /etc/pve/pve-root-ca.pem/etc/pve/priv/pve-root-ca.key 中的集群 CA 文件。

上传自定义证书

如果已经有要用于某个 Proxmox VE 节点的证书,可以直接通过 Web 界面上传该证书。

screenshot/gui-node-certs-upload-custom.png

请注意,如果提供证书密钥文件,则该文件不得受密码保护。

通过 Let’s Encrypt (ACME) 获取可信证书

Proxmox VE 包含 Automatic Certificate Management Environment (ACME)协议的实现,使 Proxmox VE 管理员可以使用 Let’s Encrypt 等 ACME 提供方, 轻松设置在现代操作系统和 Web 浏览器中默认被接受并信任的 TLS 证书。

目前实现的两个 ACME 端点是 Let’s Encrypt (LE) 生产环境及其 staging 环境。 我们的 ACME 客户端支持使用内置 Web 服务器验证 http-01 挑战, 也支持通过 DNS 插件验证 dns-01 挑战;这些 DNS 插件支持 acme.sh 支持的所有 DNS API 端点。

ACME 账户

screenshot/gui-datacenter-acme-register-account.png

需要为每个集群在要使用的端点上注册一个 ACME 账户。该账户使用的电子邮件地址将作为 ACME 端点发送续期到期等通知的联系地址。

可以通过 Web 界面 Datacenter -> ACME 注册和停用 ACME 账户,也可以使用 pvenode 命令行工具。

 pvenode acme account register account-name mail@example.com
Tip 由于存在 速率限制,在实验或首次使用 ACME 时应使用 LE staging

ACME 插件

ACME 插件的任务是自动验证你以及由你操作的 Proxmox VE 集群确实是某个域名的所有者。 这是自动证书管理的基础构件。

ACME 协议定义了不同类型的挑战,例如 http-01:Web 服务器提供包含特定内容的文件,以证明它控制某个域名。 有时由于技术限制,或记录地址无法从公网访问,这种方式不可行。此时可以使用 dns-01 挑战。 该挑战通过在域名区域中创建特定 DNS 记录来完成。

screenshot/gui-datacenter-acme-overview.png

Proxmox VE 开箱即支持这两种挑战类型。可以通过 Web 界面 Datacenter -> ACME 配置插件, 也可以使用 pvenode acme plugin add 命令配置。

ACME 插件配置存储在 /etc/pve/priv/acme/plugins.cfg 中。插件可供集群中的所有节点使用。

节点域名

每个域名都是特定于节点的。可以在 Node -> Certificates 下添加新域名条目或管理现有条目, 也可以使用 pvenode config 命令。

screenshot/gui-node-certs-add-domain.png

为节点配置所需域名并确认选择了所需 ACME 账户后,可以通过 Web 界面订购新证书。 成功后,界面将在 10 秒后重新加载。

续期将 自动进行。

ACME HTTP 挑战插件

始终会隐式配置一个 standalone 插件,用于通过在端口 80 上启动的内置 Web 服务器验证 http-01 挑战。

Note 名称 standalone 表示它可以自行提供验证,而不需要任何第三方服务。因此,该插件也适用于集群节点。

要将其用于 Let’s Encrypt ACME 的证书管理,需要满足几个前提条件。

  • 必须接受 Let’s Encrypt 的 ToS 才能注册账户。

  • 节点的 端口 80 需要可从互联网访问。

  • 端口 80 上 不得 有其他监听程序。

  • 请求的(子)域名需要解析到该节点的公网 IP。

ACME DNS API 挑战插件

在无法或不希望通过 http-01 方法进行外部访问验证的系统上,可以使用 dns-01 验证方法。 此验证方法要求 DNS 服务器允许通过 API 配置 TXT 记录。

配置用于验证的 ACME DNS API

Proxmox VE 复用为 acme.sh
[acme.sh https://github.com/acmesh-official/acme.sh]
项目开发的 DNS 插件。有关特定 API 的配置详情,请参阅其文档。

使用 DNS API 配置新插件的最简单方式是通过 Web 界面(Datacenter -> ACME)。

screenshot/gui-datacenter-acme-add-dns-plugin.png

选择 DNS 作为挑战类型。然后可以选择 API 提供方,并输入通过其 API 访问账户所需的凭据数据。 验证延迟决定了设置 DNS 记录到提示 ACME 提供方进行验证之间的时间(秒),因为提供方通常需要一些时间在其基础设施中传播记录。

Tip 关于如何获取提供方 API 凭据的更多详细信息,请参见 acme.sh How to use DNS API wiki。

由于 DNS 提供方和 API 端点众多,Proxmox VE 会为部分提供方自动生成凭据表单。 对于其他提供方,会显示一个较大的文本区域,只需将所有凭据 KEY=VALUE 对复制进去。

通过 CNAME 别名进行 DNS 验证

如果主/真实 DNS 不支持通过 API 配置记录,可以使用特殊的 alias 模式在另一个域名/DNS 服务器上处理验证。 手动为 _acme-challenge.domain1.example 设置一条永久 CNAME 记录,使其指向 _acme-challenge.domain2.example,并在 Proxmox VE 节点配置文件中相应 acmedomainX 键上将 alias 属性设置为 domain2.example,即可允许 domain2.example 的 DNS 服务器验证 domain1.example 的所有挑战。

插件组合

如果节点可通过多个域名访问,而这些域名具有不同要求或 DNS 配置能力,则可以组合使用 http-01dns-01 验证。 也可以通过为每个域名指定不同插件实例,混合使用来自多个提供方或实例的 DNS API。

Tip 通过多个域名访问同一服务会增加复杂性,应尽可能避免。

ACME 证书自动续期

如果节点已成功配置由 ACME 提供的证书(无论通过 pvenode 还是 GUI),该证书将由 pve-daily-update.service 自动续期。目前,如果证书已经过期,或将在未来 30 天内过期,将尝试续期。

Note 如果使用会颁发短期证书的自定义目录,建议禁用 pve-daily-update.timer 单元的随机延迟, 以避免重启后错过证书续期。

使用 pvenode 的 ACME 示例

示例:用于 Let’s Encrypt 证书的 pvenode 调用示例

root@proxmox:~# pvenode acme account register default mail@example.invalid
Directory endpoints:
0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory)
1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory)
2) Custom
Enter selection: 1

Terms of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
Do you agree to the above terms? [y|N]y
...
Task OK
root@proxmox:~# pvenode config set --acme domains=example.invalid
root@proxmox:~# pvenode acme cert order
Loading ACME account details
Placing ACME order
...
Status is 'valid'!

All domains validated!
...
Downloading certificate
Setting pveproxy certificate and key
Restarting pveproxy
Task OK

示例:设置 OVH API 以验证域名

Note 无论使用哪种插件,账户注册步骤都相同,此处不再重复。
Note OVH_AKOVH_AS 需要根据 OVH API 文档从 OVH 获取。

首先需要获取所有信息,以便你和 Proxmox VE 能够访问该 API。

root@proxmox:~# cat /path/to/api-token
OVH_AK=XXXXXXXXXXXXXXXX
OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
root@proxmox:~# source /path/to/api-token
root@proxmox:~# curl -XPOST -H"X-Ovh-Application: $OVH_AK" -H "Content-type: application/json" \
https://eu.api.ovh.com/1.0/auth/credential  -d '{
  "accessRules": [
    {"method": "GET","path": "/auth/time"},
    {"method": "GET","path": "/domain"},
    {"method": "GET","path": "/domain/zone/*"},
    {"method": "GET","path": "/domain/zone/*/record"},
    {"method": "POST","path": "/domain/zone/*/record"},
    {"method": "POST","path": "/domain/zone/*/refresh"},
    {"method": "PUT","path": "/domain/zone/*/record/"},
    {"method": "DELETE","path": "/domain/zone/*/record/*"}
]
}'
{"consumerKey":"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ","state":"pendingValidation","validationUrl":"https://eu.api.ovh.com/auth/?credentialToken=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}

(打开验证 URL,并按照说明将 Application Key 与账户/Consumer Key 关联)

root@proxmox:~# echo "OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" >> /path/to/api-token

现在可以设置 ACME 插件:

root@proxmox:~# pvenode acme plugin add dns example_plugin --api ovh --data /path/to/api_token
root@proxmox:~# pvenode acme plugin config example_plugin
┌────────┬──────────────────────────────────────────┐
│ key    │ value                                    │
╞════════╪══════════════════════════════════════════╡
│ api    │ ovh                                      │
├────────┼──────────────────────────────────────────┤
│ data   │ OVH_AK=XXXXXXXXXXXXXXXX                  │
│        │ OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY  │
│        │ OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  │
├────────┼──────────────────────────────────────────┤
│ digest │ 867fcf556363ca1bea866863093fcab83edf47a1 │
├────────┼──────────────────────────────────────────┤
│ plugin │ example_plugin                           │
├────────┼──────────────────────────────────────────┤
│ type   │ dns                                      │
└────────┴──────────────────────────────────────────┘

最后,可以配置要为其获取证书的域名,并为其提交证书订单:

root@proxmox:~# pvenode config set -acmedomain0 example.proxmox.com,plugin=example_plugin
root@proxmox:~# pvenode acme cert order
Loading ACME account details
Placing ACME order
Order URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/11111111/22222222

Getting authorization details from 'https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/33333333'
The validation for example.proxmox.com is pending!
[Wed Apr 22 09:25:30 CEST 2020] Using OVH endpoint: ovh-eu
[Wed Apr 22 09:25:30 CEST 2020] Checking authentication
[Wed Apr 22 09:25:30 CEST 2020] Consumer key is ok.
[Wed Apr 22 09:25:31 CEST 2020] Adding record
[Wed Apr 22 09:25:32 CEST 2020] Added, sleep 10 seconds.
Add TXT record: _acme-challenge.example.proxmox.com
Triggering validation
Sleeping for 5 seconds
Status is 'valid'!
[Wed Apr 22 09:25:48 CEST 2020] Using OVH endpoint: ovh-eu
[Wed Apr 22 09:25:48 CEST 2020] Checking authentication
[Wed Apr 22 09:25:48 CEST 2020] Consumer key is ok.
Remove TXT record: _acme-challenge.example.proxmox.com

All domains validated!

Creating CSR
Checking order status
Order is ready, finalizing order
valid!

Downloading certificate
Setting pveproxy certificate and key
Restarting pveproxy
Task OK

示例:从 staging 切换到常规 ACME 目录

不支持更改某个账户的 ACME 目录,但由于 Proxmox VE 支持多个账户,可以直接创建一个以生产(可信)ACME 目录作为端点的新账户。 也可以停用 staging 账户并重新创建它。

示例:使用 pvenodedefault ACME 账户从 staging 切换到正式目录
root@proxmox:~# pvenode acme account deactivate default
Renaming account file from '/etc/pve/priv/acme/default' to '/etc/pve/priv/acme/_deactivated_default_4'
Task OK

root@proxmox:~# pvenode acme account register default example@proxmox.com
Directory endpoints:
0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory)
1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory)
2) Custom
Enter selection: 0

Terms of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
Do you agree to the above terms? [y|N]y
...
Task OK

主机引导加载器

Proxmox VE 当前会根据安装程序中选择的磁盘设置,使用两种引导加载器之一。

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

目前在OpenEuler版本上,本工具不可用。

安装程序使用的分区方案

Proxmox VE 安装程序会在所有被选作安装目标的磁盘上创建 3 个分区。

创建的分区包括:

  • 一个 1 MB 的 BIOS Boot Partition(gdisk 类型 EF02)

  • 一个 512 MB 的 EFI System Partition(ESP,gdisk 类型 EF00)

  • 第三个分区,占用设定的 hdsize 参数范围,或占用所选存储类型使用的剩余空间

使用 ZFS 作为根文件系统的系统,会通过存储在 512 MB EFI System Partition 上的 内核和 initrd 镜像启动。对于传统 BIOS 系统以及启用了 Secure Boot 的 EFI 系统, 会使用 GRUB;对于未启用 Secure Boot 的 EFI 系统,会使用 systemd-boot。两者 都会被安装并配置为指向 ESP。

在所有使用 GRUB 启动的系统上,BIOS 模式的 GRUB(--target i386-pc)会安装到 所有所选磁盘的 BIOS Boot Partition 上
[这些包括根文件系统位于 ext4xfs 的所有安装,以及非 EFI 系统上根文件系统位于 ZFS 的安装]

使用 proxmox-boot-tool 同步 ESP 内容

proxmox-boot-tool 是一个用于确保 EFI System Partition 内容正确配置并保持同步的 工具。它会将特定内核版本复制到所有 ESP,并配置相应的引导加载器,使其从格式化为 vfat 的 ESP 启动。在以 ZFS 作为根文件系统的场景中,这意味着可以在根池上使用 所有可选功能,而无需受限于 GRUB 中 ZFS 实现也支持的子集,也无需创建单独的小型 boot-pool
[使用 GRUB 从 ZFS 根文件系统启动 https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bookworm%20Root%20on%20ZFS.html]
.

在具备冗余的设置中,安装程序会在所有磁盘上划分 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 纳入 Proxmox VE 的内核更新同步机制,请使用:

# proxmox-boot-tool init /dev/sda2

或:

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

用于强制使用 GRUB 而不是 systemd-boot 初始化,例如用于支持 Secure Boot。

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

更新所有 ESP 上的配置

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

# proxmox-boot-tool refresh

(等同于在根文件系统为 ext4xfs 的系统上运行 update-grub)。

如果更改了内核命令行,或希望同步所有内核和 initrd,则需要执行此操作。

Note update-initramfsapt(必要时)都会自动触发刷新。
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

Automatically selected kernels:
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 System Partition(ESP)。
常用命令示例

以下命令可用于查看 ESP 同步状态、列出已选择的内核,并在更改后刷新 ESP 配置:

# proxmox-boot-tool status
# proxmox-boot-tool kernel list
# proxmox-boot-tool refresh

确定正在使用的引导加载器

screenshot/boot-grub.png

确定正在使用哪个引导加载器的最简单且最可靠的方法,是观察 Proxmox VE 节点的启动过程。

你会看到 GRUB 的蓝色界面,或者简洁的黑白 systemd-boot 界面。

screenshot/boot-systemdboot.png

从正在运行的系统判断引导加载器可能并非 100% 准确。最安全的方式是运行以下命令:

# efibootmgr -v

如果返回 EFI 变量不受支持的信息,则说明正在以 BIOS/Legacy 模式使用 GRUB。

如果输出包含类似以下内容的行,则说明正在以 UEFI 模式使用 GRUB。

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 Manual https://www.gnu.org/software/grub/manual/grub/grub.html]
.

配置

对 GRUB 配置的更改通过默认文件 /etc/default/grub/etc/default/grub.d 中的 配置片段完成。更改配置后,如需重新生成配置文件,请运行:
[使用 proxmox-boot-tool 的系统会在执行 update-grub 时调用 proxmox-boot-tool refresh。]

# update-grub

Systemd-boot

systemd-boot 是轻量级 EFI 引导加载器。它会直接从安装位置所在的 EFI Service Partition(ESP)读取内核和 initrd 镜像。直接从 ESP 加载内核的主要优势在于, 无需重新实现用于访问存储的驱动程序。在 Proxmox VE 中, proxmox-boot-tool 用于保持 ESP 上的配置同步。

配置

systemd-boot 通过 EFI System Partition(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 行。

完整的内核参数列表可在以下地址找到: https://www.kernel.org/doc/html/v<YOUR-KERNEL-VERSION>/admin-guide/kernel-parameters.html. 请将 <YOUR-KERNEL-VERSION> 替换为 major.minor 版本。例如,对于基于 6.5 版本的 内核,URL 为: https://www.kernel.org/doc/html/v6.5/admin-guide/kernel-parameters.html

可以通过查看 Web 界面(Node -> Summary)或运行以下命令来查找内核版本:

# uname -r

使用输出开头的前两个数字。

为下次启动覆盖内核版本

要选择当前默认内核之外的内核,可以采用以下方式之一:

  • 使用启动过程开始时显示的引导加载器菜单

  • 使用 proxmox-boot-tool 将系统一次性或永久(直到重置固定设置)pin 到某个内核版本。

这有助于规避较新内核版本与硬件之间的不兼容问题。

Note 应尽快移除此类固定设置,以便最新内核中的所有当前安全补丁也能应用到系统。

例如:若要永久选择版本 5.15.30-1-pve 用于启动,请运行:

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

也可以设置只在下一次系统启动时引导某个内核版本。例如,这可用于测试更新后的内核 是否已解决最初导致需要 pin 某个版本的问题:

# 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

Secure Boot

自 Proxmox VE 8.1 起,通过签名软件包以及与 proxmox-boot-tool 的集成,Secure Boot 可开箱即用。

Secure Boot 正常工作需要以下软件包。可以使用 proxmox-secure-boot-support 元软件包一次性安装它们。

  • shim-signed(由 Microsoft 签名的 shim 引导加载器)

  • shim-helpers-amd64-signed(由 Proxmox 签名的 fallback 引导加载器和 MOKManager)

  • grub-efi-amd64-signed(由 Proxmox 签名的 GRUB EFI 引导加载器)

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

开箱即用的引导加载器仅支持 GRUB,因为其他引导加载器当前不符合 Secure Boot 代码签名条件。

任何新的 Proxmox VE 安装都会自动包含上述所有软件包。

关于 Secure Boot 工作方式以及如何自定义设置的更多详情,请参见 我们的 wiki

将现有安装切换到 Secure Boot

Warning 如果操作不正确,在某些情况下这可能导致安装无法启动。重新安装主机时, 如果 Secure Boot 可用,会自动完成设置,无需额外交互。请确保你拥有可用且经过充分 测试的 Proxmox VE 主机备份!

如有需要,可以将现有 UEFI 安装切换到 Secure Boot,而无需从头重新安装 Proxmox VE。

首先,确保整个系统均为最新状态。然后安装 proxmox-secure-boot-support。GRUB 会自动创建通过默认 shim 启动所需的 EFI 启动项。

systemd-boot

如果使用 systemd-boot 作为引导加载器(参见 确定正在使用的引导加载器),则需要一些额外设置。 只有在 Proxmox VE 以 ZFS-on-root 方式安装时才会如此。

要检查后一种情况,请运行:

# findmnt /

如果主机确实使用 ZFS 作为根文件系统,则 FSTYPE 列应包含 zfs

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

接下来,必须找到合适的潜在 ESP(EFI system partition)。可以使用如下 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

在此示例中,分区 sda2sdb2 是目标。可以通过它们的 512M 大小以及 FSTYPEvfat 来识别;这里对应的是一个 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。这样,如果由于 任何原因无法在 Secure Boot 模式下使用 GRUB 启动,仍可在关闭 Secure Boot 后使用 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 如需注册自定义密钥,请参见配套的 Secure Boot wiki 页面

在 Secure Boot 下使用 DKMS/第三方模块

在启用了 Secure Boot 的系统上,内核会拒绝加载未由受信任密钥签名的模块。内核软件包 随附的默认模块集合使用嵌入在内核镜像中的临时密钥签名,该密钥受该特定版本内核镜像信任。

要加载其他模块,例如使用 DKMS 构建或手动构建的模块,需要用 Secure Boot 栈信任的 密钥对其签名。最简单的方式是使用 mokutil 将这些密钥注册为 Machine Owner Key (MOK)。

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 管理的自定义/第三方模块,但在这种情况下,需要手动完成 密钥/证书生成和签名步骤。

Kernel Samepage Merging (KSM)

Kernel Samepage Merging(KSM)是 Linux 内核提供的一项可选内存去重功能, 在 Proxmox VE 中默认启用。KSM 的工作方式是扫描一段物理内存页,查找内容相同的页面, 并识别映射到这些页面的虚拟页。如果发现相同页面,对应的虚拟页会被重新映射, 使它们都指向同一个物理页,并释放旧页面。虚拟页会被标记为“写时复制”, 因此对它们的任何写入都会写入新的内存区域,从而保持共享物理页不变。

KSM 的影响

在虚拟化环境中,KSM 可以优化内存使用,因为运行相似操作系统或工作负载的多台虚拟机 可能共享大量相同的内存页。

不过,虽然 KSM 能降低内存使用量,它也带来一些安全风险,因为它可能使虚拟机暴露于 侧信道攻击。研究表明,可以利用 KSM 的某些特性,通过同一主机上的另一台虚拟机推断 正在运行的虚拟机中的信息。

因此,如果使用 Proxmox VE 提供托管服务,应考虑禁用 KSM,以便为用户提供额外的安全性。 此外,还应检查所在国家或地区的法规,因为禁用 KSM 可能是法律要求。

禁用 KSM

要查看 KSM 是否处于活动状态,可以检查以下命令的输出:

# systemctl status ksmtuned

如果处于活动状态,可以使用以下命令立即禁用:

# systemctl disable --now ksmtuned

最后,要取消当前所有已合并页面的合并,请运行:

# echo 2 > /sys/kernel/mm/ksm/run

常用命令示例:

systemctl status ksmtuned
cat /sys/kernel/mm/ksm/run
cat /sys/kernel/mm/ksm/pages_shared