接下来的部分将重点讨论常见的虚拟化任务,并解释关于主机管理和维护的{pve}具体要求。

{pve} 基于 Debian GNU/Linux,并添加了额外的仓库来提供 {pve} 相关的包。这意味着包括安全更新和错误修正在内的Debian包的全部范围都是可用的。{pve} 提供了基于 Ubuntu 内核的自有 Linux 内核。它启用了所有必要的虚拟化和容器功能,并包括了 ZFS 以及若干额外的硬件驱动程序。

对于以下部分未涉及的其他主题,请参阅Debian文档。[Debian管理员手册](https://debian-handbook.info/get)可在线查阅,它提供了对Debian操作系统的全面介绍(参见xref:Hertzog13)。

软件包仓库

{pve} 使用 http://en.wikipedia.org/wiki/Advanced_Packaging_Tool [APT] 作为其包管理工具,就像任何其他基于Debian的系统一样。

'{pve} 会自动每天检查软件包更新。root@pam 用户会通过电子邮件收到有关可用更新的通知。从图形用户界面,可以使用“变更日志”按钮来查看有关所选更新的更多详细信息。'

仓库在 {pve} 中

版本库是一系列软件包的集合,它们可以用来安装新软件,但也是获取新更新的重要途径。

Note
您需要有效的Debian和Proxmox软件源才能获得最新的安全更新、错误修复和新功能。

APT仓库在文件`/etc/apt/sources.list`中定义,并在`/etc/apt/sources.list.d/中放置的.list`文件中定义。

代码仓库管理

自从Proxmox VE 7起,您可以在网页界面中检查仓库状态。节点摘要面板显示高层次的状态概览,而单独的“仓库”面板则显示深入的状态并列出所有配置的仓库。

基本的仓库管理,例如激活或停用一个仓库,也是受支持的。

源列表

在一个 sources.list 文件中,每一行定义了一个包仓库。首选的源必须放在最前面。空行会被忽略。行中的 # 字符将该行剩余部分标记为注释。通过运行 apt-get update 获取仓库中的可用包。更新可以直接使用 apt-get 安装,或通过图形用户界面(GUI)(节点 → 更新)进行安装。

文件 `/etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
deb http://deb.debian.org/debian bookworm-updates main contrib

# security updates
deb http://security.debian.org/debian-security bookworm-security main contrib

{pve} 提供了三个不同的包仓库。

{pve} 企业代码库

这是推荐的仓库,适用于所有 {pve} 订阅用户。它包含最稳定的包,并且适合于生产环境使用。pve-enterprise 仓库默认是启用的:

文件 `/etc/apt/sources.list.d/pve-enterprise.list
deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise

请注意,您需要一个有效的订阅密钥才能访问`pve-enterprise`仓库。我们提供不同的支持级别,您可以在{pricing-url}处查看更多详情。

Note
您可以通过在上面的行前加上`#`(在行的开头)来注释掉这行代码,以此来禁用这个仓库。如果您的主机没有订阅密钥,这能防止错误信息的出现。在这种情况下,请配置`pve-no-subscription`仓库。

{pve} 无订阅存储库

正如名称所示,您不需要订阅密钥就可以访问此存储库。它可用于测试和非生产用途。不建议在生产服务器上使用这些包,因为这些包并不总是经过严格的测试和验证。

我们建议在 /etc/apt/sources.list 中配置这个仓库。

文件 `/etc/apt/sources.list
deb http://ftp.debian.org/debian bookworm main contrib
deb http://ftp.debian.org/debian bookworm-updates main contrib

# Proxmox VE pve-no-subscription repository provided by proxmox.com,
# NOT recommended for production use
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription

# security updates
deb http://security.debian.org/debian-security bookworm-security main contrib

{pve} 测试仓库

这个仓库包含最新的软件包,主要供开发者测试新功能使用。要配置它,请将以下行添加到 /etc/apt/sources.list 文件中:

pvetest`的`sources.list`条目
deb http://download.proxmox.com/debian/pve bookworm pvetest
Warning
pvetest` 存储库应该(顾名思义)只用于测试新功能或修复缺陷。

Ceph礁石企业仓库

这个仓库包含企业级{pve} Ceph 18.2 Reef 版本的软件包。它们适合用于生产环境。如果你在{pve}上运行Ceph客户端或完整的Ceph集群,请使用这个仓库。

File `/etc/apt/sources.list.d/ceph.list
deb https://enterprise.proxmox.com/debian/ceph-reef bookworm enterprise

Ceph礁石无订阅仓库

这个Ceph仓库包含了Ceph 18.2 Reef版本的软件包,在它们被转移到企业仓库之前以及在它们位于测试仓库之后。

Note
建议在生产机器上使用企业仓库。
File `/etc/apt/sources.list.d/ceph.list
deb http://download.proxmox.com/debian/ceph-reef bookworm no-subscription

Ceph礁测试库

这个Ceph仓库包含了Ceph 18.2 Reef版本的包,在它们被转移到主仓库之前。它用于在{pve}上测试新的Ceph版本。

File `/etc/apt/sources.list.d/ceph.list
deb http://download.proxmox.com/debian/ceph-reef bookworm test

Ceph Quincy 企业版仓库

这个仓库包含企业级 {pve} Ceph Quincy 包。它们适合用于生产环境。如果你在 {pve} 上运行 Ceph 客户端或完整的 Ceph 集群,请使用这个仓库。

File `/etc/apt/sources.list.d/ceph.list
deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise

Ceph Quincy 无订阅仓库

这个Ceph仓库包含了Ceph Quincy包,在它们被移动到企业仓库之前以及它们在测试仓库之后。

Note
建议在生产机器上使用企业仓库。
File `/etc/apt/sources.list.d/ceph.list
deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription

Ceph Quincy 测试库

这个Ceph仓库包含了Ceph Quincy包,在它们被转移到主仓库之前。它用于在{pve}上测试新的Ceph发布版本。

File `/etc/apt/sources.list.d/ceph.list
deb http://download.proxmox.com/debian/ceph-quincy bookworm test

旧的Ceph仓库

{pve} 8不支持Ceph Pacific、Ceph Octopus或更早版本的超融合设置。对于这些版本,你需要先将Ceph升级到较新的版本,然后再升级到Proxmox VE 8。

Debian固件仓库

从 Debian Bookworm ({pve} 8) 开始,非自由固件(根据https://www.debian.org/social_contract#guidelines[DFSG]的定义)已被移至新创建的 Debian 仓库组件 non-free-firmware 中。

如果您想要设置早期操作系统微码更新或需要额外的运行时固件文件,而这些文件并未包含在预安装的软件包`pve-firmware`中,请启用此存储库。

为了能够从这个组件安装包,运行 editor /etc/apt/sources.list,将 non-free-firmware 追加到每个 .debian.org 仓库行的末尾然后运行 apt update

安全软件包管理器

存储库中的’Release’文件已使用GnuPG签名。APT使用这些签名来验证所有包都来自可信来源。

如果你从官方ISO镜像安装{pve},验证密钥已经安装好了。

如果你在Debian上安装{pve},请用以下命令下载并安装密钥:

# wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg

随后使用`sha512sum`命令行工具验证校验和:

# sha512sum /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg
7da6fe34168adc6e479327ba517796d4702fa2f8b4f0a9833f5ea6e6b48f6507a6da403a274fe201595edc86a84463d50383d07f64bdde2e3658108db7d6dc87 /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg

或者是 md5sum 命令行工具:

# md5sum /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg
41558dc019ef90bd0f6067644a51cf5b /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg

系统软件更新

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

# apt-get update
# apt-get dist-upgrade
Note
APT包管理系统非常灵活,并提供了许多功能,参见`man apt-get`,或[Hertzog13]了解更多信息。
Tip
定期更新对于获取最新的补丁和相关的安全修复是必不可少的。主要的系统升级将在{forum}里宣布。

固件更新

这一章节的固件更新应当在在裸机服务器上运行{pve}时应用。至于在客户机内配置固件更新是否合适,例如在使用设备透传时,这在很大程度上取决于你的设置,并因此超出了讨论范围。

除了常规软件更新外,固件更新对于可靠和安全的运行也很重要。

在获取和应用固件更新时,建议组合使用多种可用选项,以尽早或者根本获得更新。

术语固件通常在语言上分为微代码(用于CPU)和固件(用于其他设备)。

持久固件

这一部分适用于所有设备。更新的微码,通常包含在BIOS/UEFI更新中,存储在主板上,而其他固件则存储在各自的设备上。这种持久化方法对CPU尤其重要,因为它使得在启动时尽早常规加载更新的微码成为可能。

Caution
在进行一些更新,比如BIOS/UEFI或储存控制器时,设备配置可能会被重置。请仔细遵循供应商的指示,并备份当前配置。

请检查您的供应商提供哪些更新方法。

Tip
如果更新指令需要重启主机,请确保这能够安全完成。另请参见节点维护

运行时固件文件

这种方法将固件存储在{pve}操作系统上,如果设备的持久化固件较旧,它将把固件传递给设备。它支持诸如网络和图形卡的设备,但不支持依赖持久化固件的设备,如主板和硬盘。

在{pve}中,`pve-firmware`软件包已经是默认安装的。因此,通过正常的系统更新(APT),常用硬件的固件会自动保持最新。

还有一个额外的Debian固件仓库存在,但默认情况下并没有配置。

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

CPU 微码更新

微码更新旨在修复发现的安全漏洞和其他严重的CPU错误。虽然CPU性能可能会受到影响,但打了补丁的微码通常仍然比未打补丁的微码更高效,因为在未打补丁的情况下核心自身必须进行缓解措施。根据CPU类型的不同,可能无法在不知情地运行CPU于不安全状态的情况下,再次达到有缺陷的工厂状态时的性能结果。

为了获取当前CPU漏洞及其缓解措施的概览,请运行 lscpu。如果{pve}主机是最新的,它的版本不是已过维护生命周期,并且至少在最后一次内核更新之后已经重启过,那么当前已知的实际漏洞才会显示出来。

除了通过persistent BIOS/UEFI更新推荐的微码更新外,还有一种独立的方法,即通过*早期操作系统微码更新*。这种方法使用方便,当主板供应商不再提供BIOS/UEFI更新时也非常有帮助。无论使用哪种方法,应用微码更新始终需要重新启动。

设置早期操作系统微码更新

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

  1. 启用Debian固件仓库

  2. 获取最新可用的包 apt update(或使用网页界面,在节点 → 更新下)

  3. 安装特定于CPU厂商的微码包:

    • For Intel CPUs: `apt install intel-microcode

    • 对于AMD CPU:`apt install amd64-microcode

  4. 重启 {pve} 主机

任何将来的微码更新也将需要重启才能加载。

微码版本

为了比较或调试目的获取当前运行的微代码版本:

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

一个微代码包含了对许多不同CPU的更新。但是专门针对您的CPU的更新可能不会经常出现。因此,仅仅查看包的日期并不能告诉您公司实际上何时为您特定的CPU发布了更新。

如果您安装了新的微代码包并重启了 {pve} 主机,而这个新的微代码版本比CPU内置的版本和主板固件中的版本都要新,您会在系统日志中看到一条信息,提示“微代码提前更新”。

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

故障排除

为了调试目的,可以通过以下方式临时禁用在系统启动时定期应用的早期操作系统微代码更新:

  1. 确保主机可以安全地重新启动 safely

  2. 重启主机以进入GRUB菜单(如果它被隐藏了,则按住`SHIFT`键)

  3. 在所需的 {pve} 启动项上按下 E

  4. 转到以 linux 开头的那一行,并以一个空格分隔,附加上 dis_ucode_ldr

  5. 按下 CTRL-X 可以在不更新早期操作系统微码的情况下启动此次操作

如果怀疑问题与最近的微码更新相关联,应该考虑对包进行降级,而不是移除包(apt purge <intel-microcode|amd64-microcode>)。否则,即便更新的微码可以无问题运行,也可能加载了过时的微码。

如果Debian仓库中有较早版本的微码包可用,如本示例所示,则可能进行降级。

# apt list -a intel-microcode
Listing... Done
intel-microcode/stable-security,now 3.20230808.1~deb12u1 amd64 [installed]
intel-microcode/stable 3.20230512.1 amd64
# apt install intel-microcode=3.202305*
...
选定的版本 '3.20230512.1' (Debian:12.1/stable [amd64]) 对应 'intel-microcode'
...
dpkg: 警告: 从 3.20230808.1~deb12u1 降级到 3.20230512.1
...
intel-microcode: 下一次启动时将更新微码
...

请再次确保主机可以安全地重启,具体方法请参考ha_manager_node_maintenance[safely]。为了应用可能包含在CPU类型对应的微码包中的较旧微码,请现在重启。

Tip

保留降级的包一段时间,并在以后尝试更多的新版本是有道理的。即使将来包的版本是相同的,系统更新可能已经在此期间解决了所遇到的问题。

# apt-mark hold intel-microcode
intel-microcode set on hold.
# apt-mark unhold intel-microcode
# apt update
# apt upgrade

网络配置

'{pve}正在使用Linux网络栈。这为如何在{pve}节点上设置网络提供了很多灵活性。配置既可以通过GUI完成,也可以通过手动编辑文件`/etc/network/interfaces`来完成,该文件包含了整个网络配置。‘interfaces(5)`手册页面包含了完整的格式描述。所有{pve}工具都努力保留直接用户修改的内容,但使用GUI仍然是首选,因为它可以保护你免受错误。

要将客户机连接到底层的物理网络,需要一个’vmbr’接口。它们是一种Linux桥接,可以被视为一种虚拟交换机,客户机和物理接口都连接到这个交换机上。本节提供一些例子,展示如何设置网络,以适应不同的用例,比如使用绑定实现冗余、VLAN路由以及NAT设置。

软件定义网络是{pve}集群中更复杂的虚拟网络的一个选项。

Warning
如果不确定的话,不鼓励使用传统的Debian工具`ifup`和`ifdown`,因为它们存在一些陷阱,如在执行`ifdown vmbrX`时中断所有客户端流量,但在稍后对同一个桥执行`ifup`时不会重新连接这些客户端。

应用网络更改

{pve}并不直接将更改写入`/etc/network/interfaces`。相反,我们会将更改写入一个名为`/etc/network/interfaces.new`的临时文件中,这样您就可以一次性进行许多相关的更改。这也允许在应用更改之前确保您的更改是正确的,因为错误的网络配置可能会使节点无法访问。

使用ifupdown2的实时重载网络

使用推荐的 ifupdown2 包(自 {pve} 7.0 起的新安装默认值),可以在不重启的情况下应用网络配置更改。如果你通过GUI更改网络配置,你可以点击 Apply Configuration 按钮。这将会把更改从暂存的 interfaces.new 文件转移到 /etc/network/interfaces,并实时应用它们。

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

Note
如果您在Debian上安装了 {pve},或者从旧版本的 {pve} 升级到 {pve} 7.0,请确保安装了 ifupdown2:`apt install ifupdown2

重启节点以应用更改

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

命名约定

我们目前使用以下命名规范来为设备命名:

  • 以太网设备:en*,systemd 网络接口命名方案。这种命名方案是 自版本5.0起用于新的{pve}安装。

  • 以太网设备:eth[N],其中 0 ≤ N (eth0eth1、…​)。这种命名方案用于在 5.0 版本之前安装的 {pve} 主机。升级到 5.0 版本时,这些名称将被保持原样。

  • 桥接名称:vmbr[N],其中 0 ≤ N ≤ 4094 (vmbr0 - vmbr4094

  • 债券:bond[N],其中 0 ≤ N(bond0, bond1, …​)

  • VLAN:只需要在设备名称后加上VLAN编号,中间用一个英文句号隔开(例如 eno1.50bond1.30)。

这使得调试网络问题更加容易,因为设备名称暗示了设备类型。

Systemd 网络接口名称

Systemd定义了一个带版本的网络设备命名方案。该方案对以太网网络设备使用两个字符的前缀`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` — 是第一个板载网络接口卡

  • enp3s0f1` — 是PCI总线3,插槽0上网络接口卡的功能1。

要获取可能的设备名称模式的完整列表,请参阅https://manpages.debian.org/stable/systemd/systemd.net-naming-scheme.7.en.html [systemd.net-naming-scheme(7)手册页]。

systemd的新版本可能会定义网络设备命名方案的新版本,并默认使用它。因此,在升级到更新的systemd版本时,例如在进行主要的{pve}升级期间,可能会更改网络设备的名称,并需要调整网络配置。为了避免因新版本的命名方案而导致名称更改,您可以手动固定特定的命名方案版本(见下文)。

然而,即使固定了命名方案的版本,由于内核或驱动程序的更新,网络设备的名称仍然可能会发生变化。为了完全避免特定网络设备名字的变更,您可以使用链接文件手动覆盖其名称(见下文以下)。

有关网络接口名称的更多信息,请参见 https://systemd.io/PREDICTABLE_INTERFACE_NAMES/ [可预测的网络接口名称]。

固定特定的命名方案版本

您可以通过在内核命令行中添加`net.naming-scheme=<version>`参数来固定网络设备命名方案的特定版本。有关命名方案版本的列表,请参见https://manpages.debian.org/stable/systemd/systemd.net-naming-scheme.7.en.html[systemd.net-naming-scheme(7)手册页面]。

例如,要固定版本`v252`,这是全新的{pve} 8.0安装的最新命名方案版本,请添加以下内核命令行参数:

net.naming-scheme=v252

请参见本节来编辑内核命令行。您需要重启系统以使更改生效。

覆盖网络设备名称

你可以通过使用自定义的https://manpages.debian.org/stable/udev/systemd.link.5.en.html[systemd.link文件]手动为特定网络设备指定一个名称。这将覆盖根据最新的网络设备命名方案所赋予的名称。通过这种方式,你可以避免因内核更新、驱动程序更新或命名方案的新版本而导致的命名更改。

自定义链接文件应该放置在 /etc/systemd/network/ 目录下,并且命名为 <n>-<id>.link,其中 n 是一个小于 99 的优先级数值,id 是某种标识符。一个链接文件包含两个部分:[Match] 部分决定了该文件将适用于哪些接口;[Link] 部分决定了这些接口应该如何配置,包含它们的命名。

要为特定网络设备分配一个名称,您需要一种方法在 [Match] 部分中唯一并永久地标识该设备。一种可能性是使用 MACAddress 选项匹配设备的 MAC 地址,因为它不太可能发生变化。然后,您可以在 [Link] 部分使用 Name 选项为其分配一个名称。

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

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

[Link]
Name=enwan0

不要忘记调整`/etc/network/interfaces`文件以使用新的名称。你需要重启节点以使更改生效。

Note
建议使用以`en`或`eth`开头的名称来指定网络接口,这样{pve}就能将其识别为物理网络设备,进而可以通过图形用户界面进行配置。此外,你应该确保这个名称未来不会与其他接口名称冲突。一种可能性是指定一个不与systemd用于网络接口的任何名称模式相匹配的名称(参见上文:见上文),例如上例中的`enwan0`。

有关链接文件的更多信息,请参见[Systemd.link(5)手册页面](https://manpages.debian.org/stable/udev/systemd.link.5.en.html)。

选择网络配置

根据您当前的网络组织和资源,您可以选择桥接、路由或伪装网络设置。

在私有局域网中的{pve}服务器,使用外部网关以连接至互联网

在这种情况下,桥接 模型最为合理,这也是新的 {pve} 安装中的默认模式。您的每个客户系统都将有一个虚拟接口连接到 {pve} 桥。这在效果上类似于将客户网络卡直接连接到局域网上的新交换机,{pve} 主机扮演着交换机的角色。

在托管服务提供商处的{pve}服务器,拥有用于客户的公共IP范围。

对于这个设置,您可以根据提供商的允许使用*桥接*或*路由*模式。

托管服务提供商的{pve}服务器,拥有一个单独的公网IP地址。

在那种情况下,为您的客户系统获取外部网络访问的唯一方法是使用*伪装*(Masquerading)。对于对您的客户的入站网络访问,您需要配置*端口转发*(Port Forwarding)。

为了进一步的灵活性,您可以配置VLANs (IEEE 802.1q)和网络绑定,也被称为“链路聚合”。这样就可以构建复杂且灵活的虚拟网络。

使用桥接的默认配置

桥接就像是用软件实现的物理网络交换机。所有虚拟客户机都可以共享一个桥接,或者你可以创建多个桥接来分隔网络域。每个宿主机最多可以有4094个桥接。

安装程序创建了一个名为`vmbr0`的单个桥接,它连接到第一块以太网卡。相应的配置在`/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地址。

一个常见的情况是,你拥有一个公共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

伪装(NAT)与 `iptables

伪装允许只有私有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
在一些启用了防火墙的伪装设置中,可能需要为出站连接配置连接跟踪区域。否则,由于防火墙可能会优先选择虚拟机桥接的 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 绑定

绑定(也称为NIC teaming或Link Aggregation)是一种将多个网络接口卡(NIC)绑定到单个网络设备的技术。可以通过它实现不同的目标,如使网络具有容错能力、提升性能或同时实现这两者。

高速硬件如光纤通道及相关的交换硬件可能非常昂贵。通过进行链路聚合,两个网络接口卡(NICs)可以表现为一个逻辑接口,从而实现双倍速度。这是一个原生的Linux内核特性,大多数交换机都支持它。如果你的节点有多个以太网端口,你可以通过将网络电缆连接到不同的交换机来分散故障点,而且在出现网络问题时,绑定连接将实现到另一根电缆的故障转移。

聚合链接可以减少实时迁移的延迟并提高数据在Proxmox VE集群节点之间复制的速度。

有7种键合模式:

  • 循环轮询(balance-rr): 按照顺序从第一个可用的网络接口(NIC)从站传输网络包,直至最后一个。这种模式提供了负载均衡和容错能力。

  • 主动-备份 (active-backup)模式: 在绑定中只有一个NIC从设备处于活动状态。仅当活动从设备失败时,另一个从设备才会变成活动状态。单个逻辑绑定接口的MAC地址在网络上仅通过一个NIC(端口)外部可见,以避免在网络交换中产生失真。这种模式提供了容错能力。

  • XOR (balance-xor): 根据 [(源 MAC 地址与目的 MAC 地址的异或值) 模 NIC 从设备计数] 传输网络数据包。这种模式为每个目标 MAC 地址选择相同的 NIC 从设备。该模式提供了负载均衡和容错能力。

  • 广播 (broadcast): 在所有从属网络接口上发送网络数据包。这种模式提供了故障容错能力。

  • *IEEE 802.3ad 动态链路聚合(802.3ad)(LACP):*创建共享相同速度和双工设置的聚合组。根据802.3ad规范,利用活动聚合器组中的所有从属网络接口。

  • 自适应传输负载均衡(balance-tlb): Linux绑定驱动模式,不需要任何特殊的网络交换机支持。根据每个网络接口从设备当前的负载(相对于速度计算)分配出站网络数据包流量。入站流量由当前指定的从设备网络接口接收。如果这个接收从设备失败,另一个从设备接管失败的接收从设备的MAC地址。

  • 适应性负载均衡(balance-alb):包括了平衡传输负载均衡(balance-tlb)以及用于IPv4流量的接收负载均衡(rlb),而且不需要任何特殊的网络交换机支持。接收负载均衡是通过ARP协商来实现的。绑定驱动程序截取本地系统发送出去的ARP应答,在其传输过程中重写源硬件地址,用单一逻辑绑定接口中的一个NIC从设备的唯一硬件地址来替换,以此让不同的网络对等点为其网络数据包流量使用不同的MAC地址。

如果您的交换机支持LACP(IEEE 802.3ad)协议,那么我们推荐使用相应的绑定模式(802.3ad)。否则,您通常应该使用活动-备份模式。

对于集群网络(Corosync),我们推荐使用多个网络进行配置。Corosync不需要网络冗余的绑定,因为如果一个网络变得不可用,它可以自己在网络之间切换。

以下债券配置可以用作分布式/共享存储网络。其优势在于您将获得更高的速度,且网络将具有容错能力。

示例:使用具有固定IP地址的绑定
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

另一种可能性是直接将bond作为桥接端口使用。这可以用来使来宾网络具有容错能力。

示例:使用一个债券作为桥接端口
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

虚拟局域网(VLAN)是在网络的第二层被划分和隔离的广播域。因此,在一个物理网络中可以拥有多个网络(多达4096个),它们彼此相互独立。

每个VLAN网络通过一个通常称为“标签”的数字来识别。然后网络数据包会被“标记”以识别它们属于哪一个虚拟网络。

VLAN用于访客网络

{pve} 默认支持此设置。您可以在创建虚拟机时指定VLAN标签。VLAN标签是客户端网络配置的一部分。网络层支持不同的模式来实现VLAN,具体取决于桥接配置:

  • ''Linux桥接的VLAN透传:在这种情况下,每个客户机的虚拟网卡都会被分配一个VLAN标签,这个标签由Linux桥接透明支持。Trunk模式也是可能的,但这需要在客户机中进行配置。''

  • 在Linux桥接中的“传统”VLAN:与VLAN识别方法相比,这种方法并不透明,并为每个VLAN创建一个带有关联桥接的VLAN设备。也就是说,举例来说,为VLAN 5创建一个客户端,将会创建两个接口eno1.5和vmbr0v5,并且这些接口将保持存在直到重启发生。

  • Open vSwitch VLAN: 这种模式使用了OVS VLAN特性。

  • 既定客户端配置的VLAN:VLAN在客户端内部分配。在这种情况下,设置完全在客户端内部完成,无法从外部受到影响。其优势在于,您可以在单个虚拟网络接口卡上使用不止一个VLAN。

主机上的VLAN

要允许主机与隔离网络进行通信,可以对任何网络设备(NIC、Bond、Bridge)应用VLAN标签。通常,你应该在与物理网卡之间抽象层次最少的接口上配置VLAN。

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

示例:使用 VLAN 5 作为 {pve} 管理 IP,采用传统 Linux 桥接方式
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 5作为具有VLAN感知的Linux桥的{pve}管理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

下一个例子是相同的设置,但是使用了一个债券来使这个网络安全可靠。

示例:使用传统的Linux桥将VLAN 5与bond0结合起来,用于{pve}管理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

{pve} 在所有环境中都能正确工作,无论是否部署了 IPv6。我们建议保留所有提供的默认设置。

如果您仍然需要在节点上禁用对IPv6的支持,请通过创建一个合适的`sysctl.conf (5)片段文件并设置适当的https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt[sysctls]来完成,例如添加/etc/sysctl.d/disable-ipv6.conf`文件,并填充以下内容:

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

这种方法比在内核命令行上禁用加载IPv6模块更受欢迎。可以参考https://www.kernel.org/doc/Documentation/networking/ipv6.rst上的文档。

在桥接上禁用MAC地址学习

默认情况下,桥接上启用了MAC学习,以确保虚拟客户及其网络的顺畅体验。

但在某些环境中,这可能是不受欢迎的。从 {pve} 7.3 版本开始,您可以通过在 /etc/network/interfaces 文件中的桥接配置上设置 bridge-disable-mac-learning 1 来禁用桥接上的 MAC 地址学习,例如:

# ...

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

一旦启用,{pve} 将手动将 VM 和容器配置的 MAC 地址添加到桥接的转发数据库中,以确保客户端仍然可以使用网络 - 但前提是他们使用的是他们实际的 MAC 地址。

时间同步

{pve} 集群堆栈本身非常依赖于所有节点都有精确同步的时间这一事实。如果所有节点上的本地时间没有同步,其他一些组件,比如 Ceph,也将无法正常工作。

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

Important
如果你将系统升级到 {pve} 7, 建议你手动安装 chronyntpopenntpd 中的任何一个。

使用自定义NTP服务器

在某些情况下,可能希望使用非默认的NTP服务器。例如,如果您的 {pve} 节点由于严格的防火墙规则而无法访问公共互联网,您需要设置本地NTP服务器,并告知NTP守护程序使用它们。

对于使用chrony的系统:

指定`chrony`应该在`/etc/chrony/chrony.conf`中使用哪些服务器:

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

重新启动 chrony

systemctl restart chronyd

检查日志以确认新配置的NTP服务器是否正在被使用:

journalctl --since -1h -u chrony

...
Aug 26 13:00:09 node1 systemd[1]: 已启动 Chrony,一个NTP客户端/服务器。
Aug 26 13:00:15 node1 chronyd[4873]: 已选择源 10.0.0.1 (ntp1.example.com)
Aug 26 13:00:15 node1 chronyd[4873]: 系统时钟TAI偏移设置为37秒
...

对于使用systemd-timesyncd的系统:

指定 /etc/systemd/timesyncd.confsystemd-timesyncd 应使用哪些服务器:

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

然后,重新启动同步服务(systemctl restart systemd-timesyncd),并通过检查日志(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
...

外部指标服务器

在{pve}中,你可以定义外部指标服务器,这些服务器将定期接收关于你的主机、虚拟客户机和存储的各种统计信息。

目前支持的有:

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

石墨服务器配置

默认端口设置为 2003,默认的 graphite 路径是 proxmox

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

您也可以配置插件以使用TCP。为了不阻塞重要的`pvestatd`统计收集守护进程,在遇到网络问题时需要设置一个超时以应对。

Influxdb插件配置

{pve} 通过 UDP 发送数据,因此必须对 influxdb 服务器进行配置以适应此方式。如有必要,此处也可以配置 MTU(最大传输单元)。

这是一个influxdb配置的示例(在您的influxdb服务器上):

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

根据这种配置,你的服务器会监听8089端口上的所有IP地址,并且将数据写入*proxmox*数据库。

作为另一种选择,可以配置插件使用InfluxDB 2.x的http(s) API。InfluxDB 1.8.x 包含了一个向前兼容的 API 端点,用于这个 v2 API。

要使用它,请将’influxdbproto’设置为’http’或’https'(根据您的配置而定)。默认情况下,{pve}使用组织’proxmox’和桶/数据库’proxmox'(它们可以分别通过配置’organization’和’bucket’来设置)。

因为InfluxDB的v2 API只能通过认证使用,你需要生成一个可以向正确存储桶写入的令牌,并进行设置。

在1.8.x的v2兼容API中,如果需要,可以使用’user:password’作为令牌,并且可以省略’organization',因为在InfluxDB 1.x中没有意义。

你也可以通过’timeout’设置来设定HTTP超时时间(默认为1秒),以及通过’max-body-size’设置来设定最大批次大小(默认25000000字节),这对应于具有相同名称的InfluxDB设置。

磁盘健康监控

虽然推荐使用健壮且有冗余的存储,但监控本地磁盘的健康状况也是非常有帮助的。

从{pve} 4.3开始,smartmontools软件包[1]被安装并需要。这是一套用于监控和控制本地硬盘的S.M.A.R.T.系统的工具。

你可以通过发出以下命令来获取磁盘的状态:

# smartctl -a /dev/sdX

其中 /dev/sdX 是你的一个本地磁盘的路径。

如果输出显示:

SMART支持是:禁用

你可以用这个命令来启用它:

# smartctl -s on /dev/sdX

关于如何使用smartctl的更多信息,请参见`man smartctl`。

默认情况下,smartmontools守护进程smartd是活跃且已启用的,并且每30分钟扫描一次位于/dev/sdX和/dev/hdX下的磁盘,以检查错误和警告,如果检测到问题,它会向root发送一封电子邮件。

关于如何配置smartd的更多信息,请参阅`man smartd`和`man smartd.conf`。

如果您使用具有硬件RAID控制器的硬盘,很可能有工具可以监控RAID阵列中的硬盘和阵列本身。有关此信息,请参阅您RAID控制器的供应商。

逻辑卷管理器(LVM)

大多数人会将 {pve} 直接安装在本地磁盘上。{pve} 安装光盘提供了几种本地磁盘管理选项,当前默认设置使用 LVM。安装程序允许你选择单个磁盘进行此类设置,并将该磁盘用作卷组(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)内分配了三个逻辑卷(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

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

交换

交换分区

数据

这个卷使用了LVM-thin,用于存储虚拟机映像。LVM-thin更适合这项任务,因为它为快照和克隆提供了高效的支持。

对于4.1及以前版本的{pve},安装程序会创建一个名为`‘data’'的标准逻辑卷,它被挂载在`/var/lib/vz`路径下。

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

硬件

我们强烈建议在此类设置中使用具有电池备份单元(BBU)的硬件RAID控制器。这样可以提高性能,提供冗余,并且使硬盘更换更容易(支持热插拔)。

LVM本身不需要任何特殊硬件,且内存需求非常低。

引导加载程序

我们默认安装了两个引导加载程序。第一个分区包含标准的GRUB引导加载程序。第二个分区是一个EFI系统分区(ESP),这使得在EFI系统上启动成为可能,并且可以从用户空间应用持久的固件更新。

创建卷组

假设我们有一个空的硬盘`/dev/sdb`,我们想在其上创建一个名为`‘vmdata’'的卷组。

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

首先创建一个分区。

sgdisk -N 1 /dev/sdb

创建一个物理卷(PV),不需要确认并且设置250K的元数据大小。

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

在`/dev/sdb1`上创建一个名为`‘vmdata’'的卷组。

# vgcreate vmdata /dev/sdb1

/var/lib/vz 创建一个额外的逻辑卷

这可以通过创建一个新的薄卷(LV)来轻松完成。

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

一个真实世界的例子:

lvcreate -n vz -V 10G pve/data

现在必须在逻辑卷上创建一个文件系统。

mkfs.ext4 /dev/pve/vz

最后这必须被安装。

Warning
请确保`/var/lib/vz`是空的。在默认安装中它不是空的。

要使它始终可访问,请将以下行添加到`/etc/fstab`中。

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

调整细分池的大小

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

lvresize --size +<size[\M,G,T]> --poolmetadatasize +<size[\M,G]> <VG>/<LVThin_pool>

Note
当扩展数据池时,元数据池也必须被扩展。

创建一个LVM-thin池

必须在卷组上创建一个薄池。如何创建卷组,请参见LVM部分。

lvcreate -L 80G -T -n vmstore vmdata

在Linux上的ZFS

ZFS是由Sun Microsystems设计的一个结合了文件系统和逻辑卷管理器的系统。从{pve} 3.4开始,ZFS文件系统的原生Linux内核移植版被引入作为可选的文件系统,也可以作为根文件系统的一个额外选择。没有必要手动编译ZFS模块 - 所有的包都已包含在内。

通过使用ZFS,即使在低预算硬件上也能够实现最大化的企业功能,通过利用SSD缓存或甚至仅使用SSD,还可以获得高性能的系统。ZFS可以用适度的CPU和内存负载以及简单的管理,来替代成本高昂的硬件RAID卡。

ZFS的一般优势
  • 通过{pve} GUI和CLI轻松配置和管理。

  • 可靠

  • 防护数据损坏

  • 文件系统级别的数据压缩

  • 快照

  • 写时复制克隆

  • 不同的RAID级别:RAID0, RAID1, RAID10, RAIDZ-1, RAIDZ-2, RAIDZ-3, dRAID, dRAID2, dRAID3

  • 可以使用SSD作为缓存

  • 自愈

  • 持续完整性检查

  • 设计用于高存储容量

  • 异步复制通过网络

  • 开源

  • 加密

  • 省略号`…​`在中英文中均可用作表示省略或暂停,所以这里不需要翻译。

硬件

ZFS严重依赖于内存,因此你至少需要8GB的内存才能开始。在实践中,根据你的硬件/预算尽可能多地使用内存。为了防止数据损坏,我们推荐使用高质量的ECC内存。

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

Important
不要在具有自己的缓存管理的硬件RAID控制器之上使用ZFS。ZFS需要直接与磁盘通信。使用HBA适配器或者像是刷成“IT”模式的LSI控制器会更合适。

如果您正在尝试在虚拟机(嵌套虚拟化)内安装 {pve},不要使用 virtio 作为该虚拟机的磁盘,因为它们不被ZFS支持。请改用IDE或SCSI(也适用于`virtio` SCSI控制器类型)。

安装为根文件系统

当你使用 {pve} 安装器进行安装时,可以为根文件系统选择ZFS。你需要在安装时选择RAID类型:

RAID0

也被称为“条带化”。这种卷的容量是所有磁盘容量的总和。但是RAID0没有增加任何冗余,因此单个驱动器的故障将使卷不可用。

RAID1

也被称为“镜像”。数据被一致地写入所有磁盘。这种模式至少需要2个相同大小的磁盘。最终的容量是单个磁盘的容量。

RAID10

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

RAIDZ-1

RAID-5变种,单一奇偶校验。至少需要3个磁盘。

RAIDZ-2

RAID-5的一个变体,双重奇偶校验。至少需要4个磁盘。

RAIDZ-3

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

安装程序会自动对磁盘进行分区,创建一个名为 rpool 的ZFS池,并在ZFS子卷 rpool/ROOT/pve-1 上安装根文件系统。

创建了一个名为`rpool/data`的子卷,用于存储虚拟机映像。为了使用{pve}工具,安装程序在`/etc/pve/storage.cfg`中创建了以下配置项:

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

安装后,您可以使用 zpool 命令查看您的ZFS池状态:

# 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

错误:没有已知的数据错误

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池的布局时需要考虑一些因素。ZFS池的基本构建单元是虚拟设备,或称为`vdev`。池中的所有vdev都被平等使用,并且数据在它们之间分条存储(RAID0)。有关vdevs的更多详细信息,请检查`zpoolconcepts(7)`手册页。

性能

每种`vdev`类型的性能表现各不相同。两个感兴趣的参数是IOPS(每秒输入/输出操作数)和可以写入或读取数据的带宽。

一个"镜像" vdev(RAID1)在写入数据时的表现大致与单个磁盘相当。而在读取数据时,性能将随镜像中磁盘数量的增加而线性扩展。

一个常见的情况是拥有4个磁盘。当将其设置为2个镜像vdevs(RAID10)时,池在IOPS和带宽方面的写入特性将与两个单独磁盘相同。对于读取操作,它将类似于4个单独磁盘。

任何冗余级别的“RAIDZ”在IOPS表现上大致相当于单个硬盘,但具有大量的带宽。具体的带宽取决于RAIDZ虚拟设备的大小和冗余级别。

一个’dRAID’池应该与等效的’RAIDZ’池的性能相匹配。

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

尺寸、空间使用和冗余

由“镜像”vdevs组成的池将拥有最佳的性能特征,但可用空间将是可用磁盘的50%。如果一个镜像vdev由超过2个磁盘组成,例如在一个三向镜像中,可用空间会更少。至少每个镜像中需要一个健康的磁盘,以保持池的功能。

''一个N个磁盘的’RAIDZ’类型vdev的可用空间大致为N-P,其中P表示RAIDZ级别。RAIDZ级别表明有多少块任意磁盘可以在不丢失数据的情况下失效。一个特殊情况是一个有4个磁盘的池使用RAIDZ2。在这种情况下,通常更好的选择是使用2个镜像vdev,因为它们会有更好的性能,同时可用空间将会是相同的。''

在使用任何RAIDZ级别时,另一个重要因素是ZVOL数据集(用于VM磁盘)的行为方式。对于池中的每一个数据块,它需要至少等于池的`ashift`值定义的最小块大小的奇偶校验数据。如果ashift值为12,那么池的块大小为4k。ZVOL的默认块大小为8k。因此,在RAIDZ2中,每写入一个8k的块,将导致写入两个额外的4k奇偶校验块,8k + 4k + 4k = 16k。当然,这是一种简化的方法,实际情况会因元数据、压缩等因素而略有不同,这些在这个例子中没有被考虑。

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

  • volsize

  • "refreservation(如果存储池没有使用薄配置)"

  • "used (if the pool is thin provisioned and without snapshots present)" 如果池是薄置备的并且没有快照存在

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

"volsize 是磁盘展示给虚拟机的大小,而 refreservation 显示了池中保留的空间,其中包括预期的奇偶校验数据所需的空间。如果池是薄置备的,那么 refreservation 将被设置为0。另一种观察行为的方法是比较虚拟机内部的已使用磁盘空间和 used 属性。请注意,快照会造成该值的偏差。"

有几种方法可以对抗空间使用的增加:

  • 增加 volblocksize 以提高数据到奇偶校验的比例。

  • 使用’mirror' vdevs 而不是 RAIDZ

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

volblocksize` 属性只能在创建 ZVOL 时设置。默认值可以在存储配置中更改。执行此操作时,需要相应调整客户端,并且根据使用情况,写放大问题可能只是从 ZFS 层移动到了客户端。

在创建存储池时使用`ashift=9`可能会根据底层的硬盘情况导致性能不佳,并且之后无法更改。

镜像vdevs(RAID1,RAID10)对于虚拟机工作负载有着良好的表现。除非你的环境有特定的需求和特性,使得RAIDZ的性能特点是可接受的,否则请使用镜像vdevs。

ZFS dRAID

在ZFS dRAID(分散式RAID)中,热备用驱动器参与RAID阵列。它们的备用容量被保留并用于重建,当某个驱动器出现故障时使用。这根据配置不同,与RAIDZ相比,在驱动器出现故障时可以提供更快的重建速度。更多信息可以在官方OpenZFS文档中找到。脚注:[OpenZFS dRAID https://openzfs.github.io/openzfs-docs/Basic%20Concepts/dRAID%20Howto.html]。

Note
dRAID 旨在用于超过10-15个硬盘的dRAID配置中。对于少量硬盘的大多数使用情况,RAIDZ设置应该更合适。
Note
图形用户界面(GUI)需要比最小值多一个磁盘(例如,dRAID1需要3个)。它还期望添加一个备用磁盘。

dRAID1`或`dRAID`:至少需要2块磁盘,其中一块可以在数据丢失前出现故障。 * dRAID2`:至少需要3个磁盘,数据丢失前可以有两个磁盘故障。 * dRAID3`:至少需要4块磁盘,数据丢失之前可以有三块磁盘失败

更多信息可以在手册页面找到:

# man zpoolconcepts

备件和数据

spares` 的数量告诉系统在磁盘发生故障时应该准备好多少块磁盘。默认值是 0 spares。如果没有备用磁盘,重建过程不会获得任何速度上的好处。

data` 定义了冗余组中的设备数量。默认值是 8. 除了当`disks - parity - spares`的结果小于8时,会使用较小的数字。一般来说,较少的`data`设备数量会导致更高的IOPS、更好的压缩比以及更快的重新银化速度,但是定义更少的数据设备会减少池的可用存储容量。

引导加载程序

{pve} 使用 proxmox-boot-tool 来管理启动加载程序配置。有关详情,请参阅 {pve} 主机引导加载程序 章节。

ZFS 管理

这一部分为您提供了一些常见任务的使用示例。ZFS本身非常强大,提供了许多选项。管理ZFS的主要命令是`zfs`和`zpool`。这两个命令都配有详细的手册页,可以通过以下方式阅读:

# man zpool
# man zfs
-----

[[sysadmin_zfs_create_new_zpool]]
创建一个新的zpool
^^^^^^^^^^^

要创建一个新的存储池,至少需要一块磁盘。`ashift`应该具有与底层磁盘相同的扇区大小(`ashift`的2的幂)或更大。

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

[TIP]
====
池名称必须遵守以下规则:

* 以一个字母(a-z或A-Z)开头
* 仅包含字母数字字符、`-`、`_`、`.`、`:` 或空格(` `)字符。
* 不能以`mirror`、`raidz`、`draid`或`spare`为开头
* 不得为 `log
====

要激活压缩(参见章节<<zfs_compression,ZFS中的压缩>>):

zfs set compression=lz4 <pool>

[[sysadmin_zfs_create_new_zpool_raid0]]
创建一个新的RAID-0池
^^^^^^^^^^^^^

最少1个磁盘

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

[[sysadmin_zfs_create_new_zpool_raid1]]
创建一个带有RAID-1的新存储池
^^^^^^^^^^^^^^^^^

至少2个磁盘

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

[[sysadmin_zfs_create_new_zpool_raid10]]
创建一个使用RAID-10的新池
^^^^^^^^^^^^^^^^

最少4个磁盘

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

[[sysadmin_zfs_create_new_zpool_raidz1]]
创建一个带有RAIDZ-1的新池
^^^^^^^^^^^^^^^^

最少3个磁盘

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

创建一个使用RAIDZ-2的新存储池
^^^^^^^^^^^^^^^^^^

最少4个磁盘

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

请阅读xref:sysadmin_zfs_raid_considerations[ZFS RAID 级别考虑]部分,以便在设置池时,特别是想要使用 RAID-Z 模式时,获得 IOPS 和带宽预期的大致估计。

[[sysadmin_zfs_create_new_zpool_with_cache]]
创建一个带有缓存(L2ARC)的新池
^^^^^^^^^^^^^^^^^^

可以使用专用设备或分区作为二级缓存以提高性能。这样的缓存设备尤其有助于大部分数据相对静态的随机读取工作负载。由于它充当实际存储和内存中的ARC之间的额外缓存层,因此如果由于内存限制需要减少ARC的大小,它也可以提供帮助。

.创建一个带有磁盘缓存的ZFS池

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

这里只使用了一个`<device>`和一个`<cache-device>`,但是可以使用更多设备,就像在xref:sysadmin_zfs_create_new_zpool_raid0[使用RAID创建新池]中所展示的那样。

请注意,对于缓存设备不存在镜像或RAID模式,它们都是简单地累加起来的。

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


[[sysadmin_zfs_create_new_zpool_with_log]]
创建一个带有日志(ZIL)的新池子
^^^^^^^^^^^^^^^^^

可以使用专用的驱动器或分区作为ZFS意图日志(ZIL),它主要用于提供安全的同步事务,因此经常用在性能关键路径上,比如数据库,或者其他更频繁发出`fsync`操作的程序。

池作为默认的ZIL位置,将ZIL IO负载转移到一个单独的设备上,可以在缓解主池的同时,帮助减少事务延迟,提高整体性能。

将磁盘用作日志设备,无论是直接使用还是通过分区,建议:

- 使用具有断电保护的快速SSD,因为这些设备的提交延迟要小得多。

- 为分区(或整个设备)至少分配几GB的空间,但使用超过您已安装内存一半以上的空间并不会为您带来任何真正的好处。

.创建具有独立日志设备的ZFS池

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

在上面的例子中使用了单个`<device>`和单个`<log-device>`,但是您也可以将其与其他RAID变体结合使用,如xref:sysadmin_zfs_create_new_zpool_raid0[创建一个新的具有RAID的池]部分所述。

你也可以将日志设备镜像到多个设备上,这主要是为了确保如果单个日志设备出现故障,性能不会立即下降。

如果所有的日志设备都失败了,ZFS主池本身将再次被使用,直到日志设备被替换。

[[sysadmin_zfs_add_cache_and_log_dev]]
将缓存和日志添加到现有资源池中
^^^^^^^^^^^^^^^

如果你有一个没有缓存和日志的池,你仍然可以在任何时候添加它们中的一个或两个。

例如,假设你有一块带有断电保护功能的优质企业级SSD,你想用它来提升你的池(pool)的整体性能。

日志设备的最大大小应该约为已安装物理内存的一半,这意味着ZIL大多数情况下只会占用SSD的一小部分,剩余空间可以用作缓存。

首先你需要使用`parted`或`gdisk`在SSD上创建两个GPT分区。

那么你就可以将它们添加到资源池中:

.将一个单独的日志设备和二级缓存同时添加到现有的资源池中。

zpool add -f <pool> log <device-part1> cache <device-part2>

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

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

.向现有的ZFS池添加一个日志设备

zpool add <pool> log <log-device>

[[sysadmin_zfs_change_failed_dev]]
更换失败的设备
^^^^^^^

zpool replace -f <pool> <old-device> <new-device>

.更换失败的可启动设备

根据{pve}的安装方式,它要么是使用`systemd-boot`,要么通过`proxmox-boot-tool`使用GRUB footnote:[系统安装了{pve} 6.4或更高版本,EFI系统安装了{pve} 5.4或更高版本],或者使用普通的GRUB作为引导程序(见xref:sysboot[主机引导程序])。您可以通过运行以下命令来检查:

proxmox-boot-tool status

复制分区表、重新发行GUID以及替换ZFS分区的首要步骤是相同的。为了使系统能够从新磁盘启动,需要执行不同的步骤,这些步骤取决于所使用的引导加载程序。

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 系统分区,这是由 {pve} 安装程序自版本 5.4 起在可启动磁盘上设置为分区#2。有关详细信息,请参阅 xref:sysboot_proxmox_boot_setup[设置新分区以用作同步的 ESP]。"

NOTE: 如果`proxmox-boot-tool status`显示您当前的磁盘正在使用GRUB,特别是当启用了Secure Boot时,请确保以'grub'模式传递给`proxmox-boot-tool init`!

.使用普通的GRUB:

grub-install <new disk>

NOTE: 普通的GRUB只在安装了{pve} 6.3或更早版本的系统上使用,这些系统尚未手动迁移到使用`proxmox-boot-tool`。


配置电子邮件通知
~~~~~~~~

ZFS附带一个事件守护进程`ZED`,它监控ZFS内核模块生成的事件。守护进程还可以在发生ZFS事件(如池错误)时发送电子邮件。较新的ZFS包将守护进程分包在一个独立的`zfs-zed`包中,通常情况下这个包在{pve}中应该已经默认安装。

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

--------
ZED_EMAIL_ADDR="root"
--------

请注意,{pve} 将邮件转发给 `root` 用户配置的电子邮件地址。


[[sysadmin_zfs_limit_memory_usage]]
限制ZFS内存使用
~~~~~~~~~

默认情况下,ZFS会使用主机内存的'50%'来作为**自适应替换缓存**(Adaptive Replacement Cache,简称ARC)。对于从{pve} 8.1开始的新安装,ARC的使用限制将被设置为安装的物理内存的'10%',并限制在最大+16 GiB+。该值将被写入到`/etc/modprobe.d/zfs.conf`中。

为ARC分配足够的内存对于IO性能至关重要,因此请谨慎减少它。作为一个一般的经验法则,至少应该分配+2 GiB基础内存+每TiB存储空间增加1 GiB。例如,如果你有一个+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 * 2^30^')。

IMPORTANT: 如果您想要设置的+zfs_arc_max+值小于等于+zfs_arc_min+(其默认值为系统内存的1/32),则除非您同时将+zfs_arc_min+设为最多+zfs_arc_max - 1+,否则+zfs_arc_max+将会被忽略。

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

这个示例设置(临时)将内存使用限制在8 GiB('8 * 2^30'), 适用于总内存超过256 GiB的系统,在这些系统中,仅设置+zfs_arc_max+是不起作用的。

[IMPORTANT]
====
如果您的根文件系统是ZFS,每次这个值发生变化时,您都必须更新您的initramfs:

update-initramfs -u -k all

你*必须重启*电脑来激活这些更改。
====


[[zfs_swap]]
在ZFS上交换
~~~~~~~

在zvol上创建的交换空间可能会引起一些问题,比如阻塞服务器或产生高IO负载,这种情况常在启动对外部存储的备份时看到。

我们强烈建议使用足够的内存,这样通常不会遇到内存不足的情况。如果你需要或希望添加交换空间,建议在物理磁盘上创建一个分区并将其用作交换设备。你可以在安装程序的高级选项中预留一些空间用于此目的。此外,你可以降低“交换倾向”值。对于服务器来说,10是一个好的值:

sysctl -w vm.swappiness=10

要使交换性(swappiness)设置持久化,用你选择的编辑器打开`/etc/sysctl.conf`文件,并添加以下行:

--------
vm.swappiness = 10
--------

.Linux内核 `swappiness` 参数值
[width="100%", cols="<m,2d", options="header"]
|===========================================================
| 值                  | 策略
| vm.swappiness = 0   | 内核只会在避免“内存不足”条件下才进行交换
| vm.swappiness = 1   | 不完全禁用交换的最小数量。
| vm.swappiness = 10  | 当系统存在足够内存时,有时推荐此值以提高性能。
| vm.swappiness = 60  | 默认值。
| vm.swappiness = 100 | 内核将积极进行交换。
|===========================================================

[[zfs_encryption]]
加密的ZFS数据集
~~~~~~~~~

WARNING: '''{pve}中的原生ZFS加密目前还处于实验阶段。已知的限制和问题包括使用加密数据集进行复制时的问题footnote:[https://bugzilla.proxmox.com/show_bug.cgi?id=2350],以及在使用快照或ZVOLs时出现的校验和错误。footnote:[https://github.com/openzfs/zfs/issues/11688]'''

ZFS在Linux版本0.8.0引入了对数据集本机加密的支持。在从先前的ZFS on Linux版本升级之后,可以按照池启用加密功能:

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不支持从含有加密数据集的池中引导启动,且对于启动时自动解锁加密数据集的支持也有限。不支持加密功能的旧版本ZFS将无法解密存储的数据。

NOTE: 建议在启动后手动解锁存储数据集,或者编写一个自定义单元,在启动时将解锁所需的密钥材料传递给 `zfs load-key`。

WARNING: 在启用生产数据加密之前,建立并测试备份程序。如果相关的密钥材料/密码/密钥文件丢失,将无法再访问加密数据。

在创建数据集/zvols时需要设置加密,并且默认情况下这个设置会继承给子数据集。例如,要创建一个加密的数据集 `tank/encrypted_data` 并在 {pve} 中配置它作为存储,请运行以下命令:

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

在此存储上创建的所有访客卷/磁盘将使用父数据集的共享密钥材料进行加密。

要实际使用存储空间,需要加载相关的密钥材料并且挂载数据集。这可以通过以下一步完成:

zfs mount -l tank/encrypted_data

Enter passphrase for tank/encrypted_data:

也可以通过设置`keylocation`和`keyformat`属性来使用(随机的)密钥文件代替密码提示,这可以在创建时或通过`zfs change-key`在现有数据集上进行。

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: 在使用密钥文件时,需要特别注意保护密钥文件不受未授权访问或意外丢失。如果没有密钥文件,将无法访问明文数据!

在加密数据集下创建的客户卷将会相应地设置其`encryptionroot`属性。密钥材料只需要为每个encryptionroot加载一次,就可以对其下所有加密数据集可用。

请参阅`encryptionroot`、`encryption`、`keylocation`、`keyformat`和`keystatus`属性,`zfs load-key`、`zfs unload-key`和`zfs change-key`命令,以及`man zfs`中的`Encryption`部分,以获取更多详细信息和高级用法。


[[zfs_compression]]
ZFS中的压缩
~~~~~~~

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

您可以通过以下方式启用压缩:

zfs set compression=<algorithm> <dataset>

我们推荐使用`lz4`算法,因为它几乎不会增加CPU的负担。其他像`lzjb`和`gzip-N`的算法也是可用的,其中`N`是从`1`(最快)到`9`(最佳压缩比)的整数。根据选择的算法以及数据的可压缩性,启用压缩甚至可能提升I/O性能。

您可以随时使用以下方法禁用压缩:

zfs set compression=off <dataset>

再次强调,只有新的区块会受到这次变化的影响。


[[sysadmin_zfs_special_device]]
ZFS 专用设备
~~~~~~~~

自0.8.0版本起,ZFS支持`special`设备。在存储池中,`special`设备用于存储元数据、去重表格,以及可选的小文件块。

一个`特殊`设备可以提高由旋转速度慢的硬盘组成的存储池的速度,尤其是在有大量元数据变化的情况下。例如,涉及创建、更新或删除大量文件的工作负载将从`特殊`设备的存在中受益。ZFS数据集也可以配置为将所有小文件存储在`特殊`设备上,这进一步提高了性能。使用快速的SSD作为`特殊`设备。

IMPORTANT: special`设备的冗余度应该与池的冗余度相匹配,因为`special`设备是整个池的故障点。

WARNING: 向池中添加一个`特别的`设备是无法撤销的!

.创建一个带有`special`设备和RAID-1的池:

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

.将一个`special`设备添加到已存在的RAID-1池中:

zpool add <pool> special mirror <device1> <device2>

ZFS数据集暴露了`special_small_blocks=<size>`属性。`size`可以是`0`,以禁用在`special`设备上存储小文件块,或者是在`512B`到`1M`范围内的二的幂次方。设置该属性后,小于`size`的新文件块将被分配到`special`设备上。

IMPORTANT: 如果`special_small_blocks`的值大于或等于数据集的`recordsize`(默认`128K`),*所有*数据将被写入`special`设备,所以要小心!

在池(pool)上设置`special_small_blocks`属性将改变该属性对所有子ZFS数据集的默认值(例如,池中的所有容器都将选择小文件块)。

.为所有小于4K块大小的文件选择加入到全局池中:

zfs set special_small_blocks=4K <pool>

.为单个数据集选择启用小文件块:

zfs set special_small_blocks=4K <pool>/<filesystem>

.为单个数据集选择退出小文件块:

zfs set special_small_blocks=0 <pool>/<filesystem>

[[sysadmin_zfs_features]]
ZFS池功能
~~~~~~

在ZFS中,对磁盘格式的更改只在主要版本更迭时进行,并通过*特性*来指定。所有特性以及通用机制都在`zpool-features(5)`手册页中有详细文档说明。

由于启用新特性可能会导致池不可被旧版本的ZFS导入,因此需要管理员主动进行,通过在池上运行 `zpool upgrade` 命令(参见 `zpool-upgrade(8)` 手册页)。

除非你需要使用其中的新功能,否则启用它们没有好处。

实际上,启用新功能也有一些缺点:

* 一个使用ZFS作为根文件系统的系统,如果仍通过GRUB引导启动,并且在rpool上激活了新功能,由于GRUB中ZFS的实现不兼容,这将导致系统无法启动。
* 当系统使用一个较旧的内核启动时,它将无法导入任何升级过的存储池,因为该旧内核仍然附带旧版的ZFS模块。
* 使用较旧的{pve} ISO引导以修复一个无法启动的系统同样不会起作用。

IMPORTANT: 如果您的系统仍然使用GRUB引导,请*不要*升级您的rpool,因为这会导致您的系统无法启动。这包括在{pve} 5.4之前安装的系统,以及使用传统BIOS启动的系统(请参阅xref:sysboot_determine_bootloader_used[如何确定使用的引导加载程序])。

.为ZFS池启用新特性:

zpool upgrade <pool>

[[chapter_btrfs]]
BTRFS
-----

WARNING: BTRFS集成目前在{pve}中是一个**技术预览**。

BTRFS 是一个现代的写时复制文件系统,由 Linux 内核原生支持,实现了如快照、内建 RAID 以及通过数据和元数据的校验和进行自我修复的功能。从 {pve} 7.0 开始,BTRFS 被引入作为根文件系统的可选项。

.BTRFS的一般优势

* 主系统设置几乎与传统基于ext4的设置相同。

* 快照

* 文件系统级别的数据压缩

* 写时复制克隆

* RAID0、RAID1和RAID10

* 数据防损坏保护

* 自愈

* 原生支持的Linux内核

* ...

.注意事项

* RAID 5/6级别是实验性的并且危险的

作为根文件系统的安装
~~~~~~~~~~

当您使用{pve}安装程序进行安装时,可以选择BTRFS作为根文件系统。您需要在安装时选择RAID类型:

[horizontal]
RAID0:: 也被称为“条带化”。这种卷的容量是所有磁盘容量的总和。但是RAID0没有增加任何冗余,因此单个驱动器的故障会导致卷不可用。

RAID1:: 也被称为“镜像”。数据会被一模一样地写入到所有磁盘中。这种模式至少需要两块相同大小的磁盘。其结果容量等同于单个磁盘的容量。

RAID10:: RAID0和RAID1的组合。至少需要4个磁盘。

安装程序会自动分区磁盘,并在 `/var/lib/pve/local-btrfs` 创建一个额外的子卷。为了能够使用 {pve} 工具,安装程序会在 `/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`参数分别用于设置元数据和数据的配置文件。可以使用可选的`-L`参数来设置标签。

通常,支持以下模式:`single`、`raid0`、`raid1`、`raid10`。

在单个磁盘`/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

…​其他挂载点因简略而省略

using the UUID from the mkfs.btrfs output is highly recommended

UUID=e2c0c3ff-2114-4f54-b767-3a203e49f6f3 /my-storage btrfs defaults 0 0

TIP: 如果你不再拥有UUID,你可以使用`blkid`工具列出所有块设备的属性。

之后,你可以通过执行以下操作来触发第一次挂载:

mount /my-storage

在下次重启后,系统将会在启动时自动完成这项操作。

将BTRFS文件系统添加到{pve}
^^^^^^^^^^^^^^^^^^

您可以通过网络界面将一个现有的BTRFS文件系统添加到{pve},或者使用命令行界面,例如:

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

创建一个子卷
^^^^^^

创建一个子卷将其链接到BTRFS文件系统中的一个路径,在那里它将显示为一个普通目录。

btrfs subvolume create /some/path

之后 `/some/path` 将像一个普通目录一样工作。

删除子卷
^^^^

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

btrfs subvolume delete /some/path

创建一个子卷的快照
^^^^^^^^^

BTRFS实际上并不区分快照和普通子卷,所以进行快照实际上也可以被视为创建一个子卷的任意副本。按照惯例,{pve}在创建客户磁盘或子卷的快照时会使用只读标志,但这个标志后来也可以更改。

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

您可以简单地将 `compress=zstd`、`compress=lzo` 或 `compress=zlib` 追加到上面的 `defaults` 中,如下所示:

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

这个更改将在重启后生效。

检查空间使用情况
^^^^^^^^

经典的`df`工具可能会对于一些BTRFS设置输出令人困惑的数值。为了获得更好的估算,请使用`btrfs filesystem usage /PATH`命令,例如:

btrfs fi usage /my-storage

[[proxmox_node_management]]
Proxmox 节点管理
------------

{PVE}节点管理工具(`pvenode`)允许你控制节点特定的设置和资源。

当前,`pvenode` 允许您设置节点的描述、在节点的访客上运行各种批量操作、查看节点的任务历史记录,并通过 `pveproxy` 管理用于 API 和 web GUI 的节点 SSL 证书。









远程唤醒
~~~~
远程唤醒(Wake-on-LAN,简称WoL)允许你通过发送一个魔术包来开启网络中的休眠计算机。至少有一个网络接口卡(NIC)必须支持此功能,并且需要在计算机的固件(BIOS/UEFI)配置中启用相应选项。选项名称可能从“启用网络唤醒”变为“通过PCIE设备开机”;如果不确定,可以查看主板厂商的手册。`ethtool`可以用来检查`<interface>`的WoL配置,通过运行:

ethtool <interface> | grep Wake-on

pvenode` 允许你通过 WoL 命令唤醒集群中的休眠成员:

pvenode wakeonlan <node>

这将在UDP端口9上广播WoL魔术包,其中包含从`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>

广播地址(默认为`255.255.255.255`)在发送WoL(唤醒局域网)数据包时可以通过使用以下命令显式设置`broadcast-address`来进行更改:

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

任务历史
~~~~

当排查服务器问题时,例如,失败的备份作业,通常查看之前运行任务的日志会很有帮助。使用 {pve},你可以通过 `pvenode task` 命令访问节点的任务历史。

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

pvenode task list --errors --vmid 100

任务的日志可以通过其UPID打印出来。

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

批量客房电源管理
~~~~~~~~

如果你有很多虚拟机/容器,可以使用 `pvenode` 的 `startall` 和 `stopall` 子命令来批量启动和停止宾主机。默认情况下,`pvenode startall` 仅会启动在引导时设为自动启动的虚拟机/容器(参见 xref:qm_startup_and_shutdown[虚拟机的自动启动和关闭]),但是你可以使用 `--force` 标志来覆盖此行为。这两个命令还有一个 `--vms` 选项,可以限制停止/启动的宾主机到指定的 VMIDs。

例如,要启动虚拟机 '100'、'101' 和 '102',不管它们是否设置了 `onboot`,你可以使用:

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

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

pvenode stopall

NOTE: '''stopall命令首先尝试执行一个干净的关机,然后等待直到所有的客户机都成功关机或者一个可以覆盖的超时(默认为3分钟)到期为止。一旦发生这种情况,并且force-stop参数没有明确设置为0(假),所有仍在运行的虚拟客户机都将被强制停止。'''


[[first_guest_boot_delay]]
首次访客启动延迟
~~~~~~~~

如果您的虚拟机/容器依赖于启动缓慢的外部资源,例如NFS服务器,您也可以设置节点启动后和配置为自动启动的第一台虚拟机/容器启动之间的延迟时间(参见 xref:qm_startup_and_shutdown[虚拟机的自动启动和关闭])。

你可以通过设置以下参数来实现这一点(其中`10`代表秒数延迟):

pvenode config set --startall-onboot-delay 10

批量客户迁移
~~~~~~

如果升级情况需要你将所有客体从一个节点迁移到另一个节点,`pvenode` 还提供了 `migrateall` 子命令用于批量迁移。默认情况下,此命令将会迁移系统上的每一个客体到目标节点。然而,它可以设置为仅迁移一组特定的客体。

例如,要将虚拟机'100'、'101'和'102'迁移到节点'pve2',并启用本地磁盘的实时迁移,你可以运行:

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

// TODO: explain node shutdown (stopall is used there) and maintenance options


[[sysadmin_certificate_management]]
证书管理

集群内部通信的证书

每个{PVE}集群默认创建自己的(自签名的)证书颁发机构(CA)并为每个节点生成一个由上述CA签名的证书。如果使用SPICE,这些证书被用于与集群的`pveproxy`服务以及Shell/Console特性的加密通信。

CA证书和密钥存储在Proxmox集群文件系统(pmxcfs)中。

API和Web界面的证书

REST API和web GUI由`pveproxy`服务提供,该服务在每个节点上运行。

您可以为`pveproxy`使用以下证书选项:

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

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

  3. 使用ACME(Let’s Encrypt)获取可信任的证书,并自动更新,这也集成在{pve} API和网络接口中。

对于选项2和3,文件`/etc/pve/local/pveproxy-ssl.pem`(以及无需密码的`/etc/pve/local/pveproxy-ssl.key`)将会被使用。

Note
请记住,/etc/pve/local 是一个指向 /etc/pve/nodes/NODENAME 的节点特定的符号链接。

证书通过{PVE}节点管理命令管理(参见`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文件。

上传自定义证书

如果您已经有了一个证书,想要用于{pve}节点,您可以简单地通过Web界面上传该证书。

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

通过Let’s Encrypt (ACME) 获取受信任的证书

{PVE} 包括对自动证书管理环境ACME)协议的实现,允许 {pve} 管理员使用像 Let’s Encrypt 这样的 ACME 提供者来轻松设置 TLS 证书,这些证书在现代操作系统和网络浏览器中被默认接受和信任。

目前实现的两个ACME端点是https://letsencrypt.org[Let’s Encrypt (LE)]的生产环境及其测试环境。我们的ACME客户端支持使用内置的web服务器对`http-01`挑战进行验证,以及使用支持所有DNS API端点https://acme.sh[acme.sh]的DNS插件对`dns-01`挑战进行验证。

ACME账户

您需要为每个集群注册一个ACME账户,并使用您想要使用的终端。该账户使用的电子邮件地址将作为ACME终端发出的续订到期或类似通知的联系点。

您可以通过网页界面 Datacenter -> ACME 或使用 pvenode 命令行工具来注册和停用 ACME 账户。

pvenode acme account register account-name mail@example.com
Tip
由于 https://letsencrypt.org/docs/rate-limits/ [速率限制],如果您是第一次使用ACME或进行实验,您应该使用LE staging

ACME 插件

ACME插件的任务是自动验证您,因此您所操作的 {pve} 集群,是域名的真正所有者。这是自动证书管理的基础构建模块。

ACME协议规定了不同类型的挑战,例如`http-01`,其中一个web服务器提供一个包含特定内容的文件,以证明它控制了一个域名。有时这是不可能的,可能是因为技术限制,或者如果记录的地址无法从公共互联网访问。在这些情况下可以使用`dns-01`挑战。完成这个挑战需要在域的区域中创建一个特定的DNS记录。

'{pve} 默认支持这两种挑战类型,您可以在 Datacenter -> ACME 的网络界面下配置插件,或者使用 pvenode acme plugin add 命令进行配置。'

ACME 插件配置存储在 /etc/pve/priv/acme/plugins.cfg。对于集群中的所有节点,都有一个可用的插件。

节点域

每个域都是节点特定的。您可以在 节点 -> 证书 下添加新的或管理现有的域条目,或者使用 pvenode config 命令。

为节点配置好期望的域名并确保已选择期望的ACME账户后,您可以通过Web界面订购新证书。成功后,界面将在10秒后重新加载。

更新将会自动进行。

ACME HTTP 挑战插件

总是有一个隐式配置的`standalone`插件,用于通过在端口80上生成的内置Web服务器验证`http-01`挑战。

Note
名称`standalone`意味着它可以自行提供验证,无需任何第三方服务。因此,这个插件也适用于集群节点。

要使用它进行Let’s Encrypts ACME的证书管理,有一些先决条件。

  • 你必须接受Let’s Encrypt的服务条款(ToS)才能注册账户。

  • 节点的端口 80需要能够被互联网访问。

  • 端口80上必须没有其他监听器。

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

ACME DNS API 挑战插件

在那些通过`http-01`方法进行验证的外部访问不可能或不希望的系统上,可以使用`dns-01`验证方法。这种验证方法需要一个允许通过API配置`TXT`记录的DNS服务器。

配置ACME DNS API进行验证

{PVE}重用了为`acme.sh`项目脚注:[acme.sh https://github.com/acmesh-official/acme.sh] 开发的DNS插件,请参阅其文档以获取特定API配置的详细信息。

使用DNS API配置新插件最简单的方法是通过网络界面(数据中心 -> ACME)。

选择`DNS`作为挑战类型。然后你可以选择你的API提供商,输入凭据数据以通过他们的API访问你的账户。

Tip
请查看 acme.sh 的 https://github.com/acmesh-official/acme.sh/wiki/dnsapi#how-to-use-dns-api [如何使用 DNS API] wiki,以获取有关如何为您的提供商获取 API 凭证的更详细信息。

鉴于存在许多DNS提供商和API端点,{pve}会自动为一些提供商生成凭证表单。对于其他提供商,您将看到一个更大的文本区域,只需将所有凭证的`KEY`=`VALUE`对复制到那里即可。

通过CNAME别名进行DNS验证

一种特殊的 alias 模式可以用来在不同的域名/DNS服务器上进行验证,以防你的主要/真实DNS不支持通过API进行配置。手动为 _acme-challenge.domain1.example 设置一个永久的 CNAME 记录,指向 _acme-challenge.domain2.example,并在 {PVE} 节点配置文件中设置 alias 属性为 domain2.example,以允许 domain2.example 的DNS服务器验证 domain1.example 的所有挑战。

插件组合

结合使用`http-01`和`dns-01`验证是可能的,以防您的节点通过满足不同要求/拥有不同DNS配置能力的多个域名可达。通过为每个域指定不同的插件实例,也可以混合来自多个提供商或实例的DNS API。

Tip
如果可能的话,应该避免通过多个域名访问同一服务,因为这会增加复杂性。

ACME证书的自动续订

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

ACME案例与`pvenode`相关操作

例子:使用 Let’s Encrypt 证书的 Sample 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

服务条款: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
您同意上述条款吗?[y|N]y
...
任务完成
root@proxmox:~# pvenode config set --acme domains=example.invalid
root@proxmox:~# pvenode acme cert order
加载ACME账户详细信息
下达ACME订单
...
状态为'有效'!

所有域名已验证!
...
正在下载证书
设置 pveproxy 证书和密钥
重启 pveproxy
任务完成

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

Note
无论使用哪些插件,账户注册步骤都是相同的,并且在此不再重复。
Note
OVH_AK` 和 OVH_AS 需要根据 OVH API 文档从 OVH 获取。

首先你需要获取所有信息,这样你和{pve}才能访问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"}

打开验证链接并按照指引将应用程序密钥与账户/消费者密钥关联起来。

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

从 'https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/33333333' 获取授权详情
example.proxmox.com 的验证等待中!
[Wed Apr 22 09:25:30 CEST 2020] 使用 OVH 端点:ovh-eu
[Wed Apr 22 09:25:30 CEST 2020] 正在检查认证
[Wed Apr 22 09:25:30 CEST 2020] 消费者密钥正常。
[Wed Apr 22 09:25:31 CEST 2020] 正在添加记录
[Wed Apr 22 09:25:32 CEST 2020] 已添加,等待10秒。
添加 TXT 记录:_acme-challenge.example.proxmox.com
触发验证
等待5秒
状态为'有效'!
[Wed Apr 22 09:25:48 CEST 2020] 使用 OVH 端点:ovh-eu
[Wed Apr 22 09:25:48 CEST 2020] 正在检查认证
[Wed Apr 22 09:25:48 CEST 2020] 消费者密钥正常。
移除 TXT 记录:_acme-challenge.example.proxmox.com

所有域名已验证!

创建CSR
检查订单状态
订单已准备好,正在完成订单
有效!

下载证书
设置 pveproxy 证书和密钥
重启 pveproxy
任务完成

示例:从`staging`环境切换到常规的ACME目录

更改账户的ACME目录是不支持的,但由于{pve}支持多个账户,您可以直接创建一个以生产(受信任的)ACME目录作为终点的新账户。您还可以停用测试账户并重新创建它。

示例:使用 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

服务条款:https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
你同意上述条款吗?[y|N]y
...
任务完成

主机引导加载程序

{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实现中的子集,或者不得不创建一个单独的小型启动池[2]

在具有冗余设置的系统中,安装程序会对所有磁盘进行分区,并创建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`中的配置片段来完成的。在配置更改后重新生成配置文件,请运行:[3]

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

内核相同页合并 (KSM)

Kernel Samepage Merging(KSM)是Linux内核提供的一个可选的内存去重功能,默认情况下在{pve}中启用。KSM通过扫描一系列物理内存页来搜索内容完全相同的页,并识别映射到这些页上的虚拟页。如果发现了内容相同的内存页,相应的虚拟页会被重新映射,使它们都指向同一物理页,而旧的物理页会被释放。这些虚拟页被标记为“写时复制”,这样任何对它们的写操作都会被写入到新的内存区域,保持共享的物理页不变。

KSM的含义

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

然而,虽然KSM能够降低内存使用量,但它也带来了一些安全风险,因为它可能会让虚拟机(VM)暴露于旁道攻击。研究表明,通过利用KSM的某些特性,可以通过同一主机上的第二个虚拟机推断出正在运行的虚拟机的信息。

因此,如果您使用{pve}来提供托管服务,您应该考虑禁用KSM,以便为您的用户提供额外的安全保障。此外,您应当检查您所在国家的法规,因为禁用KSM可能是一项法律要求。

禁用KSM

要检查KSM是否激活,你可以查看以下命令的输出:

# systemctl status ksmtuned

如果是这样,可以立即使用以下方式禁用:

# systemctl disable --now ksmtuned

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

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

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