4115 字
21 分钟

Ceph 19.2.7 在线升级:CRC 风险、滚动暂停与验收边界

2026-10-15 凌晨,将 Ceph 服务端和 Toolbox 从 19.2.6 升到了 19.2.7。29 个核心 daemon 已全部收敛,基础验收、四类卷的三节点重挂,以及 60 分钟现场观察通过。

这次升级带着明确的未解决风险:准备阶段发现两条新的客户端 CRC 错误,先停止发布,接受这两条事件的风险后才继续。CRC 根因仍未查明,不能认为 19.2.7 已经修复它。24 小时只读复核安排在 2026-10-16 02:50,截至本稿记录时尚未完成,稳定性验收仍待完成。

本文依据本轮执行记录和脱敏汇总整理,状态截点为 2026-10-15 04:05,时间均为北京时间。三台节点以 node-a、node-b、node-c 代称,省略内网地址、私有仓库地址、对象 UID、卷句柄、维护目录和凭据。文中的数量属于本次窗口基线,不代表集群以后一直保持这些数字。

本轮只更新 Ceph 补丁版本#

前面的 Rook 1.20.8 与 CSI 升级已经完成,这次保留管理层和客户端组合,只更新 Ceph 服务端及工具镜像。

对象升级前本轮结果
Ceph 核心 daemon19.2.619.2.7,29 个全部收敛
Toolbox 及其他运行中的 Ceph 容器原 Ceph 镜像更新到同一固定构建,单独核验
Rook Operator / cluster Chart1.20.8保持
Ceph CSI3.17.1保持
网络、存储和认证布局host 网络、msgr2、原池和 CRUSH、现用密钥保持

29 个核心 daemon 包括 3 MON、2 MGR、18 OSD、4 MDS 和 2 RGW。两套 CephFS 各有一个 active 和一个 standby-replay。三台物理机同时承载 Kubernetes 控制面、etcd、业务和 Ceph,因此节点重启、批量删 Pod、客户端密钥迁移都没有混进这个补丁窗口。

19.2.7 于 10 月 12 日发布,包含 CephFS/MDS、BlueStore 停顿和 RGW 签名兼容等修复;Rook 1.20 的支持范围包含 Squid 19.2.x。这提供了升级依据,但发布说明不能直接证明现网 CRC 或历史 CephFS 元数据缺失的根因已经覆盖。Ceph 19.2.7 发布说明、Rook Ceph 升级文档

先核对发布来源,再改两个镜像字段#

维护机和笔记本都有同名 Chart,内容却不一样。笔记本上的副本仍是旧版,不能因为目录名相同就拿来发布。

实际使用的是服务器上已经交付过的 Chart 1.20.8 工作副本和覆盖层。它没有 Git 元数据,又含有敏感配置,因此没有把整个目录复制进博客或仓库,而是核对交付摘要、当前 Helm release 清单、Chart 渲染结果和 live 对象。18 个非 Secret 对象与现有 release 对齐后,才生成候选。

源配置只改两处:

字段改动
cephImage.tag固定到 v19.2.7-20261009,同时附加 OCI index 摘要
toolbox.image使用相同构建和摘要的完整镜像引用

渲染后的差异限于 CephCluster.spec.cephVersion.image 和 Toolbox Deployment 的容器镜像,没有新增对象删除、存储布局变化或认证配置变化。Helm lint、完整渲染差异检查和 API server dry-run 均通过。

升级保护继续保留。下面是 CephCluster 的相关 spec 片段,不是完整 Helm values:

spec:
skipUpgradeChecks: false
continueUpgradeAfterChecksEvenIfNotHealthy: false
upgradeOSDRequiresHealthyPGs: true
storage:
osdMaxUpdatesInParallel: 1

这意味着 OSD 一次只更新一个,保留健康 PG 和 daemon 可停止检查。后面遇到问题时,也没有把这些检查关掉来加快进度。

镜像摘要要按层级核对#

对外记录使用官方镜像引用;实际发布经过现有镜像代理,先验证两端内容相同,再在三个节点完整预拉取:

quay.io/ceph/ceph:v19.2.7-20261009@sha256:3fc0a79f1c671f0e75be24ba77a4ab32227e5ea080e16dfc0840a1dc6c30bf7e

