HOME

Proxmox VE + Ceph 集群搭建

文章目录33 节

最近想深入了解 Proxmox VE 与 Ceph 分布式存储,因此在 VMware vSphere 8.0 上搭建一套三节点 PVE + Ceph 实验集群。本文按实际操作顺序记录 PVE 安装、四套网络规划、主机名与 Corosync 排错、Ceph Tentacle 软件源、MON/MGR/OSD、三副本 RBD、CephFS/MDS 以及内网 HTTPS 证书配置,并保留新旧版本界面差异和实际踩坑过程。

实验环境

项目配置
虚拟化平台VMware vSphere 8.0
Proxmox VE9.2.2
内核7.0.2-6-pve
Debian13(trixie)
PVE 节点pve-01pve-02pve-03
系统盘每节点 32 GB
Ceph 数据盘每节点 200 GB,保持为独立裸盘
网卡每节点 4 块 VMXNET3

节点与网络规划

节点FQDNPVE 管理网 vmbr0Corosync 集群网 vmbr1Ceph Public 网络 vmbr2Ceph Cluster 网络 vmbr3
pve-01pve-01.lan10.0.10.1/2410.0.11.1/2410.0.12.1/2410.0.13.1/24
pve-02pve-02.lan10.0.10.2/2410.0.11.2/2410.0.12.2/2410.0.13.2/24
pve-03pve-03.lan10.0.10.3/2410.0.11.3/2410.0.12.3/2410.0.13.3/24

四套网络的用途不能混淆:

  • 10.0.10.0/24 用于 PVE Web 管理、SSH 和节点管理。
  • 10.0.11.0/24 只用于 Proxmox 集群的 Corosync Link 0。
  • 10.0.12.0/24 用作 Ceph Public Network,承载 RBD、CephFS 客户端与 Ceph 服务之间的通信。
  • 10.0.13.0/24 用作 Ceph Cluster Network,专门承载 OSD 复制、恢复和心跳流量。

Corosync 的“集群网络”与 Ceph 的 Cluster Network 是两个不同概念。10.0.11.0/24 不能同时作为 Ceph Cluster Network。

安装三个 PVE 节点

创建 vSphere 虚拟机

在 vSphere 的标准交换机 vSwitch0 上为 PVE 规划了以下 Port Group:

Port GroupVLAN IDPVE 网卡Linux Bridge用途
PVE 管理网络未打标签nic0vmbr0PVE Web、SSH 和节点管理
PVE Corosync 集群网络10ens224vmbr1Corosync Link 0
PVE Ceph Public 存储网络11ens256vmbr2Ceph 客户端与服务通信
PVE Ceph Cluster 后端复制网络12ens161vmbr3OSD 复制、恢复和心跳

vSwitch0 上的 PVE 管理、Corosync、Ceph Public 和 Ceph Cluster Port Group

vSwitch0 当前只有一条 vmnic0 1000 Mbps 物理 uplink,因此这四套网络是 VLAN 层面的逻辑隔离,不是物理隔离。对本次 HomeLab 来说,三台 PVE 虚拟机都运行在同一台 ESXi 主机上,同一 VLAN 内的 PVE 节点间流量由 vSwitch 在主机内部交换,不需要经过 vmnic0

这类节点之间的通信属于“东西向流量”。访问路由器、互联网或其他 ESXi 主机的“南北向流量”仍然需要经过 vmnic0。如果后续将 PVE 节点迁移到不同 ESXi 主机,Ceph 流量也会转为跨主机通信并受到物理 uplink 带宽限制。

vSphere 中的 PVE 虚拟机硬件配置

初始创建虚拟机时为每个 PVE 节点配置了三块 VMXNET3 网卡。在 Ceph 初始化前根据官方网络建议,又为每个节点增加第四块 VMXNET3,用于 Ceph Cluster 后端复制网络。VMXNET3 是 VMware 的半虚拟化网卡,界面显示的链路速率不代表实际业务一定能达到对应带宽。

PVE 虚拟机的四张网卡已重新绑定到正确 Port Group

踩坑:重命名 Port Group 后 PVE 网卡断开

为了让名称与 PVE 和 Ceph 官方术语一致,本次将原有 Port Group 重命名为 PVE Corosync 集群网络PVE Ceph Public 存储网络PVE Ceph Cluster 后端复制网络。在当前 vSphere 环境中,虚拟机配置没有自动跟随新的 Port Group 名称,导致对应虚拟网卡断开。

故障时三台 PVE 的 ens224/vmbr1ens256/vmbr2 都显示 NO-CARRIER/DOWN,PVE-01 只看到自己一个集群节点,Quorate: No,Corosync 中的 PVE-02 和 PVE-03 处于 disconnected

处理方法是分别打开三台 PVE 虚拟机的“编辑设置”页面,为每张虚拟网卡重新选择改名后的 Port Group,并确认“已连接”和“启动时连接”。修复后四张网卡全部恢复 UP/LOWER_UP,PVE 集群也恢复 Nodes: 3Quorate: Yes

数据盘在 vSphere 中直接挂载给 PVE,不在操作系统安装阶段建立文件系统或 LVM,后续由 Ceph 创建 OSD 时使用。

完成 PVE 安装

Proxmox VE 安装许可页面

阅读并同意许可协议。

选择 Proxmox VE 系统安装磁盘

选择 32 GB 系统盘安装 PVE,不要选中为 Ceph 准备的 200 GB 数据盘。

设置位置和时区

位置选择 China,时区选择 Asia/Shanghai

设置管理员密码和电子邮件地址

设置 root 密码和有效的告警邮箱。截图中使用的 mail@example.invalid 只是文档示例,实际环境应换成可接收告警的地址。

设置主机名和管理地址

初次安装时填写错误的 FQDN

PVE 节点名会进入 pmxcfs、证书和集群配置,应在安装时直接填入最终 FQDN。

三个节点分别是:

