Rook 升到 1.20.8:CSI 接管、回填等待与原卷验收
2026-09-30,把三台物理节点上的 Rook 从 1.19.10 升到了 1.20.8,Ceph CSI 从 3.16.2 升到了 3.17.1。Ceph 服务端和 Toolbox 继续使用 19.2.6,Kubernetes 继续使用 1.34.12。
10:57 开始准备,13:36 完成升级、基础验收、测试资源清理和最终双份 etcd 快照。中间真正花时间的有两件事:CSI 接管后,Helm 保存的清单与实际 Driver 配置没有对齐;恢复 Rook 调谐后,最后一个 OSD 又需要等待 PG 回填结束。
原有 95 组业务 PV/PVC、13 个 VMI 的身份保持,四类临时卷完成了跨节点重挂和在线扩容。不过,原计划的 24 小时观察后来提前结束,本轮结论是升级成功、基础验收通过,没有完成 24 小时稳定性验收。
本文依据 9 月 30 日的执行与检查记录整理,时间均为北京时间。节点用 node-a、node-b、node-c 代称,实际地址、私有仓库、备份位置和凭据省略。文中的版本、卷数量与部署方式属于当日窗口,不代表写作时或后续维护后的现状。配置片段只说明本次改动,不能代替完整环境覆盖层。
为什么在 Kubernetes 1.35 前先处理存储
前一天刚完成 Kubernetes 1.34.12 升级。当时 Rook 1.19.10、Ceph 19.2.6、Ceph CSI 3.16.2 没有一起更换。继续规划 Kubernetes 1.35 时,需要重新核对存储客户端的兼容范围。
Ceph CSI 的固定版本文档中,3.16.2 的 Kubernetes 测试范围到 1.34,3.17.1 的范围包含 1.35。这是本次先更新存储管理层与驱动的依据之一;测试矩阵没有覆盖,不等于已经证明旧驱动必然故障,但也不适合把未经覆盖的组合直接当作维护基线。Ceph CSI v3.17.1 测试矩阵
这里还有一个比镜像 tag 更重要的变化:Rook 1.20 不再替管理员创建、维护 CSI Driver 配置。原来通过 Rook ConfigMap 或 Chart 表达的 CSI 设置,要迁到 Ceph CSI Operator 的资源及独立 ceph-csi-drivers Chart。Rook 1.20 升级说明
因此,这次没有只替换 Ceph CSI 镜像,而是把 Rook、CSI Operator、Drivers Chart 和相关 sidecar 一起按目标组合更新。
| 组件 | 升级前 | 本轮结果 |
|---|---|---|
| Rook Operator、两个 Rook Chart | 1.19.10 | 1.20.8 |
| Ceph CSI Operator | 0.6.0 | 1.0.4 |
| 独立 ceph-csi-drivers release | 尚未安装独立 release | Chart 1.0.4,接管已有配置资源 |
| Ceph CSI RBD / CephFS | 3.16.2 | 3.17.1 |
| Ceph 服务端与 Toolbox | 19.2.6 | 保持 |
| Kubernetes | 1.34.12 | 保持 |
节点注册 sidecar、provisioner、attacher 分别更新到 2.17.0、6.2.0、4.12.0;resizer 2.1.0、snapshotter 8.5.0 保持。没有开启 CSI Addons、NFS 或 NVMe-oF。
本轮不升级宿主机或内核,不排空节点,也不主动重启业务虚机。之前完成的 msgr2、host 网络和服务端 CephX 轮换继续保留:daemon KeyGeneration 为 1,CSI 客户端仍使用 aes,不借升级改密钥类型。
两个 Rook Chart 之外,多了一份 CSI 配置来源
升级后的管理关系可以这样看:
rook-ceph release ├─ Rook Operator └─ Ceph CSI Operator
ceph-csi-drivers release └─ OperatorConfig / Driver / 对应权限 └─ CSI Operator 调谐 controller 和 node plugin
rook-ceph-cluster release └─ CephCluster、池、文件系统、对象存储等配置 └─ Rook Operator 调谐 Ceph 工作负载升级前就已经有 Driver 和 OperatorConfig 对象。新增 Helm release 的工作,是把已有的有效设置交给新的管理方式,不能拿一份默认 values 覆盖现网。
准备候选配置时,先保存原覆盖层和这三份 CSI CR,再检查 release 归属、UID、实际 Pod 的网络、ServiceAccount、资源配额与镜像。controller 保留两副本、Recreate 和实际生效的 hostNetwork: false;node plugin 继续使用主机网络。没有把旧配置中一个未实际生效的继承值,顺手变成本次的新行为。
两个驱动名保持不变:
rook-ceph.rbd.csi.ceph.comrook-ceph.cephfs.csi.ceph.com官方 Helm 升级路径要求先达到 Rook 1.19.5,再按 rook-ceph → ceph-csi-drivers → rook-ceph-cluster 的顺序处理。本环境已经是 1.19.10,实际操作在这条顺序之间加入了暂停、节点验收和健康门槛。Helm 升级顺序
原来的数据怎么继续使用
这次沿用原 CephCluster、原 FSID、原 OSD 和磁盘。没有创建第二套 Ceph,也没有将备份导入一套新存储。
| 层次 | 本轮保留的内容 | 核对方式 |
|---|---|---|
| Ceph 集群 | CephCluster UID、FSID、OSD 与存储布局 | 前后身份、渲染规格和健康状态对比 |
| Kubernetes 卷 | 原 PV/PVC UID、claim 绑定、CSI volumeHandle | 对照发布前基线逐项检查 |
| 消费者 | 13 个 VMI 的 UID 与运行状态 | 每阶段及最终验收对比 |
| CSI 入口 | 原 driver 名称及 Ceph 连接配置 | 检查 CR、实际 Pod 和新挂载行为 |
新版 CSI 继续根据原来的卷标识访问 Ceph 中已有的 RBD image 和 CephFS subvolume。维护目录保存的是 Chart、配置、脚本、备份与证据,业务数据并不因为 Chart 换了目录而移动。
“保留原数据”在这里有具体证据:身份和绑定没有变化,业务数据库查询、复制与应用健康检查正常,独立测试卷也验证了重挂后数据仍在。它不等于对全部业务文件做过逐字节校验。
发布前准备了什么
三台节点都同时承载控制面、etcd、业务和 Ceph。基线除了 Kubernetes Ready,还包括 API、etcd 三成员、18 OSD、三个 MON quorum、全部 PG clean,以及 7 套 PostgreSQL、5 套 MariaDB、9 套 Redis 的实际查询与复制状态。
恢复材料重新生成,没有直接沿用十天前的快照:
- 一份新的 etcd 快照,使用 etcdutl 检查元数据,在另一台节点保留第二份并核对 SHA256。
- 43 份业务恢复文件,合计约 20.11 GB,覆盖约定范围内的数据库、两份 VictoriaMetrics 原生快照和 GitLab 仓库。
- 备份格式与原生校验检查,GitLab 的 50 个 bundle 做 clone/fsck,两节点副本逐文件比对摘要。
这次没有做整个升级组合的隔离演练,也没有覆盖全部 PV、虚机磁盘和对象数据。两份材料仍处在同一集群故障域内;etcd 快照不等于业务数据备份,文件校验也不等于完整恢复演练。
三个 Chart 包核对官方索引摘要。服务器直接下载超时后,改由管理机下载、验证,再传到维护目录。六个新镜像在三节点预拉取,并将现有 Harbor 路由得到的 image ID 与上游 linux/amd64 内容核对,避免等到删除旧 Pod 后才发现目标镜像不可用。
新旧 cluster Chart 都渲染出 18 个对象,存储规格保持一致。候选经过 Helm lint、渲染对比和 API server dry-run。这里的 dry-run 只验证了候选能否被 API 接受,后面的故障说明:它并不能代替实际接管后的检查。
最后,在独立 namespace 创建四个 1Gi 临时卷,分别对应 SSD/HDD 的 RBD 和 CephFS。探针持续执行写入、fsync、读回,并保留固定 marker;生产卷没有被拿来做随机写测试。
先控制节点插件,再暂停 Rook
节点插件更新顺序定为 node-b → node-c → node-a。开始前先用旧 Chart 把 RBD、CephFS 两个 DaemonSet 的策略改为 OnDelete,确认原有六个节点插件 Pod 的 UID 都没有变化。
接着记录并保护仍被使用的 20 个旧 CSI ServiceAccount/RBAC 对象,再暂停 Rook 调谐。暂留权限是为了让接管过程有可用的过渡路径;是否能删,要等最后确认没有引用。
暂停通过经审阅的 scaleDownOperator=true 配置完成,目的在于把 CSI 资源交接、节点插件更新与 Ceph daemon 滚动分开。暂停 Rook Operator 不会主动停止已经运行的 Ceph daemon,但会暂时失去对应调谐能力,因此给它设置了 60 分钟上限。
另一台控制节点上还设置了一次性 systemd timer,在 55 分钟时恢复 Operator 副本。正常恢复后停止 timer。实际暂停从 11:21:04 到 11:42:31,共 21 分 27 秒,没有用满上限。
主要发布命令采用下面的形式。MAINT_ROOT 是经过备份、校验和渲染审阅的维护目录;各条命令之间有单独验收,不能把这段当成可连续执行的一键脚本。
# Rook 已进入受控暂停阶段;新 Chart 继续保持暂停helm upgrade rook-ceph "$MAINT_ROOT/charts/rook-ceph" \ -n rook-ceph -f "$MAINT_ROOT/candidate/operator-new-paused.yaml" \ --wait --timeout 8m
# 安装管理已有 CSI 配置的独立 releasehelm install ceph-csi-drivers "$MAINT_ROOT/charts/ceph-csi-drivers" \ -n rook-ceph -f "$MAINT_ROOT/candidate/drivers-migration.yaml" \ --wait --timeout 8m
# CSI 三节点更新和卷重挂验收通过后,才处理 cluster Charthelm upgrade rook-ceph-cluster "$MAINT_ROOT/charts/rook-ceph-cluster" \ -n rook-ceph -f "$MAINT_ROOT/candidate/cluster-new.yaml" \ --wait --timeout 8mcluster Chart 完成后,再用 operator-new-final.yaml 恢复 Rook。没有使用 --atomic 自动回滚或 mutating force,也没有卸载原 release 后重装。
第一个停止点:Helm 已部署,新的 Pod 却没有账号可用
11:22,Rook Chart 和 Drivers Chart 的发布命令先后返回。随后在 node-b 正常删除第一个旧 RBD node plugin,新的 Pod 无法创建,错误指向:
serviceaccount "rbd-nodeplugin-sa" not found两个 CSI controller 也出现同类 FailedCreate。节点更新循环立即停止,没有继续 node-c 和 node-a。
现场对照得到三组不同的事实:
| 检查对象 | 当时看到的结果 |
|---|---|
| Helm 保存的目标 manifest | 已包含完整的新 ServiceAccount 名称 |
| live Driver CR | nodePlugin/controllerPlugin 缺少显式 serviceAccountName,仍保留之前的 spec |
| CSI Operator 生成的工作负载 | 引用了不存在的短名称 ServiceAccount |
一次使用相同候选的 Helm upgrade 将 Drivers release 推到 revision 2,live spec 仍未修复。这次重试没有解决问题,后面也没有继续靠重复 upgrade 碰运气。
能确认的是 release 清单与 live CR spec 不一致。这些证据不足以把根因直接定成 CSI 镜像缺陷,或者断言所有 Helm 接管都会有同样的问题。
恢复分成两步。
先临时把 CSI Operator 的 CSI_SERVICE_ACCOUNT_PREFIX 恢复为原来的 ceph-csi-,复用前面保留下来的权限。controller 恢复 2/2、node plugin 恢复 3/3,四个测试卷读写通过后,再处理配置差异。
然后,对两份 Driver 和一份 OperatorConfig 先做 server dry-run,再使用带 UID 与 resourceVersion 前置条件的 JSON Patch,将 /spec 原地对齐到已审阅的 Drivers Chart 渲染结果。没有删除重建这些 CR,也没有借修复覆盖凭据。
确认 controller 实际使用新账号后,恢复空前缀并重启 CSI Operator,复核显式账号字段继续存在。node-b 上此前临时恢复的 RBD Pod 仍使用旧账号,因此记录它的 UID 后又受控替换一次,直到最终新账号也在实际 Pod 上生效。
这一步给后续验收增加了一个明确条件:不只核对镜像,还要核对新 Pod 真正使用的 ServiceAccount。
三节点重挂完成后,继续等 Ceph 收敛
三个节点分别在 11:34、11:37、11:41 完成 CSI 更新和四类测试卷重挂。每到一个节点,都检查两种节点插件的镜像、账号、Ready 状态,以及四个测试卷的持久 marker 和持续读写。
RBD 的 RWO 卷移动时,出现过短暂 Multi-Attach 等待。原节点正常 detach 后等待解除,没有强制删除 VolumeAttachment 或绕开单节点挂载约束。
11:42:31 恢复 Rook 调谐之后,Ceph 相关工作负载开始原生滚动。Ceph 二进制版本仍是 19.2.6,但 Rook 管理的 Pod 模板和辅助组件需要更新,不能把“Ceph 版本没变”理解成服务端完全没有滚动。
此前的 OSD 保护配置保持不变:
cephClusterSpec: storage: osdMaxUpdatesInParallel: 1 upgradeOSDRequiresHealthyPGs: true skipUpgradeChecks: false continueUpgradeAfterChecksEvenIfNotHealthy: false12:11 的采样中,18 个 OSD 已经 up/in,三个 MON 在 quorum,两套 CephFS 和 RGW 状态正常。但仍有 8 个 active+remapped+backfilling PG,约 18.1 万个对象 misplaced;纳入检查的 Ceph 相关 Deployment 中,33/34 已更新就绪,最后一个 OSD 仍在等前面的恢复完成。
当时显示的 HEALTH_OK 不能替代全部 PG clean。检查同时要求:
CephCluster Ready,且 observedGeneration 跟上 generation34/34 个纳入检查的 Deployment 已更新、就绪,rook-version 为 v1.20.818 OSD up/in,三个 MON 在 quorum所有 PG 为 active+clean,可附带 scrubbing / deep原业务卷、VMI、API 与 etcd 检查通过没有把带 stale、remapped 或 backfill 的组合放进 clean 白名单,也没有为了缩短等待降低门槛或调整恢复参数。四类测试卷在等待期间继续读写。
到 13:22:08,这些条件全部满足。34 是本轮纳入核对的 Ceph 相关 Deployment 数量,检查的是 Rook 模板更新与就绪情况;它不是 Ceph 服务端版本号,也不是磁盘数量。
恢复正常策略,再验证扩容与删除
收敛后将 Drivers release 升到 revision 3,两个 CSI node plugin 恢复:
updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 0这次只改变更新策略,六个节点插件 Pod 的 UID 保持,未产生额外重建。
随后把四个临时 PVC 都从 1Gi 扩到 2Gi。验收不止看 PVC 的容量字段,还等待 resize 条件结束,在容器内检查挂载容量,并复核 marker 与读写心跳。HDD RBD 等待了一段正常的文件系统扩容过程,最终四类卷全部通过。
清理前保存探针日志,核对 namespace 标签、四个 PVC/PV 的 UID、绑定和 volumeHandle 与发布前记录一致。确认 namespace 里只有本次资源后再正常删除,并等待四个测试 PV 消失,恢复为原来的 95 组业务卷。
20 项过渡权限也先检查实际 Pod、Deployment、DaemonSet、StatefulSet 和角色绑定的引用,再逐项移除。没有按一个宽泛标签批量删权限,也没有清理业务数据或强制移除 finalizer。
第二个收尾问题:新 Chart 生成了一个空监控任务
监控验收发现 ScrapePoolHasNoTargets 指向 CSI 的采集任务。第一眼容易以为升级把原有 CSI 指标弄丢了,继续查历史后才确定不是这个情况:
- 原 Driver CR 没有启用 liveness。
- 升级前两个历史时点都没有 CSI 的
up时序。 - 旧 values 虽然设置了
csi.serviceMonitor.enabled=true,旧模板还要求 liveness 或 grpc metrics 已启用,才生成 ServiceMonitor。 - 新模板移除了后一个条件,于是生成了一个找不到采集 Service 的监控任务。
这个条件变化可以直接对照 1.19.10 模板和 1.20.8 模板。
本轮选择与原配置对齐,将最终覆盖层中的 csi.serviceMonitor.enabled 设为 false。渲染对比确认只有空 ServiceMonitor 被移除,其他对象完全相同,再通过 operator release revision 13 发布。VictoriaMetrics 转换器留下的对应 VMServiceScrape,则在核对来源、UID 和 spec 后单独清理。
13:35:48,对应空采集指标和告警消失,Rook namespace 的 Pod UID 保持。Ceph mgr/exporter 采集继续正常。
这是对未启用功能的采集配置做对齐,不能写成已经补齐 CSI liveness 监控。本轮的 CSI 功能结论来自实际挂载、读写和扩容测试。
另一个原有问题是 CephPoolGrowthWarning。新规则按池身份聚合预测值,消除了此前的 duplicate-series 求值错误,for: 1h 也已加载生效。Rook 聚合修复
但指标取值是 0~1 比例,规则仍与 95 比较;上游另有使用 0.95 的阈值修复。本轮明确决定不做这项本地修正,所以只记录聚合求值恢复,保留阈值单位不匹配的风险,不能因为规则返回成功就把整个告警问题标成已修复。Ceph 阈值修复
最终交付:运行版本、配置文件和业务都要对上
升级期间使用维护目录里的已审阅 Chart 与候选 values 发布,原工作目录最初仍是旧版本。基础检查通过后,再将最终官方 Chart 文件与覆盖层同步回原目录;旧资产单独留档,原有非 Chart 文件保留。
下面省略服务器私有父目录,只列最终相对位置:
| Release | Chart | 最终 revision | 工作目录与覆盖层 |
|---|---|---|---|
| rook-ceph | v1.20.8 | 13 | rook-ceph/rook-ceph.yaml |
| rook-ceph-cluster | v1.20.8 | 44 | rook-ceph-cluster/rook-ceph-cluster.yaml |
| ceph-csi-drivers | 1.0.4 | 3 | ceph-csi-drivers/rook-ceph-drivers.yaml |
这些 revision 是本环境的历史,不是读者应该追求的目标数字。同步后做了 Chart 文件比对、覆盖层摘要记录和 Helm lint,避免线上已经升级,下一次却从旧工作副本重新发布。
最终检查覆盖如下:
| 范围 | 当日已验证的结果 |
|---|---|
| Kubernetes / etcd | 三节点、API、etcd 三成员健康 |
| Ceph / CSI | 18 OSD up/in、3 MON quorum、745 clean PG;目标工作负载版本、就绪和策略通过 |
| 原业务资源 | 95 组业务卷 UID/绑定保持,13 个 VMI 身份与就绪状态保持 |
| 临时存储测试 | 四类卷读写、三节点重挂、数据保留、1Gi→2Gi 在线扩容及删除通过 |
| 数据库 | 7 PostgreSQL、5 MariaDB、9 Redis 的查询、角色、主备复制通过 |
| 应用与对象存储 | GitLab/Harbor 健康;本次自有 S3 对象写入、读回、删除和缺失复核通过 |
| 网络 | 35 条 Ingress 记录、DNS、原可达的 10 个 VM SSH TCP 端口通过相应检查 |
| 监控 | 85 个已发现 targets up,无规则求值错误;已知例外单列 |
| 恢复材料 | 最终 etcd 快照完成元数据与双份 SHA256 核验,旧快照保留 |
入口结果按端点语义判断:API 根路径的 404、KAS 的 426 与页面正常响应分别记录,并没有把它们当成完整登录或业务交易测试。SSH TCP 可达也只证明端口连通,不代表虚机内所有服务已逐项验收。
13:36:19,升级与基础验收完成。
最后没有做满 24 小时观察
基础验收后安排了每小时只读检查,原计划至少观察到第二天同一时间。实际留下五轮观察汇总,最后一轮收敛检查采于 20:29,全局、数据库、入口和配置检查采于 21:30,没有新增 Rook/CSI 故障、配置漂移、Rook Pod 替换或重启增加。
这里有两点必须按实际过程写。
第一,调度和 SSH 会话存在间隔。最后一次触发标识写着较早的时间,不能据此把采集结果也算到那个时点;连接关闭后,先确认服务器已经保存完整结果,再核对内容,没有把 SSH 中断直接解释成集群故障。已有样本也不足以证明整个间隔里没有短暂异常。
第二,当天下午另一个窗口已获批准继续升级 CNPG,原来的阶段等待被缩短。此后的业务观察与数据库维护重叠,不能称为完全隔离于其他变更的 Rook 稳态观察。
到 22:06,我决定不再继续观察,删除临时任务并关闭本轮维护。记录保留为“基础验收通过,观察提前结束”,没有补写一份并未发生的 24 小时稳定性通过结论。
这次最需要记住的,是几个不同的完成时点:Helm 命令返回、CSI CR 真正生效、新 Pod 能挂载原卷、Ceph PG 恢复 clean、业务验收完成,以及日常负载观察结束。前一个时点的成功,不能替后一个签字。
后续仍需单独处理的事项包括:CephX 客户端 AUTH 风险、持续备份/PITR 缺口、既有应用例外、CSI liveness 指标,以及保留的容量预测阈值问题。Rook 1.20.8 的这轮交付已经完成,它们没有因此自动消失。