这里有三种不同的摘要,不能直接互相比较:

层级本轮核对的内容
OCI index官方与代理的响应摘要、响应正文 SHA256 一致
linux/amd64 manifest目标平台和 manifest 摘要一致
image config / CRI image ID三节点实际缓存的镜像身份符合该构建

CRI 显示的 image ID 与多架构 OCI index 摘要不是同一个对象。只看到两者字符串不同,不能据此认定镜像被替换;只看到 tag 相同,也不能认定内容一致。

一个节点首次拉取出现过 tls: bad record MAC。保持 TLS 和固定摘要校验后重试成功,最后三个节点均完成核验。这个重试结果只说明目标镜像已经准备好,不能据此判断底层通信异常已经消除,也不能把它和 Ceph 客户端 CRC 直接归为同一根因。

预拉取还有实际作用:镜像仓库本身也依赖这套存储。先把完整内容准备在节点上,减少滚动期间再次依赖仓库读取的机会。

CRC 先触发停止,再明确接受这两条事件#

规划时,某节点近 24 小时已有 13 条 libceph ... integrity error, bad crc。这些是已知风险,没有因准备升级就标成已解决。

本轮从 01:33:48 开始执行。随后补查日志,发现同一节点在 01:38:45 又出现两条 CRC,发生在准备阶段、有效探针窗口之前,却仍属于本次执行期间的新增事件。因此,02:13 先记录停止,没有提交 Helm 升级,源配置、release revision 和 Operator 副本保持原状,第一轮测试卷正常清理。

继续的依据是随后明确接受了这两条新增 CRC 的风险。它们单列为准备阶段事件,没有并入此前 13 条历史记录,也没有把后续所有 CRC 一并忽略。之后的新 CRC、EIO、数据读回不一致、MDS damage 或 MON 丢失 quorum,仍是立即停止条件;单项业务连续不可用达到 60 分钟,也停止推进。

发布前的验证同时保留了完整边界:

  • 有效探针和日志窗口从 01:42:06 开始。四类卷的保留日志各覆盖至少 1,939 秒,超过约定的 30 分钟,持续写入、fsync 和读回均通过。
  • 接受上述两条事件后,从有效窗口起点重新核对完整内核日志,没有再发现新增 CRC;没有通过挪动起点把那两条事件抹掉。
  • 重建四个专用测试卷,继续承担升级期间和后续重挂验证。

这次决定承担的是一个仍未定因的风险。短窗口没有复现,只能作为当时继续操作的观测依据,不能替代根因调查。

一次 Helm 提交,等待实际 daemon 收敛#

时间事件
01:33:48开始准备与基线采集
01:42:06有效探针、日志观察窗口开始
02:13因准备阶段两条新增 CRC,发布前停止
约 02:20明确接受这两条事件的风险,恢复准备
02:23:41提交 cluster Helm 升级
02:23:48Helm revision 45 显示 deployed
02:25:16—约 02:27damaged 空字段误报,暂停并核实后恢复 Operator
02:49:2829 个核心 daemon 实际收敛到 19.2.7
03:01:08—04:01:48完成 3,639 秒现场观察
04:05:01最终验收与测试资源清理完成

发布只提交了一次 cluster release 的镜像变更,Chart 仍是 1.20.8。没有使用 --atomic 或自动 rollback,也没有手动批量删除 Ceph Pod。

后续由 Rook 按原生检查滚动。官方流程会在替换 daemon 前检查能否停止,并在更新后等待 quorum、PG 或 MDS 状态恢复。本轮保留这些检查,OSD 并发为 1。Rook 滚动升级流程

OSD 替换期间,短暂出现过 17/18 up 和相应 HEALTH_WARN,等待恢复后再处理下一个。这个过程需要结合正在替换的对象、PG 和 I/O 判断;不能把预期切换中的每个告警都当成失控,也不能只因“正在升级”就放过额外故障。

Helm 在 02:23:48 就返回 deployed,但真正收敛直到 02:49:28。中间即使新工作负载已经 Ready,仍有旧 RGW 处于退出过程,实际版本仍是混合状态。Helm 成功、CephCluster Ready、所有实际 daemon 完成升级,是三个需要分别验证的事实。