节点Hostname (FQDN)IP Address
pve-01pve-01.lan10.0.10.1/24
pve-02pve-02.lan10.0.10.2/24
pve-03pve-03.lan10.0.10.3/24

本次初次安装时输入了 pve.lan,后来将系统主机名改为 pve-01,但 pmxcfs 仍保留旧节点名 pve,最终导致在 Web 界面编辑网络时出现 500: proxy not allowed。完整排查与修复见 Proxmox VE 9.2 编辑网络配置报 500 proxy not allowed 排查记录

在创建集群前,三台节点都应确认主机名已经稳定:

# 短主机名应分别是 pve-01、pve-02 和 pve-03
hostname

# FQDN 应分别是 pve-01.lan、pve-02.lan 和 pve-03.lan
hostname -f

# 确认 PVE 实际识别到的节点名
pvesh get /nodes --output-format json-pretty

配置 PVE 9.2 软件源

PVE 9.2 基于 Debian 13(trixie),安装器默认使用 Deb822 格式的 .sources 文件。

启用 PVE no-subscription 源

本次实验没有 Proxmox 订阅,/etc/apt/sources.list.d/proxmox.sources 使用以下内容:

Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg

同时在 /etc/apt/sources.list.d/pve-enterprise.sources 中保留企业源配置,但追加或修改为:

Enabled: no

这只是禁用需要订阅的软件源,不代表获得企业订阅支持。修改后在每个节点顺序执行:

# 刷新索引,确认没有 401 Unauthorized 或签名错误
apt update

# 验证 PVE 版本
pveversion

三个节点实际结果均为:

pve-manager/9.2.2/b9984c6d90a4bd80 (running kernel: 7.0.2-6-pve)

可选:去除未订阅弹窗

这个操作只修改 PVE Web 前端对未订阅状态的判断,不会为系统添加订阅,也不会改变软件源或更新权限。不介意弹窗时可以跳过本节。

三个节点分别执行:

# 前端文件路径
FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"

# 每次修改前创建带时间戳的备份
BACKUP="${FILE}.bak-$(date +%Y%m%d-%H%M%S)"
cp -a "$FILE" "$BACKUP"

# 只在 checked_command 函数范围内替换未订阅判断
sed -i \
  "/checked_command: function/,/} else {/ \
  s/res\\.data\\.status\\.toLowerCase() !== 'active'/false/" \
  "$FILE"

# 重启 Web 代理并验证服务状态
systemctl restart pveproxy.service
systemctl is-active pveproxy.service

# 记录备份文件,便于后续恢复
echo "$BACKUP"

本次三台节点都已完成修改,pveproxy.service 保持 active。Proxmox 软件包升级可能覆盖该文件,升级后需要重新检查。

需要恢复时,将下面的备份文件名替换为实际时间戳:

FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"

cp -a \
  "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.bak-YYYYMMDD-HHMMSS" \
  "$FILE"

systemctl restart pveproxy.service
systemctl is-active pveproxy.service

配置管理、Corosync 和 Ceph 网络

安装器已为第一块网卡创建 vmbr0。在每个节点的“系统 → 网络”中再创建 vmbr1vmbr2vmbr3,并将它们分别绑定到 vSphere 中对应的 Corosync、Ceph Public 和 Ceph Cluster Port Group。

PVE-01 的管理、Corosync、Ceph Public 和 Ceph Cluster Linux Bridge 配置

PVE-01 的实际网络配置如下。nic0ens224ens256ens161 是本次虚拟机里的网卡名,其他环境必须按 ip -br link 的结果替换:

auto vmbr0
iface vmbr0 inet static
    address 10.0.10.1/24
    gateway 10.0.0.1
    bridge-ports nic0
    bridge-stp off
    bridge-fd 0
# PVE 管理网络

auto vmbr1
iface vmbr1 inet static
    address 10.0.11.1/24
    bridge-ports ens224
    bridge-stp off
    bridge-fd 0
# Corosync 集群网络

auto vmbr2
iface vmbr2 inet static
    address 10.0.12.1/24
    bridge-ports ens256
    bridge-stp off
    bridge-fd 0
# Ceph Public 存储网络

auto vmbr3
iface vmbr3 inet static
    address 10.0.13.1/24
    bridge-ports ens161
    bridge-stp off
    bridge-fd 0
# Ceph Cluster 后端复制网络

PVE-02 和 PVE-03 使用同样的结构,只将四套网络的末位地址分别改为 .2.3。只有 vmbr0 配置默认网关,vmbr1vmbr2vmbr3 都不配网关。

VLAN 10、11 和 12 由 vSphere Port Group 负责打标签,因此 PVE 中的这三个 Linux Bridge 不再配置 VLAN ID,也不勾选“VLAN 感知”,避免重复打标签。MTU 统一保持 1500

为什么 /24 地址能使用 10.0.0.1 网关

我的 HomeLab 路由器 LAN 的实际网络是 10.0.0.0/16,网关为 10.0.0.1,但 PVE 管理地址配置成了 10.0.10.x/24。从普通三层配置看,10.0.0.1 不在 10.0.10.0/24 中,不应直接作为该接口的网关。

当前 PVE 生成了以下路由:

default via 10.0.0.1 dev vmbr0 proto kernel onlink

onlink 会强制内核把该网关当作二层直连邻居。同时 vSphere 底层二层网络可达,路由器也使用 /16,因此当前实验能正常访问外部网络。

这是实验环境的特例,不应作为通用 /24 配置照搬。新建环境时,更建议让管理地址的掩码与路由器网络规划保持一致,或在管理网内使用同一子网的网关。

统一配置 hosts

三个节点的 /etc/hosts 使用完全相同的内容:

127.0.0.1 localhost.localdomain localhost

# 管理:Proxmox 节点正式主机名固定解析到管理网
10.0.10.1 pve-01.lan pve-01
10.0.10.2 pve-02.lan pve-02
10.0.10.3 pve-03.lan pve-03

