十二个构建

裸机上的 Proxmox,可用的嵌套虚拟机

一台单租户 EPYC 机器,运行 Proxmox VE,使用镜像 NVMe,为虚拟机提供路由桥接,并从虚拟机内部证明嵌套虚拟化。

构建内容

一台裸机服务器运行 Proxmox VE 作为其自身的管理程序,NVMe 驱动器上配置 ZFS 镜像,桥接网络为虚拟机提供真实地址,并启用和验证嵌套虚拟化——这意味着该机器上的虚拟机可以再运行虚拟机。

嵌套是在裸机上而非虚拟实例上执行此操作的原因。你不能在别人的管理程序内以可预测的结果进行嵌套,而在 BM-E 上,没有我们的管理程序挡路:你拥有 IPMI、电源按钮和主板。运行什么由你决定。

开始之前

  • 一台 BM-E:三十二个 Zen 4 核心、256 GB ECC 内存、四块 NVMe 驱动器、八个 IPv4 地址。IPMI 可通过 VPN 访问,支持团队在机器交付时设置。
  • 订购时选择 Proxmox VE 8,或通过面板上传自定义 ISO。两种方式最终都会进入相同的安装程序。
  • 预留半小时,期间无人需要使用机器,因为第一步会多次重启。

1. 安装

通过管理 VPN 连接到控制台,挂载 ISO 并启动。在磁盘选择界面选择全部四块 NVMe 设备,选择 zfs (RAID10),并打开高级选项:

  • ashift 设为 12,这是 4K 扇区的正确值,之后无法更改,除非重建存储池。
  • compress 设为 lz4。它只消耗一小部分核心,通常能节省三分之一的空间。
  • 减少 hdsize 以留出空间给虚拟机存储,除非你希望根存储池独占所有空间。

根据面板信息设置管理地址和网关,并使用机器的完全限定域名作为主机名。两次重启后,你将看到登录提示符和 8006 端口的 Web 界面。

2. 软件源和软件包

企业软件源在没有订阅时会失败,并会在每个 apt update 中产生杂乱信息,直到你处理它:

rm -f /etc/apt/sources.list.d/pve-enterprise.sources
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-community.list
apt update && apt full-upgrade -y
apt install -y ifupdown2 chrony zfsutils-linux
reboot

3. 为 ZFS 分配内存

否则 ARC 会增长到内存的一半,而在一个专门运行虚拟机的机器上,这些内存有更好的用途:

echo "options zfs zfs_arc_max=34359738368" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all

在 256 GB 的机器上,32 GB 的 ARC 既能提供充足的缓存,又不会让虚拟机内存不足。重启以生效,或者如果无法重启,使用 echo 将其即时应用于 /sys/module/zfs/parameters/zfs_arc_max

4. 网络

八个地址不多,因此虚拟机位于私有桥上,只有需要公共地址的虚拟机才获得路由到它们的地址。编辑 /etc/network/interfaces

auto lo
iface lo inet loopback

auto enp1s0f0
iface enp1s0f0 inet static
  address <public address>/24
  gateway <gateway>

auto vmbr0
iface vmbr0 inet static
  address 10.20.0.1/24
  bridge-ports none
  bridge-stp off
  bridge-fd 0
  post-up   iptables -t nat -A POSTROUTING -s 10.20.0.0/24 -o enp1s0f0 -j MASQUERADE
  post-down iptables -t nat -D POSTROUTING -s 10.20.0.0/24 -o enp1s0f0 -j MASQUERADE

iface vmbr0 inet6 static
  address 2001:db8:1a2b:20::1/64

IPv6 不需要地址转换,因为路由到机器的 /64 是真正的路由:将地址分配给桥上的虚拟机,它们就能直接访问互联网。两个协议族之间的这种不对称并不优雅,但这是我们所处地址空间的真实形态。

sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/80-pve.conf
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.d/80-pve.conf
ifreload -a

5. 嵌套虚拟化