damaged 空字段造成了一次真实暂停#

三个新 MON 的启动日志里,各打印了两行空的 FSMap 字段。日志里出现了 damaged 这个词,字段后面却没有 damaged rank。

监测规则最初使用宽泛关键词匹配,把六行空字段当成损坏事件。规则触发后,确实停止了 Rook Operator,并确认 Operator Pod 已经退出;没有把误报仅仅记在日志里后继续滚动。

暂停后的核对分为三层:

  1. 原生 FSMap 的 damaged 集合为空,两套 active MDS 的 damage 列表也为空。
  2. 集群 HEALTH_OK、18 OSD up/in,四个测试卷 I/O 正常。
  3. 原日志显示的是空字段,没有出现真实 rank damage 或 MDS_DAMAGE。

确认误报后,保留原始事件,将检测规则收窄到真实损坏状态,并增加“空字段不触发、真实 rank damage 必须触发”的正反例自检,再恢复 Operator 原来的一个副本。没有执行 damage 清除、crash 归档或旧密钥恢复来让检查变绿。

这也再次确认了暂停的边界:停 Operator 只能阻止它继续下发调谐,已经交给 Kubernetes 的 Deployment 更新仍可能完成。 暂停不等于撤销,暂停期间也会失去部分自动调谐和故障恢复能力。因此要确认 Operator 真的退出,还要检查已经下发的滚动;本轮没有设置旧维护流程中的定时自动恢复。Rook 暂停 Operator 的维护说明

验收覆盖原身份、测试数据和真实业务#

版本收敛后,先确认原来的存储仍是原来的存储:FSID、18 个 OSD UUID、CRUSH 和 17 个池的布局保持,原 95 对业务 PV/PVC 的 UID、绑定和 CSI volumeHandle 保持。清理后,原 94 个 VolumeAttachment 全部 attached,14 个 VMI Running/Ready。

窗口中有一台并行维护的虚机在 Ceph 发布前已经重建过 VMI,因此保存初始基线,只刷新了这一项发布前的当前 VMI UID,继续核对逻辑 VM 和原磁盘。没有为了让验收通过而放宽全部资源的身份检查。

Ceph 服务端 KeyGeneration 继续为 1,四个 CSI Secret 只比较 UID/resourceVersion,没有读取值,也没有回放旧 Secret。

四类测试卷,逐节点验证持久数据#

在独立测试命名空间中,为下面四类存储各创建一个 1Gi 卷:

存储类路径
ceph-blockRBD
ceph-block-hddHDD RBD
ceph-filesystemCephFS
ceph-filesystem-hddHDD CephFS

探针持续写入、fsync、读回逐字节比较,并检查固定持久 marker。升级后,每类卷在三个节点分别挂载验证,共 12 项重挂检查。其中初始节点的检查可能仍在同一节点,不能写成 12 次全部都是跨节点移动。

重挂检查有一个容易忽略的条件:marker 不存在就必须失败,不能顺手重新初始化。 否则挂错卷、丢失旧数据后新建文件,也可能被误报成“读写正常”。对象删除和重挂还核对了 PVC/PV UID、CSI handle 及 Pod 的 UID/resourceVersion 前置条件,避免清理并行任务的资源。

S3 和应用检查要真正读取内容#

S3 使用专用前缀,验证普通对象及 16MiB、4 分片 multipart 对象的 PUT、GET、HEAD、读回 SHA256、预签名 GET 和 DELETE,最后清理本轮对象。

multipart ETag 单独核对 HTTP 响应,没有把它当作正文 MD5;客户端展示的 MD5 sum 还可能来自对象元数据,不能拿展示字段代替实际下载校验。本次覆盖的是现用客户端路径,没有据此宣称所有 SDK、签名组合和 S3 功能都已验证。

真实业务验收覆盖 7 套 PostgreSQL、5 套 MariaDB、9 套 Redis 的角色和复制,以及 27 个 Sentinel 的仲裁检查。同时检查 GitLab readiness/Gitaly、Harbor health、镜像 manifest 和真实 blob 的 SHA256、镜像站实际文件读取、DNS、28 条入口路径及 12 个虚机内服务端口。入口返回值按业务预期判断,不能把正常的鉴权拒绝一律算成故障。