# 集群:供 Corosync 集群通信使用的独立名称
10.0.11.1 pve-01-cluster.lan pve-01-cluster
10.0.11.2 pve-02-cluster.lan pve-02-cluster
10.0.11.3 pve-03-cluster.lan pve-03-cluster

# 存储:供 Ceph 存储通信使用的独立名称
10.0.12.1 pve-01-storage.lan pve-01-storage
10.0.12.2 pve-02-storage.lan pve-02-storage
10.0.12.3 pve-03-storage.lan pve-03-storage

不要把 pve-01.lan 同时写到 10.0.10.110.0.11.110.0.12.1 三条记录中。同一节点主机名如果随机解析到不同网络,会影响 PVE 节点身份、证书和集群通信的可预期性。

当前 /etc/hosts 只为管理、Corosync 和 Ceph Public 网络定义了别名。Ceph Cluster 后端网络由 Ceph 通过 10.0.13.0/24 直接管理,当前不依赖 hosts 别名。

在每个节点上检查解析和四网互通:

# 确认本节点 FQDN 解析到管理网
hostname -f
getent hosts pve-01 pve-02 pve-03

# 确认集群和存储别名指向专用网络
getent hosts pve-01-cluster pve-02-cluster pve-03-cluster
getent hosts pve-01-storage pve-02-storage pve-03-storage

# 查看四套地址和路由,防止默认网关出现在 vmbr1、vmbr2 或 vmbr3
ip -br -4 address show
ip route show

# 从 PVE-01 验证另外两个节点的三套专用网络
ping -c 3 10.0.11.2
ping -c 3 10.0.11.3
ping -c 3 10.0.12.2
ping -c 3 10.0.12.3
ping -c 3 10.0.13.2
ping -c 3 10.0.13.3

实际验证时,三台节点的 vmbr0-3 全部处于 UP,PVE-01 到 PVE-02、PVE-03 的 10.0.11/12/13 三套专用网络均为 0% 丢包。

创建 PVE 集群

在 PVE-01 的“数据中心 → 集群”中创建集群 PVE-Cluster。正确做法是在创建窗口中为 Link 0 主动选择 PVE-01 的集群地址 10.0.11.1,而不是管理地址 10.0.10.1

本次实际操作时漏选了集群网络,创建后 Corosync 的 ring0_addr 使用了 10.0.10.1。PVE 9.2 管理界面没有“修改集群网络”或“删除集群”按钮,“系统 → 网络”也只管理网卡和 Linux Bridge,不会修改 Corosync。

当时集群只有 PVE-01,且没有虚拟机和容器,因此在备份和语法检查后,将 /etc/pve/corosync.conf 中的 ring0_addr 改为 10.0.11.1,并把 config_version 在原值基础上递增。完整的安全操作、回滚方法和多节点警告见 Proxmox VE 9.2 创建集群后修改 Corosync 集群网络

修正 PVE-01 后,再将 PVE-02 和 PVE-03 加入集群,并为它们的 Link 0 分别使用 10.0.11.210.0.11.3

验证 Corosync 和 quorum

# 确认集群有三个节点且保持法定票数
pvecm status

# 确认每个节点的 ring0_addr 都在 10.0.11.0/24
cat /etc/pve/corosync.conf

# 检查 Corosync Link 0 状态
corosync-cfgtool -s

当前实际配置的关键结果为:

Nodes:            3
Quorate:          Yes

Membership information
----------------------
0x00000001          1 10.0.11.1 (local)
0x00000002          1 10.0.11.2
0x00000003          1 10.0.11.3

/etc/pve/corosync.conf 中三个节点的 ring0_addr 也分别是 10.0.11.110.0.11.210.0.11.3。当前 config_version4;该数字是随配置变更递增的版本号,不是所有环境都应照搬的固定值。

准备 Ceph Tentacle 软件源

PVE 9.2 的 Ceph 安装向导可以自动写入软件源,也可以选择手动管理。本次开始使用 Proxmox 官方 Ceph Tentacle 源,但下载速度较慢,因此暂停安装后,先将三个节点切换到中科大镜像。

三个节点分别执行以下操作。为避免镜像站限速,apt update 和后续 Ceph 安装建议逐台进行:

# Ceph Deb822 软件源文件
SOURCE="/etc/apt/sources.list.d/ceph.sources"

# 保留当前配置,便于快速回滚
BACKUP="${SOURCE}.bak-$(date +%Y%m%d-%H%M%S)"
cp -a "$SOURCE" "$BACKUP"

# PVE 9.2 / Debian 13 使用 trixie 和 Ceph Tentacle
cat > "$SOURCE" <<'EOF'
Types: deb
URIs: https://mirrors.ustc.edu.cn/proxmox/debian/ceph-tentacle
Suites: trixie
Components: no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF

# 刷新索引,再检查软件来源和候选版本
apt update
apt-cache policy ceph ceph-common

echo "$BACKUP"

三个节点已确认使用以下源:

https://mirrors.ustc.edu.cn/proxmox/debian/ceph-tentacle

换源完成但尚未正式安装时,PVE-01 的版本结果为:

ceph:
  Installed: (none)
  Candidate: 20.2.2-pve1

ceph-common:
  Installed: 19.2.3-pve4
  Candidate: 20.2.2-pve1

PVE 基础环境中已有旧版 ceph-common 客户端组件,不代表 Ceph 集群已经安装和初始化。当时 ceph 元软件包仍是未安装状态。

中科大镜像的单节点顺序测试速度约为 24.7-27.1 MB/s。对三个节点同时发起下载时出现过 HTTP 429 Too Many Requests,因此后续 Ceph 安装将按 PVE-01、PVE-02、PVE-03 的顺序逐台执行。

踩坑:WebUI 安装向导会覆盖手工配置的 Ceph 源

三个节点切换到中科大镜像后,在 PVE-01 左侧导航栏进入“Ceph”并点击“安装 Ceph”。安装向导使用预设的 Proxmox 官方源,将 PVE-01 的 /etc/apt/sources.list.d/ceph.sources 重新写回官方地址,之前的镜像配置因此被覆盖。