cat /sys/module/kvm_amd/parameters/nested

在当前内核上,这应该已经输出 1。如果输出 0

echo "options kvm-amd nested=1" > /etc/modprobe.d/kvm-amd.conf
update-initramfs -u && reboot

嵌套还要求虚拟机看到的 CPU 具备该特性,这意味着处理器类型必须是 host。否则会呈现一个屏蔽了虚拟化扩展的合成 CPU 模型,内部管理程序会拒绝启动,并给出一个未提及此问题的错误。

6. 虚拟机示例

cd /var/lib/vz/template/iso
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2

qm create 100 --name inner --memory 16384 --cores 8 --cpu host \
  --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-single --ostype l26 \
  --agent enabled=1 --machine q35 --bios ovmf
qm set 100 --efidisk0 local-zfs:1
qm importdisk 100 debian-13-genericcloud-amd64.qcow2 local-zfs
qm set 100 --scsi0 local-zfs:vm-100-disk-1,discard=on,ssd=1
qm set 100 --boot order=scsi0
qm set 100 --ipconfig0 ip=10.20.0.100/24,gw=10.20.0.1
qm set 100 --sshkeys /root/.ssh/authorized_keys
qm set 100 --ciuser admin
qm start 100

discard=on 搭配 ssd=1 意味着虚拟机内的删除操作会将空间返还给存储池,而不是积累成你无法追踪的已用空间。

7. 防火墙

8006 端口的 Web 界面不应公开访问。在数据中心层面将其限制为你管理的地址——WireGuard 指南中的隧道端点是最佳选择:

cat > /etc/pve/firewall/cluster.fw <<EOF
[OPTIONS]
enable: 1
policy_in: DROP

[RULES]
IN SSH(ACCEPT) -source 10.7.0.0/24
IN ACCEPT -source 10.7.0.0/24 -dport 8006 -proto tcp
IN ACCEPT -p icmp
EOF
systemctl restart pve-firewall

验证

先验证宿主机:

pveversion -v | head -3
zpool status rpool
zpool list -o name,size,alloc,free,frag,cap
arc_summary | head -12

存储池报告 ONLINE,两个镜像对,ARC 目标是你设置的 32 GB,而不是机器的内存一半。

现在验证本次构建的真正重点。登录虚拟机并检查分配给它的处理器:

ssh [email protected]
lscpu | grep -E "Model name|Virtuali"
grep -c svm /proc/cpuinfo

型号名称应为真实的 EPYC 型号,虚拟化行应显示 AMD-V。第三条命令返回零表示处理器类型不是 host,以下所有操作都将失败。

然后在虚拟机中运行一台机器:

apt install -y qemu-system-x86 qemu-utils cpu-checker
kvm-ok
wget https://dl-cdn.alpinelinux.org/alpine/v3.22/releases/x86_64/alpine-virt-3.22.0-x86_64.iso
qemu-system-x86_64 -enable-kvm -m 2048 -cdrom alpine-virt-3.22.0-x86_64.iso -nographic

kvm-ok 显示加速可用,随后 Alpine 启动在几秒钟内到达登录提示符而不是缓慢爬行,这即是验证。没有嵌套,同样的命令要么直接拒绝,要么以约二十分之一的速度进行软件模拟,这是无法忽视的。

最后,确认接口从外部关闭:

curl -m5 -k https://<public address>:8006/ ; echo "exit $?"

连接超时是正确的答案。

后续

ZFS 上的快照在产生差异之前是免费的,因此每晚的 zfs-auto-snapshot 计划几乎不花费任何成本,并且比任何备份策略都拯救了更多的机器。裸机重建当天即可完成,但重建返回的是一台空机器,这与恢复你的机器是两回事。

随时恭候

选择城市,选择大小,用加密货币支付。

无需填写关于您的身份信息的表格,无需等待人工审批,无需电话验证。账单结清后,凭证将发送到您的邮箱。