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 核心 daemon | 19.2.6 | 19.2.7,29 个全部收敛 |
| Toolbox 及其他运行中的 Ceph 容器 | 原 Ceph 镜像 | 更新到同一固定构建,单独核验 |
| Rook Operator / cluster Chart | 1.20.8 | 保持 |
| Ceph CSI | 3.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:48 | Helm revision 45 显示 deployed |
| 02:25:16—约 02:27 | damaged 空字段误报,暂停并核实后恢复 Operator |
| 02:49:28 | 29 个核心 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 已经退出;没有把误报仅仅记在日志里后继续滚动。
暂停后的核对分为三层:
- 原生 FSMap 的 damaged 集合为空,两套 active MDS 的 damage 列表也为空。
- 集群 HEALTH_OK、18 OSD up/in,四个测试卷 I/O 正常。
- 原日志显示的是空字段,没有出现真实 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-block | RBD |
ceph-block-hdd | HDD RBD |
ceph-filesystem | CephFS |
ceph-filesystem-hdd | HDD 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 版本生命周期