软件源文件属于各节点本地配置,所以本次只有打开安装向导的 PVE-01 被改动,PVE-02 和 PVE-03 仍保持中科大源。停止安装后,先将 PVE-01 的 ceph.sources 恢复为中科大地址,再改用后台手工安装。

已经手工设置 Ceph 镜像源时,不要在未检查的情况下重新进入 WebUI 安装向导。每次调用向导后,都应重新检查 ceph.sourcesapt-cache policy ceph

逐台手工安装 Ceph 软件包

每个节点安装前先确认候选版本仍然来自中科大 Ceph Tentacle 源:

# 确认源地址没有被 WebUI 重新写回官方源
grep -E '^(URIs|Suites|Components):' \
  /etc/apt/sources.list.d/ceph.sources

# 逐台刷新软件索引
apt update

# Candidate 应为计划安装的 Tentacle 版本,并显示中科大源
apt-cache policy ceph ceph-common

本次后台手工执行的安装命令为:

apt install ceph ceph-mds ceph-volume gdisk nvme-cli

其中 ceph-mds 是 CephFS 的 Metadata Server,只使用 RBD 块存储时不是必需组件;本文后续创建了 CephFS,因此三台节点都实际使用了该组件。nvme-cli 用于查看和诊断 NVMe 设备,不使用 NVMe 时可按实际需求决定是否安装。

PVE-02 通过后台完成 Ceph Tentacle 软件包安装

截图中 PVE-02 已完成 cephceph-mdsceph-volume 以及 MON、MGR、OSD 相关软件包的安装,终端已返回 root 提示符。安装过程中还出现了:

chown: cannot access '/var/log/ceph/*.log*': No such file or directory
/usr/lib/tmpfiles.d/legacy.conf:14: Duplicate line for path "/run/lock", ignoring.

本次初次安装时 Ceph 日志尚未生成,systemd-tmpfiles 也明确忽略了重复定义,两条提示都没有中断 dpkg 安装。不过不能只凭返回命令提示符判断安装成功,还需要执行:

# 确认 Ceph 版本
ceph --version

# 需要的软件包应显示 ii(已安装)状态
dpkg-query -W -f='${db:Status-Abbrev}\t${Package}\t${Version}\n' \
  ceph ceph-mds ceph-volume gdisk nvme-cli

# 已安装版本和候选版本应保持一致
apt-cache policy ceph ceph-common

此时完成的只是 Ceph 软件包安装。在创建 Ceph 配置、MON、MGR 和 OSD 之前,ceph -s 还不能用来证明集群健康。

三台节点最终验证结果一致:

ceph version 20.2.2 (06f6a7ab7187f570d9fc04b7ac9664f1fb6b84b0) tentacle (stable)

Installed: 20.2.2-pve1
Candidate: 20.2.2-pve1
Source: https://mirrors.ustc.edu.cn/proxmox/debian/ceph-tentacle

Ceph 分布式存储

初始化 Ceph 集群网络

软件包安装完成后,进入“数据中心 → Ceph”。首次进入时会显示“Ceph 未初始化”,需要先创建一次基础集群配置。

Ceph 尚未初始化

点击“配置 Ceph”,在“配置”页选择当前节点对应的本地地址:

Public Network IP/CIDR:10.0.12.1/24
Cluster Network IP/CIDR:10.0.13.1/24
第一个 Ceph monitor:pve-01

这里填写的是 PVE-01 本机接口上的地址和掩码,不是只写网络号 10.0.12.0/2410.0.13.0/24。Public Network 对应 Ceph 客户端和服务通信,Cluster Network 对应 OSD 复制、恢复和心跳;两者都不使用管理网 10.0.10.0/24 或 Corosync 网 10.0.11.0/24

Ceph 初始化向导中的 Public Network 和 Cluster Network

命令行等价操作是在 PVE-01 执行一次:

# 仅在尚未存在 /etc/pve/ceph.conf 时执行一次
pveceph init \
  --network 10.0.12.0/24 \
  --cluster-network 10.0.13.0/24

初始化会创建集群级 /etc/pve/ceph.conf,该文件通过 PVE 的 pmxcfs 同步到其他节点,因此不要在 PVE-02、PVE-03 重复执行。初始化成功不等于已经拥有完整的 Ceph 存储,后续仍需创建其他 MON、MGR、OSD 和存储池。

Ceph 基础初始化成功

Ceph Monitor 与 Manager 的作用

初始化向导只创建了第一个 MON。随后在三个节点分别创建 MON 和 MGR,使控制面具备高可用能力。本次最终状态如下:

组件节点状态地址或角色
MONpve-01、pve-02、pve-03running10.0.12.1/2/3:6789
MGRpve-01active当前管理器主实例
MGRpve-02、pve-03standby热备,主实例故障时接管

三个 Ceph Monitor 与 Manager 的运行状态

Monitor(MON)

MON 是 Ceph 的集群控制面,主要负责维护并提供:

  • 集群成员和状态图(Monmap、OSDMap、PGMap 等)
  • MON 自身的 quorum 和选主
  • CephX 认证信息和集群配置
  • 向客户端和 OSD 提供当前集群拓扑

MON 不负责保存虚拟机数据。生产环境通常部署奇数个 MON,例如三个节点各一个,这样单个 MON 故障后仍可保持多数派。截图中的三个 MON 都绑定在 Ceph Public 网络的 10.0.12.x 地址上。

Manager(MGR)

MGR 是 Ceph 的管理与监控服务,主要提供:

  • 集群性能指标、容量和状态统计
  • Dashboard、Prometheus 等管理模块
  • 与编排、设备和服务管理相关的扩展模块
  • 向 PVE Web 界面提供 Ceph 管理数据

MGR 使用一个 active 实例和一个或多个 standby 实例。standby 不是额外的数据副本,而是控制服务的热备;当前 active MGR 失效后,其他节点可以自动接管。MGR 也不负责 OSD 数据复制,真正保存数据并执行副本/纠删码的是 OSD。