镜像站检查了后端 Service 和公开 HTTPS 上两条 hardlink 路径的实际内容。它证明的是这些文件在当时可读且校验一致,没有覆盖整个 CephFS,也没有证明历史元数据缺失的根因已经修复。

60 分钟通过,仍有明确的证据边界#

完成重挂和基础功能验收后,从 03:01:08 到 04:01:48 进行了 3,639 秒现场观察。保留了 200 次监测样本、50 个 daemon 日志片段,观察期内新增错误匹配为 0,观察期日志采集缺口为 0。四类探针最后分别完成 1,941、1,861、1,901、1,851 轮。

最终确认三个 MON 保持 quorum、18/18 OSD up/in、745 PG clean,两套 CephFS 主备正常、damage 为空。除了 29 个核心 daemon,还单独核对 Toolbox、exporter、crashcollector 和日志容器,共 68 个运行中的 Ceph 容器使用固定目标镜像;已结束的历史 Job 不混入运行中镜像统计。

随后正常清理本轮注册的四只测试 PVC/PV、相应 VolumeAttachment 和测试命名空间,重新核对原业务卷和虚机。没有按名称模糊匹配删除资源。

这段观察与独立的数据库备份/PITR 维护并行,后者创建了自己的隔离恢复资源,也出现过数据库重建和切主。验收限定原有生产数据库,保留瞬时异常及后续复查结果,没有把其他任务的新增 PVC 当成本轮遗留。因此,它不是隔离于其他维护的纯 Ceph 稳态区间,也不能单凭时间重合就把所有业务变化归因于 Ceph。

性能数据同样只作现场对照:OSD apply/commit 最大瞬时 gauge 从窗口起点的 8/8ms,到最终的 22/22ms,中间也有更低采样。并行负载下这些离散值不足以评价性能提升、尾延迟或容量,本轮没有做相关基准测试。

日志结论也只对已经完整采集的观察期负责。升级滚动中的容器替换、历史日志保留范围,都要单独看;轮转、截断或采集缺口应记为 INCOMPLETE,不能用有限样本没有匹配替代全窗口无错误。

尚未完成的事#

CRC 风险仍然存在。 规划时的 13 条历史 CRC、本轮准备阶段被明确接受的两条新增 CRC,均保留在记录中。有效进入窗口与 60 分钟现场观察没有再发现新增匹配,仍不足以确定根因,更不能承诺以后不再出现。

三项客户端 CephX 告警仍保持静默。 现用 CSI 和 mirror peer 的 aes 兼容设置保留,没有把告警静默写成认证问题解决,也没有在这个补丁窗口强行收紧为只允许 aes256k。此前 msgr2、host 网络和 CephX 服务端轮换的服务端代次继续保留。

本次没有建立升级前恢复点。 这是明确选择接受的恢复限制,不是推荐的维护前提。本任务没有新建 etcd、数据库、PV、虚机磁盘、RGW 对象或配置恢复备份;并行任务后来产生的备份,也不能补成提交升级前的统一恢复点。历史材料没有在本轮证明当前完整恢复能力,不能承诺回到升级前状态或对象零丢失。

出现真实故障时,优先保住 quorum、现有 daemon 和业务 I/O,再根据原因做前向修复。Helm rollback、把镜像改回 19.2.6、恢复旧 Secret,都不能直接当作数据恢复方案;本轮没有验证镜像降级兼容性。

24 小时复核仍待完成。 以 10 月 15 日 02:49:28 的实际收敛时刻为起点,已安排 10 月 16 日 02:50 做一次只读复核,继续检查版本、quorum、OSD/PG、MDS damage、客户端 CRC/EIO、认证、crash、业务复制和入口,并核对日志覆盖范围。到这份草稿的状态截点,结果仍是待完成,不能提前写成 24 小时稳定性通过。

另外,写稿时官方列出的 Squid 预计维护结束日期是 2026-10-31。19.2.7 是本次补丁落点,后续大版本升级还需要独立规划和窗口。Ceph 版本生命周期