
千万不要升级 rook-ceph helm chart 到 v1.20.0
血的教训! 差点让我的 Homelab 宕机, 数据丢失.
当时我是这样的情况:
从 rook-ceph v1.19.6 升级到 v1.20.0 后,Ceph mon 数据被升级为 Tentacle ondisk format (v20),无法降级回 v19.x。同时 v1.20.0 的 CSI operator 存在 ServiceAccount 命名不一致的 bug。
升级到 v1.20.0 后,以下 Deployment 和 DaemonSet 无法创建 Pod:
组件 | 报错 |
|---|---|
|
|
|
|
|
|
|
|
Rook v1.20.0 的 CSI operator(ceph-csi-controller-manager)在创建 CSI Deployment/DaemonSet 时,引用的 ServiceAccount 名称使用旧命名风格(无 ceph-csi- 前缀):
cephfs-ctrlplugin-sarbd-ctrlplugin-sacephfs-nodeplugin-sarbd-nodeplugin-sa但 Helm chart 创建的 ServiceAccount 使用新命名风格(带 ceph-csi- 前缀):
ceph-csi-cephfs-ctrlplugin-saceph-csi-rbd-ctrlplugin-saceph-csi-cephfs-nodeplugin-saceph-csi-rbd-nodeplugin-sa名称不匹配导致 Pod 无法通过 ServiceAccount 校验。
通过拷贝创建的旧风格 SA 缺少三层 RBAC 权限,每一层都会导致不同的问题:
层级 | 缺失的绑定 | 影响组件 | 症状 |
|---|---|---|---|
|
| ctrlplugin, nodeplugin | 无法 list csinodes/volumeattachments/persistentvolumes |
|
| ctrlplugin | CSI attacher/resizer/snapshotter 无法 acquire leader lease,volume attach/detach 超时 |
|
| nodeplugin | 无法 get nodes 信息 |
基于已有的新风格 SA 拷贝创建旧风格 SA:
# 创建 ctrlplugin SA
kubectl get sa -n rook-ceph ceph-csi-cephfs-ctrlplugin-sa -o yaml \
| sed 's/name: ceph-csi-cephfs-ctrlplugin-sa/name: cephfs-ctrlplugin-sa/' \
| kubectl apply -f -
kubectl get sa -n rook-ceph ceph-csi-rbd-ctrlplugin-sa -o yaml \
| sed 's/name: ceph-csi-rbd-ctrlplugin-sa/name: rbd-ctrlplugin-sa/' \
| kubectl apply -f -
# 创建 nodeplugin SA
kubectl get sa -n rook-ceph ceph-csi-cephfs-nodeplugin-sa -o yaml \
| sed 's/name: ceph-csi-cephfs-nodeplugin-sa/name: cephfs-nodeplugin-sa/' \
| kubectl apply -f -
kubectl get sa -n rook-ceph ceph-csi-rbd-nodeplugin-sa -o yaml \
| sed 's/name: ceph-csi-rbd-nodeplugin-sa/name: rbd-nodeplugin-sa/' \
| kubectl apply -f -旧风格 SA 缺少三层 RBAC 绑定,必须全部补齐:
# cephfs nodeplugin
kubectl patch clusterrolebinding ceph-csi-cephfs-nodeplugin-crb --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "cephfs-nodeplugin-sa", "namespace": "rook-ceph"}}]'
kubectl patch clusterrolebinding cephfs-csi-nodeplugin-role --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "cephfs-nodeplugin-sa", "namespace": "rook-ceph"}}]'
# rbd nodeplugin
kubectl patch clusterrolebinding ceph-csi-rbd-nodeplugin-crb --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "rbd-nodeplugin-sa", "namespace": "rook-ceph"}}]'
kubectl patch clusterrolebinding rbd-csi-nodeplugin --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "rbd-nodeplugin-sa", "namespace": "rook-ceph"}}]'ctrlplugin 需要 list/watch csinodes、volumeattachments、persistentvolumes:
# cephfs ctrlplugin
kubectl patch clusterrolebinding ceph-csi-cephfs-ctrlplugin-crb --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "cephfs-ctrlplugin-sa", "namespace": "rook-ceph"}}]'
# rbd ctrlplugin
kubectl patch clusterrolebinding ceph-csi-rbd-ctrlplugin-crb --type=json \
-p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "rbd-ctrlplugin-sa", "namespace": "rook-ceph"}}]'ctrlplugin 中的 csi-attacher、csi-resizer、csi-snapshotter 需要通过 leases 进行 leader election。如果缺少这个权限,attacher 永远无法成为 leader,导致所有 VolumeAttach/Detach 操作超时:
kubectl patch rolebinding ceph-csi-leader-election-rolebinding -n rook-ceph --type=json \
-p='[
{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "rbd-ctrlplugin-sa", "namespace": "rook-ceph"}},
{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": "cephfs-ctrlplugin-sa", "namespace": "rook-ceph"}}
]'诊断命令: 如果 attacher 日志中出现以下错误,说明缺少 leases 权限:
E... leaderelection.go:461] "Error retrieving lease lock" err="leases.coordination.k8s.io ... is forbidden: User ... cannot get resource \"leases\"..."修复后(并重启 Pod)应看到:
Normal LeaderElection ... became leader# 重启 ctrlplugin Deployment
kubectl rollout restart deploy -n rook-ceph \
rook-ceph.cephfs.csi.ceph.com-ctrlplugin \
rook-ceph.rbd.csi.ceph.com-ctrlplugin
# 删除 nodeplugin Pod(DaemonSet 会自动重建)
kubectl delete pods -n rook-ceph -l app=rook-ceph.cephfs.csi.ceph.com-nodeplugin
kubectl delete pods -n rook-ceph -l app=rook-ceph.rbd.csi.ceph.com-nodepluginRBAC 修复后,CSI attacher 恢复正常,但升级期间会产生大量残留资源需要手动清理。
旧 Pod 持有的 lease 可能阻止新 attacher 成为 leader:
kubectl delete lease -n rook-ceph \
external-attacher-leader-rook-ceph-cephfs-csi-ceph-com \
external-attacher-leader-rook-ceph-rbd-csi-ceph-com 2>/dev/null升级期间 CSI attacher 不可用,会产生大量带有 deletionTimestamp 但 attached: true 的 VolumeAttachment。这些需要移除 finalizer 才能删除:
# 列出所有卡在删除中的 VA
kubectl get volumeattachment -o jsonpath='{range .items[?(@.metadata.deletionTimestamp)]}{.metadata.name}{" — attached: "}{.status.attached}{"\n"}{end}'
# 强制清除所有卡死 VA 的 finalizer
kubectl get volumeattachment -o jsonpath='{range .items[?(@.metadata.deletionTimestamp)]}{.metadata.name}{"\n"}{end}' | while read va; do
[ -z "$va" ] && continue
kubectl patch volumeattachment "$va" --type=merge -p '{"metadata":{"finalizers":null}}'
echo "cleared: $va"
done诊断命令: 如果 PVC 挂载日志出现 Multi-Attach error 或 timed out waiting for external-attacher,大概率是残留 VA 未清理。
RBAC 和 VA 清理后,之前因 CSI 不可用而卡住的业务 Pod 需要删除重建:
# 删除卡在 ContainerCreating/PodInitializing 的业务 Pod
# 示例(gitea):
kubectl delete pod -n gitea -l app.kubernetes.io/name=gitea
# 批量清理所有非 Running 的 Pod(排除 volsync 和已知应用问题的 Pod):
kubectl get pods -A --no-headers | grep -v -E 'Running|Completed|volsync' | while read ns pod rest; do
kubectl delete pod "$pod" -n "$ns" --force --grace-period=0 2>/dev/null
done# 1. 所有 rook-ceph Pod 应 Running
kubectl get pods -n rook-ceph | grep -v -E 'Running|Completed'
# 2. CephCluster 状态应为 Ready
kubectl get cephcluster -n rook-ceph
# 3. Ceph 健康状态(HEALTH_WARN 中 Telemetry 告警可忽略)
kubectl exec -n rook-ceph deploy/rook-ceph-tools -- ceph status修复后,attacher/resizer/snapshotter 应成功成为 leader:
# 查看 leader election 事件(应有 5 个 became leader)
kubectl get events -n rook-ceph --sort-by='.lastTimestamp' | grep LeaderElection | tail -5预期输出示例:
Normal LeaderElection ... external-attacher-leader-rook-ceph-rbd-csi-ceph-com became leader
Normal LeaderElection ... external-attacher-leader-rook-ceph-cephfs-csi-ceph-com became leader
Normal LeaderElection ... external-resizer-rook-ceph-rbd-csi-ceph-com became leader
Normal LeaderElection ... external-snapshotter-leader-rook-ceph-rbd-csi-ceph-com became leader
Normal LeaderElection ... external-snapshotter-leader-rook-ceph-cephfs-csi-ceph-com became leader# 确认使用 rook PV 的业务 Pod 均正常(排除 volsync 和已知非 rook 问题的 Pod)
kubectl get pods -A --no-headers | grep -v -E 'Running|Completed|volsync'# 确认无卡死的 VA
kubectl get volumeattachment -o jsonpath='{range .items[?(@.metadata.deletionTimestamp)]}{.metadata.name}{"\n"}{end}' | wc -l
# 输出应为 0以下表格记录了从「旧 SA 名称」→「需要绑定的 ClusterRoleBinding/RoleBinding」的完整映射:
旧 SA 名称 | 绑定的 CRB/RoleBinding | 授予的权限 | 类型 |
|---|---|---|---|
|
| nodes get/list | ClusterRoleBinding |
|
| nodes get/list | ClusterRoleBinding |
|
| nodes get/list | ClusterRoleBinding |
|
| nodes get/list | ClusterRoleBinding |
|
| csinodes, volumeattachments, persistentvolumes | ClusterRoleBinding |
|
| csinodes, volumeattachments, persistentvolumes | ClusterRoleBinding |
|
| leases (leader election) | RoleBinding |
|
| leases (leader election) | RoleBinding |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。