可以用以下命令核对控制面状态:

# 查看 Ceph 总体状态;初始化阶段没有 OSD 时可能出现 HEALTH_WARN
ceph -s

# 查看 MON quorum
ceph quorum_status --format json-pretty

# 查看 MGR 的 active/standby 状态
ceph mgr dump

当前阶段完成的是 Ceph 网络、基础配置、MON 和 MGR 控制面。还没有创建 OSD 和存储池,不能把此时的 ceph -s 当作“存储集群已经可用”的证明。

创建三节点 OSD

每台 PVE 虚拟机都有一块独立的 200 GB /dev/sdb,计划各创建一个 BlueStore OSD。创建 OSD 会清空目标磁盘,操作前先在三台节点分别执行只读检查:

# 核对系统盘与 200 GB 数据盘,目标盘不应有分区、文件系统或挂载点
lsblk -e7 -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL

# 只检查目标盘,available 应为 True,rejected reasons 应为空
ceph-volume inventory /dev/sdb

# 预演 ceph-volume 的 LVM 布局,不写入磁盘
ceph-volume lvm batch --report /dev/sdb

# 检查已有 OSD,首次创建前应为空
ceph osd tree

三台节点的检查结果一致:/dev/sdb 为 200 GB VMware 虚拟磁盘,没有分区、文件系统、LVM 或旧 Ceph 签名;针对目标盘的 inventory 返回 available=True,batch 预演计划使用整块磁盘创建一个 OSD。

本次全盘运行不带设备参数的 ceph-volume inventory 时,还出现过:

RuntimeError: /dev/pve/data_tmeta not found

这是扫描系统盘 PVE LVM thin-pool 隐藏元数据卷时触发的路径问题,/dev/mapper/pve-data_tmeta 实际存在。目标盘 /dev/sdb 的定向 inventory、PVE 磁盘接口和 batch 预演均通过,因此没有修改或删除系统盘 LVM,也没有把这个提示误判成数据盘不可用。

在每台节点的“Ceph → OSD”中点击“创建 OSD”,按以下参数逐台创建:

数据盘:/dev/sdb
DB 设备:不单独指定
WAL 设备:不单独指定
加密:关闭
设备类别:自动识别为 hdd
对象存储:BlueStore

对应的命令行操作是在每台节点分别执行:

# 仅在当前节点的 /dev/sdb 已确认是目标裸盘后执行
pveceph osd create /dev/sdb

为便于观察状态变化,本次按 PVE-01、PVE-02、PVE-03 的顺序创建,并在每一步后检查 ceph -sceph osd tree。最终 CRUSH 树为:

节点OSD类型状态原始容量
pve-01osd.0hdd / bluestoreup / in200 GiB
pve-02osd.1hdd / bluestoreup / in200 GiB
pve-03osd.2hdd / bluestoreup / in200 GiB

三台节点各有一个 BlueStore OSD

默认 replicated_rule 使用 host 作为 CRUSH 故障域,因此三副本会分别落在三台不同的 PVE 主机上,而不是只在同一主机的不同 OSD 之间复制。本实验每个节点只有一个 OSD,任何一个节点或 OSD 故障都会导致集群降级,但剩余两个副本仍满足默认 min_size=2 的读写下限。

验证 OSD 与容量

三个 OSD 全部创建完成后,ceph -s 返回:

health: HEALTH_OK
mon: 3 daemons, quorum pve-01,pve-02,pve-03
mgr: pve-01(active), standbys: pve-02, pve-03
osd: 3 osds: 3 up, 3 in
pools: 1 pools, 1 pgs
pgs: 1 active+clean

ceph -s 显示三个 OSD 均为 up 和 in

PVE Ceph 总览显示 HEALTH_OK

此时显示的一个 pool 和一个 PG 来自 Ceph 自动创建的 .mgr 管理池,不是供虚拟机使用的 RBD 业务池。实时配置为 size=3min_size=2,其中少量对象用于 MGR 管理数据。

界面显示的 600 GiB 是三块磁盘相加后的原始容量。以后创建三副本 RBD 池时,每份业务数据会保存三份,因此理论业务容量约为 200 GiB;扣除 BlueStore 元数据、Ceph 保留空间和安全水位后,当前 ceph df detail 估算的最大可用容量约为 190 GiB。不要把 600 GiB avail 直接当作虚拟机可分配容量。

可以使用以下命令复核:

# 三个 OSD 应全部 up/in,并分别位于三台 host 下
ceph osd tree

# 查看每个 OSD 的原始容量、使用率和 PG 数量
ceph osd df tree

# 确认当前唯一的池是 .mgr,并查看 size/min_size
ceph osd pool ls detail

# 区分 RAW STORAGE 与三副本池的 MAX AVAIL
ceph df detail

当前 Ceph 控制面和三节点 OSD 数据面已经正常,接下来创建供 PVE 虚拟机使用的 RBD 业务池。

创建 RBD 业务池并接入 PVE

在“数据中心 → Ceph → Pools”中创建 VM_Pool。本次使用三台主机、三个 OSD,创建时填写:

名称:VM_Pool
大小(size):3
PG 自动缩放模式:on
添加存储:勾选

创建 VM_Pool 时将目标副本数设为 3

这里的“大小”对应 Ceph 的 size,表示集群健康时每个对象应保存的目标副本数,并不是磁盘容量。三节点各有一个 OSD,size=3 会通过默认 replicated_rule 将三个副本分别放到三台主机。

第一次操作时曾把“大小”误填为 2,实时配置因此变成 size=2 min_size=2。这种组合虽然能获得约 285 GiB 的估算可用容量,但任意一个 OSD 或节点离线后只剩一个副本,低于 min_size=2,业务池会暂停 I/O。确认字段含义后删除了这个空池,并以 size=3 重新创建。

创建完成后编辑 Pool,将“最小副本数”设置为 2:

VM_Pool 使用 size 3 和 min_size 2

min_size=2 表示至少有两个可用副本时才允许 I/O。正常状态保存三份副本;一台节点或 OSD 故障时,剩余两份仍能继续提供读写;再损失一份后则停止 I/O,以避免只剩单副本时继续写入带来的数据风险。因此本实验最终采用 size=3 min_size=2,而不是 size=2 min_size=2

勾选“添加存储”后,PVE 自动为 Pool 启用 rbd 应用,并将它写入集群级 /etc/pve/storage.cfg

rbd: VM_Pool
        content rootdir,images
        krbd 0
        pool VM_Pool

使用以下命令核对 Pool、PG、容量和 PVE 存储状态:

ceph -s
ceph osd pool ls detail
ceph osd pool autoscale-status
ceph df detail
pvesm status

最终检查结果为:

pool 'VM_Pool' replicated size 3 min_size 2 application rbd
129 pgs: 129 active+clean
VM_Pool MAX AVAIL: 190 GiB
PVE storage VM_Pool: rbd / active

创建界面默认给出了 128 个 PG,同时启用了 PG autoscaler。当前 autoscaler 建议将 VM_Pool 调整到 32 个 PG,Ceph 会在后台逐步合并;调整期间可能短暂看到 peering,应等待 ceph -s 恢复为全部 active+clean 后再进行故障测试。由于最终使用三副本,600 GiB 原始容量对应的业务池估算可用容量约为 190 GiB。

创建 CephFS 与 MDS 高可用

RBD 用于虚拟机和容器的块设备,CephFS 则提供可以由多个 PVE 节点同时挂载的共享文件系统。本实验继续创建名为 cephfs 的 CephFS,并勾选添加到 PVE 存储。创建任务自动完成了以下操作:

  • 创建数据池 cephfs_data,用于保存文件实际内容。
  • 创建元数据池 cephfs_metadata,用于保存目录树、文件名、inode、权限、配额和快照等文件系统元数据。
  • 为两个 Pool 设置 cephfs application。
  • 创建文件系统 cephfs,并加入 PVE 集群存储配置。
  • 等待一个 MDS 进入 active 状态后结束任务。

CephFS 创建任务完成并返回 TASK OK

MDS 是 CephFS 的元数据服务进程,负责路径解析、目录操作、客户端会话、能力授权和文件锁协调。它不保存文件内容,也不是 CephFS 的额外数据副本;数据和元数据的持久化与三副本仍由底层 OSD Pool 完成。

本次在三台节点都创建了 MDS,实时状态为:

cephfs:1 {0=pve-03=up:active} 2 up:standby
max_mds: 1
active MDS: pve-03
standby MDS: pve-01, pve-02

CephFS 使用一个 active MDS 和两个 standby MDS

max_mds=1 表示当前文件系统只有一个活动 rank,因此一个 MDS 负责处理请求,另外两个作为故障接管候选。active MDS 故障后,standby 会自动接管;这与把 max_mds 提高到多个 active rank 进行元数据负载扩展是两回事。截图中的 MDS 地址全部位于 10.0.12.0/24 Ceph Public Network,符合前面的网络规划。

两个 CephFS Pool 也沿用三节点副本策略:

cephfs_data:     size 3, min_size 2, application cephfs
cephfs_metadata: size 3, min_size 2, application cephfs

元数据池还自动设置了较高的恢复优先级和 autoscale bias,以优先保障文件系统元数据。数据池的 PG autoscaler 会像 VM_Pool 一样在后台收敛,检查期间所有 PG 均为 active+clean

CephFS 已作为共享存储挂载到三个 PVE 节点:

存储 ID:cephfs
挂载路径:/mnt/pve/cephfs
内容:backup、iso、vztmpl
状态:active

PVE 中的 RBD 与 CephFS 共享存储均已启用

ceph fs status 显示三个客户端,正好对应三台 PVE 节点。实际挂载源包含三个 MON 地址 10.0.12.1-3,文件系统类型为 ceph,证明节点不是只显示一条存储配置,而是已经完成内核挂载。

需要注意,VM_Poolcephfs_datacephfs_metadata 都使用同一组三块 200 GiB OSD。PVE 界面为 RBD 和 CephFS 各显示约 190 GiB,并不表示获得了两份可以相加的容量;它们竞争同一个 600 GiB 原始空间。另外,将 PVE 备份写到同一 Ceph 集群只能提供共享访问,不能防御整个 Ceph 集群或底层 ESXi 存储故障,重要备份仍应写入独立 PBS 或其他独立存储。

可以使用以下命令复核 CephFS:

ceph -s
ceph fs status
ceph fs get cephfs
ceph mds stat
ceph osd pool ls detail
pvesm status
findmnt -T /mnt/pve/cephfs

最终集群保持 HEALTH_OK,CephFS 显示 1/1 healthy,三个 OSD 均为 up/in,检查时 217 个 PG 全部为 active+clean

配置 PVE HTTPS 证书

PVE 9.2 的 ACME 界面与旧版文章不同:账户注册、DNS 质询插件和节点证书域名分别配置。ACME 账户DNS Plugin属于集群级配置,创建一次即可;每台节点的域名和证书仍需分别添加、申请。

选择证书域名

PVE 安装时使用的 pve-01.lanpve-02.lanpve-03.lan 是内网主机名,Let’s Encrypt 不会为 .lan 私有后缀签发公网信任证书。这里增加 HTTPS 访问别名,不修改 PVE 节点身份:

节点ACME 证书域名内网解析地址
pve-01pve-01.lab.xiangjigong.top10.0.10.1
pve-02pve-02.lab.xiangjigong.top10.0.10.2
pve-03pve-03.lab.xiangjigong.top10.0.10.3

DNS-01 质询只需要 DNS API 创建 _acme-challenge TXT 记录,不要求这些域名有公网 A 记录。但浏览器访问 PVE 时,内网 DNS 仍需将域名解析到对应的管理地址。现有的 pve-01.lan 等主机名、/etc/hosts 和集群节点名称保持不变。

注册 ACME 账户

在“数据中心 → ACME → 账户”中新增账户:

账户名称:pve
ACME 目录:Let's Encrypt V2
电子邮件:填写可接收证书告警的地址

阅读并接受服务条款后注册。Let’s Encrypt V2 是生产环境目录;只有专门测试时才使用 Staging 目录。本次 PVE-01 的 pve 账户已经注册成功,其他节点不需要重复创建。

创建阿里云 DNS 插件

在“数据中心 → ACME → Challenge Plugins”中新增:

插件 ID:aliyun-dns-ram
验证延迟:30
DNS API:Alibaba Cloud DNS
Ali_API=https://alidns.aliyuncs.com/
Ali_Key=阿里云 RAM 用户的 AccessKey ID
Ali_Secret=与该 ID 配对的 AccessKey Secret

Ali_API 使用默认值即可。API 数据只填写键值,不添加引号、空格或反引号。建议专门创建 RAM 用户,例如 pve-acme,授予 DNS 权限后再创建 AccessKey;不要在文章或截图中保留主账号密钥。RAM 用户绑定权限不等于已经创建 AccessKey,必须在“认证管理 → AccessKey”中生成一对匹配的 ID 和 Secret。

PVE 9.2 执行 pvesh get /cluster/acme/plugins 时会在 data 列直接显示 Ali_KeyAli_Secret。不要把完整输出粘贴到文章、工单或聊天记录中;排查插件时只检查插件 ID、API 类型和必要的字段长度。

PVE 集群的 ACME 账户和阿里云 DNS 插件配置

PVE 9.2 的 DNS API 选择列表

在节点创建域名时,质询类型选择 DNS,而不是 HTTP。HTTP-01 要求 Let’s Encrypt 从公网访问节点的 80 端口,本实验环境没有这个入口;DNS-01 通过阿里云 API 完成验证。

PVE 9.2 的 ACME 质询类型选择

添加节点域名并申请证书

分别进入每个节点的“系统 → 证书 → ACME → 添加”,为节点添加对应域名:

质询类型:DNS
域名:pve-01.lab.xiangjigong.top
插件:aliyun-dns-ram

PVE-02 和 PVE-03 分别使用 pve-02.lab.xiangjigong.toppve-03.lab.xiangjigong.top。添加域名只保存配置,不代表证书已经签发;还要在对应节点点击“立即申请证书”,或在节点后台执行:

# 在当前节点申请 ACME 证书;域名和插件来自节点配置
pvenode acme cert order

本次 PVE-01 的实际成功输出包含:

Add TXT record: _acme-challenge.pve-01.lab.xiangjigong.top
Status is 'valid', domain 'pve-01.lab.xiangjigong.top' OK!
All domains validated!
Setting pveproxy certificate and key
Task OK

PVE 9.2.2 阿里云签名错误排查

第一次申请时,Let’s Encrypt 订单和授权都已创建,但 PVE 日志显示:

The validation for pve-01.lab.xiangjigong.top is pending!
Error add txt for domain:_acme-challenge.pve-01.lab.xiangjigong.top
TASK ERROR: ... proxmox-acme setup ali ... failed: exit code 1

阿里云操作审计进一步显示:

事件:DescribeDomainRecords
操作者:pve-acme
错误码:SignatureDoesNotMatch

这说明请求已经到达阿里云,RAM 权限和网络策略都不是根因。PVE 9.2.2 的 libproxmox-acme-plugins 1.7.1 搭载了旧版 ACME 函数库,阿里云插件调用 _url_encode upper-hex 时实际生成了小写的 %3d;阿里云签名规范要求 %3D 这样的大写十六进制转义,因此 HMAC 签名不匹配。上游 acme.sh 已在 issue 6272 中针对第三方旧版函数库增加了兼容处理。

排查时还遇到过 ram.aliyuncs.comGetPolicy / EntityNotExist.Policy 事件。该事件由阿里云资源管理服务角色查询策略产生,不是 PVE 的 DNS 请求;判断证书问题时应筛选 alidns.aliyuncs.comDescribeDomainRecords 和 PVE 的源 IP。

在每台节点上备份并修补本地插件文件。该文件不在 /etc/pve 集群文件系统中,三台节点必须分别修补:

FILE="/usr/share/proxmox-acme/dnsapi/dns_ali.sh"
BACKUP="${FILE}.bak-acme-uppercase-$(date +%Y%m%d-%H%M%S)"
cp -a "$FILE" "$BACKUP"

# 将插件中的大小写编码调用改为专用的大写编码函数,并在 _ali_rest 前插入该函数
perl -0pi -e 's/_url_encode upper-hex/_ali_urlencode_upper/g; s#\n_ali_rest\(\) \{#\n_ali_urlencode_upper() {\n  {\n    _url_encode\n    echo\n  } | sed "s/%a/%A/g;s/%b/%B/g;s/%c/%C/g;s/%d/%D/g;s/%e/%E/g;s/%f/%F/g;s/%\\(.\\)a/%\\1A/g;s/%\\(.\\)b/%\\1B/g;s/%\\(.\\)c/%\\1C/g;s/%\\(.\\)d/%\\1D/g;s/%\\(.\\)e/%\\1E/g;s/%\\(.\\)f/%\\1F/g"\n}\n\n_ali_rest() {#s' "$FILE"

# 检查脚本语法并记录备份路径
sh -n "$FILE"
echo "$BACKUP"

本次三台节点均已完成补丁并保留备份。软件包升级可能覆盖手工修改,升级后应重新检查该文件;如果未来仓库提供包含上游修复的 libproxmox-acme-plugins,应优先升级软件包并移除手工补丁。

证书签发后的验证不要只看任务返回 OK,还要确认 PVE 实际加载了 Let’s Encrypt 证书。hostname -f 返回的是 PVE 节点身份(例如 pve-01.lan),不是 ACME 证书域名,因此检查 SNI 时要显式填写对应的证书域名:

# 证书列表中应出现 pveproxy-ssl.pem,issuer 应为 Let's Encrypt
pvesh get /nodes/$(hostname)/certificates/info

# 使用当前节点的 ACME 域名作为 SNI 检查 8006 端口返回的证书
DOMAIN="pve-01.lab.xiangjigong.top"
echo | openssl s_client \
  -connect 127.0.0.1:8006 \
  -servername "$DOMAIN" 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

本次三台节点的证书页面均显示 pveproxy-ssl.pem,主题分别为 pve-01.lab.xiangjigong.toppve-02.lab.xiangjigong.toppve-03.lab.xiangjigong.top,签发者均为 Let’s Encrypt。PVE-01 的证书详情还显示签发者为 YR1,有效期为 2026-07-22 至 2026-10-20。

PVE-01 已加载 Let's Encrypt 证书

PVE-02 已加载 Let's Encrypt 证书

PVE-03 已加载 Let's Encrypt 证书

PVE-01 的证书详细信息

让内网浏览器使用证书域名访问

证书只负责 TLS 加密和域名身份校验,不负责 DNS 解析。PVE 原有的 pve-01.lanpve-02.lanpve-03.lan 仍然是集群节点身份;浏览器访问 Let’s Encrypt 证书时,必须使用证书中的 pve-01.lab.xiangjigong.top 等完整域名。直接访问 https://10.0.10.1:8006 会因为证书 SAN 中没有这个 IP 而产生名称不匹配告警。

DNS-01 申请不要求公网 A 记录,但内网客户端必须把证书域名解析到管理网地址。单台 Mac 可以在 /etc/hosts 添加:

10.0.10.1 pve-01.lab.xiangjigong.top
10.0.10.2 pve-02.lab.xiangjigong.top
10.0.10.3 pve-03.lab.xiangjigong.top

多台客户端使用时,建议在路由器或内网 DNS 中建立同样的内部解析,而不是把管理地址发布到公网。修改 Mac 的 hosts 后刷新缓存:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

本次客户端使用 Shadowrocket。它启用 TUN 和 Fake-IP 时,域名可能被解析成 198.18.0.x,这不是 PVE 地址。Shadowrocket 中打开“设置 → DNS → 总是真实 IP”,重新启用代理/TUN;如果当前配置支持规则覆盖,再将内网域名和管理网设置为直连,并放在规则列表靠前位置:

[Rule]
DOMAIN-SUFFIX,lab.xiangjigong.top,DIRECT
IP-CIDR,10.0.0.0/16,DIRECT

Chrome 仍报 ERR_CONNECTION_CLOSED 时,完全退出并重新打开浏览器,然后在 chrome://net-internals/#dns 点击 Clear host cache,在 chrome://net-internals/#sockets 点击 Flush socket pools。最终应同时满足:域名解析到 10.0.10.x、TCP 8006 可达、证书校验通过并返回 HTTP/1.1 200 OK

总结

至此,这套三节点 PVE + Ceph 实验集群已经完成从底层网络到共享存储的完整搭建:

  • 三台 PVE 9.2.2 节点部署和主机名校正。
  • PVE 管理、Corosync、Ceph Public 和 Ceph Cluster 四套网络配置。
  • vSphere VLAN 10、11、12 Port Group 与三台 PVE 四网卡绑定,以及 Port Group 重命名后的断链修复。
  • 三节点 PVE 集群创建,quorum 正常。
  • Corosync Link 0 全部使用 10.0.11.0/24
  • Ceph Tentacle 中科大软件源配置、WebUI 覆盖源排查、候选版本检查和下载测试。
  • 三台 PVE 节点已逐台完成 Ceph 20.2.2-pve1 软件包安装,已安装版本与候选版本一致。
  • Ceph Public/Cluster 网络初始化完成,三个 MON 形成 quorum,三个 MGR 为一主两备。
  • 三台节点各创建一个 200 GiB BlueStore OSD,osd.0-2 全部 up/in,集群达到 HEALTH_OK
  • 已创建 VM_Pool RBD 业务池并接入 PVE 存储,最终参数为 size=3min_size=2、PG autoscaler on,检查时全部 PG 为 active+clean
  • 已创建 cephfscephfs_datacephfs_metadata,三台节点的 MDS 为一主两备,CephFS 已挂载为 PVE 共享存储。
  • PVE 9.2.2 ACME 阿里云 DNS 签名问题排查完成;三台节点均已应用大小写编码补丁并保留备份。
  • 三台 PVE 节点均已成功签发并加载各自 lab.xiangjigong.top 域名的 Let’s Encrypt 证书。
  • 已在客户端通过 hosts/内网解析和 Shadowrocket 直连规则完成 PVE-01 的域名 HTTPS 访问,验证证书、连接和 Web 响应均正常。

最终状态证明这套设计在实验环境中可以正常工作:三个 MON 形成 quorum,MGR 和 MDS 都具备主备接管能力,三个 OSD 按主机故障域保存副本,RBD 和 CephFS 均已作为 PVE 集群级共享存储启用。部署过程中遇到的主机名残留、Corosync 链路、WebUI 覆盖 Ceph 软件源、阿里云 DNS 签名和代理 Fake-IP 问题,也都通过实际日志和状态检查完成闭环。

这仍是一套 HomeLab,而不是生产架构。三台 PVE 虚拟机运行在同一台 ESXi 主机上,四套网络主要依靠 VLAN 进行逻辑隔离,虚拟 Ceph 数据盘也不能替代真正分散在不同物理服务器上的故障域。RBD 与 CephFS 共享同一组三块 OSD,同一 Ceph 集群中的备份同样不能替代独立 PBS 或异地备份。

本文的目标是完成可复现的集群搭建与基础验证。虚拟机磁盘性能、CephFS 跨节点读写、MDS 接管、OSD/节点故障恢复和 PG autoscaler 收敛过程,可以在此环境基础上继续作为独立实验展开。

技术分享 Proxmox VE Ceph Corosync 存储