替换或移除由 PVC 支持的 OSD 设备
本文档介绍在 Ceph 集群使用由 PVC 支持的 OSD(CephCluster.spec.storage.storageClassDeviceSets)时,如何移除或替换 Object Storage Daemon(OSD)。这些 OSD 使用来自 Local Storage StorageClass 的 Block PersistentVolumeClaims(PVC),例如 localblock。
对于基于主机的 OSD(CephCluster.spec.storage.nodes),请改用替换或移除设备。
减少 storageClassDeviceSets[].count 或移除 storageClassDeviceSets 条目不会删除 OSD。它只会降低 OSD 的期望数量,使 Rook 在清除 OSD 后不会重新创建设备。从 Ceph 中移除数据始终需要显式清除特定的 OSD ID。存在多个 PVC 集时,可以移除其中一个集,也可以移除最后一个 PVC 集。
先决条件
-
除要替换设备时的故障磁盘外,所有集群组件均运行正常。
-
集群是使用由 PVC 支持的 OSD 创建的。确认 CephCluster 包含 spec.storage.storageClassDeviceSets,并且 spec.storage.nodes 为空。
kubectl -n rook-ceph get cephcluster ceph-cluster -o jsonpath='{.spec.storage.storageClassDeviceSets}' ; echo
kubectl -n rook-ceph get cephcluster ceph-cluster -o jsonpath='{.spec.storage.nodes}' ; echo
-
你具有 cluster-admin 访问权限,并且可以进入 rook-ceph-tools 执行命令。
约束和限制
- 在数据重新平衡期间,集群性能可能会暂时降低。除非已确认剩余容量和故障域,否则一次不要清除多个 OSD。
- 如果集群因正在移除的 OSD 以外的原因处于
HEALTH_ERR 状态,请不要继续操作。
- 如果 OSD 是某个设备类中的最后一个设备,则仅使用该设备类的存储池会受到影响。
- 在降低
count、移除集或清除 OSD 时,不要将 Rook operator 缩容至零。Rook 必须保持运行,以便在更改期望容量后不会重新创建 OSD。只有在擦除已释放的磁盘时,才可以将其缩容至零,具体说明请参阅清除遗留的 BlueStore 标签。
- 清除后,如果
count 仍高于剩余 OSD 的数量,或者设备集仍在 spec 中,Rook 会创建新的 PVC/OSD 来填补缺口。这就是替换路径。对于缩容操作,请在清除之前或清除后立即降低 count,或者移除该集。
识别 OSD 和 PVC
-
列出 OSD Pod,并记下 OSD ID 和节点。
kubectl -n rook-ceph get pod -l app=rook-ceph-osd -o wide
-
查找支持该 OSD 的 PVC。
kubectl -n rook-ceph get pvc -l ceph.rook.io/DeviceSet=<deviceSet-name>
kubectl -n rook-ceph get deploy rook-ceph-osd-<id> -o jsonpath='{.metadata.labels.ceph\.rook\.io/pvc}{"\n"}'
-
确认集群运行状况和剩余容量。
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph -s
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd df
剩余 OSD 的 AVAIL 总和必须大于要移除 OSD 的 USE。
移除 OSD(缩容)
当你希望减少 OSD 数量且不希望 Rook 配置替代 OSD 时,请使用此操作步骤。
降低期望数量
修补 CephCluster 中匹配的 storageClassDeviceSets 条目,使 count 等于你要保留的 OSD 数量。例如,将包含 count: 3 的集更改为 2。
kubectl -n rook-ceph patch cephcluster ceph-cluster --type=json \
-p '[{"op":"replace","path":"/spec/storage/storageClassDeviceSets/0/count","value":2}]'
如果有多个设备集,请更改数组索引,以修补拥有该 OSD 的设备集。要停用整个设备集,请删除该列表条目,而不是降低 count:
kubectl -n rook-ceph patch cephcluster ceph-cluster --type=json \
-p '[{"op":"remove","path":"/spec/storage/storageClassDeviceSets/1"}]'
当 count 减少或移除设备集时,Rook 不会删除 OSD。
将 OSD 标记为 out 并等待数据迁移
-
如果 OSD 仍在运行,请将其缩容。
kubectl -n rook-ceph scale deploy rook-ceph-osd-<id> --replicas=0
-
从 tools Pod 中,将 OSD 标记为 down 和 out。
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash
ceph osd down osd.<id>
ceph osd out osd.<id>
ceph -s
等待 PG 变为 active+clean,并且集群变为 HEALTH_OK(或仅存在与此次移除相关的警告)。回填完成前不要清除 OSD,除非 OSD 已经发生故障且你必须继续操作。
清除 OSD
使用上游的 rook-ceph-purge-osd Job。它会在需要时将 OSD 标记为 out,运行 ceph osd purge,并删除 OSD Deployment、OSD prepare Job 和 OSD PVC。ServiceAccount 已随 Rook 安装。
该 Job 仅适用于已经处于 down 状态且存在于 ceph osd dump 中的 OSD。它不会等待回填。请先完成将 OSD 标记为 out 并等待数据迁移。如果 OSD 从未加入 Ceph(not found osd.<id> in OSDDump),请跳过该 Job,手动删除 Deployment、prepare Job 和 PVC。
替换 <OSD-ID>,并使用集群中已运行的 Rook operator 镜像:
OSD_ID=<id>
IMG=$(kubectl -n rook-ceph get deploy rook-ceph-operator -o jsonpath='{.spec.template.spec.containers[0].image}')
kubectl -n rook-ceph delete job rook-ceph-purge-osd --ignore-not-found
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: rook-ceph-purge-osd
namespace: rook-ceph
labels:
app: rook-ceph-purge-osd
spec:
backoffLimit: 0
template:
metadata:
labels:
app: rook-ceph-purge-osd
spec:
serviceAccountName: rook-ceph-purge-osd
restartPolicy: Never
containers:
- name: osd-removal
image: ${IMG}
args:
- "ceph"
- "osd"
- "remove"
- "--preserve-pvc"
- "false"
- "--force-osd-removal"
- "false"
- "--osd-ids"
- "${OSD_ID}"
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: ROOK_MON_ENDPOINTS
valueFrom:
configMapKeyRef:
key: data
name: rook-ceph-mon-endpoints
- name: ROOK_CEPH_USERNAME
valueFrom:
secretKeyRef:
key: ceph-username
name: rook-ceph-mon
- name: ROOK_CONFIG_DIR
value: /var/lib/rook
- name: ROOK_CEPH_CONFIG_OVERRIDE
value: /etc/rook/config/override.conf
- name: ROOK_FSID
valueFrom:
secretKeyRef:
key: fsid
name: rook-ceph-mon
- name: ROOK_LOG_LEVEL
value: DEBUG
volumeMounts:
- mountPath: /etc/ceph
name: ceph-conf-emptydir
- mountPath: /var/lib/rook
name: rook-config
- name: ceph-admin-secret
mountPath: /var/lib/rook-ceph-mon
volumes:
- name: ceph-admin-secret
secret:
secretName: rook-ceph-mon
items:
- key: ceph-secret
path: secret.keyring
- emptyDir: {}
name: ceph-conf-emptydir
- emptyDir: {}
name: rook-config
EOF
kubectl -n rook-ceph wait --for=condition=complete job/rook-ceph-purge-osd --timeout=180s
kubectl -n rook-ceph logs -l app=rook-ceph-purge-osd --tail=50
确认日志包含 completed removal of OSD。然后删除 Job:
kubectl -n rook-ceph delete job rook-ceph-purge-osd
等待 PVC 消失。如果要重复使用该磁盘,请等待其 backing PV 变为 Available。
如果 Job 不可用,请从 tools Pod 中清除 OSD,并自行删除残留对象。首先删除已完成的 OSD prepare Job。该 Job 仍挂载 PVC,因此在 Job 删除前,PVC 会保持 Terminating 状态。
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd purge osd.<id> --yes-i-really-mean-it
kubectl -n rook-ceph delete deploy rook-ceph-osd-<id>
kubectl -n rook-ceph delete job rook-ceph-osd-prepare-<osd-pvc-name>
kubectl -n rook-ceph delete pvc <osd-pvc-name>
验证
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph -s
kubectl -n rook-ceph get pvc -l ceph.rook.io/DeviceSet=<deviceSet-name>
kubectl -n rook-ceph get cephcluster ceph-cluster -o jsonpath='{.spec.storage.storageClassDeviceSets}' ; echo
被移除的 OSD ID 不得出现在 ceph osd tree 中。如果你降低了 count,它必须与该设备集的剩余 OSD 数量匹配。如果你移除了设备集,该名称不得出现在 storageClassDeviceSets 中。否则 Rook 会创建另一个 OSD。
替换失败的 OSD(保持容量)
当磁盘或 PVC 发生故障且你希望保持 OSD 数量不变时,使用此操作步骤。
保持期望数量
不要降低 storageClassDeviceSets[].count,也不要移除设备集。
如果你要安装一块新磁盘,请在同一个 StorageClass(localblock 或设备集使用的类)中创建一个新的 Block PV。该 PV 必须在合适的节点上处于 Available 状态。
如果你要重复使用同一个本地磁盘,请不要创建新的 PV。清除 OSD 后,Local Storage 通常会将现有 PV 恢复为 Available 状态。你必须先清除残留的 BlueStore 标签,然后 Rook 才能再次准备该磁盘。如果跳过清除步骤,Rook 会重复使用旧的 OSD 元数据,替换的 OSD 会在 expand-bluefs 期间保持 CrashLoopBackOff 状态。
清除失败的 OSD
按照将 OSD 标记为 out 并等待数据迁移和清除 OSD中的步骤操作。如果 OSD Pod 已处于 CrashLoopBackOff 或 Error 状态,则可以跳过 ceph osd down。
等待 Rook 创建替换的
由于 count 未发生变化,Rook 会使用未使用的最高索引创建新的 PVC,并启动新的 OSD。新的 OSD ID 可能不同于旧 OSD。
kubectl -n rook-ceph get pvc -l ceph.rook.io/DeviceSet=<deviceSet-name>
kubectl -n rook-ceph get pod -l app=rook-ceph-osd
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd tree
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph -s
等待新的 OSD 处于 up/in 状态,并且 PG 处于 active+clean 状态。
清除残留的 BlueStore 标签
仅当 OSD PVC 已消失且 backing PV 处于 Available 状态时,才使用此操作步骤。不要清除仍绑定到 PVC 的设备。
Rook OSD prepare 不会清除以前使用过的 Block PV。sgdisk --zap-all、清除开头或结尾的 100 MiB,以及 blkdiscard 都不够。BlueStore 会在 1 GiB(0x40000000)和 10 GiB(0x280000000)处保留标签。
-
查找 PV 节点和本地路径。
kubectl get pv <pv-name> -o jsonpath='node={.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values} path={.spec.local.path}{"\n"}'
-
可选:将 Rook operator 缩放到零,以免在清除期间绑定新的 PVC。
kubectl -n rook-ceph scale deploy rook-ceph-operator --replicas=0
-
在该节点上以 root 身份清除 PV 路径解析到的块设备。将 /dev/vdc 替换为实际设备(PV 本地路径上的 readlink -f,或 LocalVolume 的 devicePaths 条目)。
DEV=/dev/vdc
dd if=/dev/zero of=$DEV bs=1M seek=1024 count=16 oflag=direct conv=fsync
dd if=/dev/zero of=$DEV bs=1M seek=10240 count=16 oflag=direct conv=fsync
dd if=/dev/zero of=$DEV bs=1M count=16 oflag=direct conv=fsync
确认标签已清除。ceph-bluestore-tool show-label --dev $DEV 必须报告未找到有效的 bdev 标签,并且 ceph-volume raw list $DEV 必须为 {}。
-
如果你缩减了 Rook operator,则将其恢复。
kubectl -n rook-ceph scale deploy rook-ceph-operator --replicas=1
然后,如果你是在替换 OSD,请返回等待 Rook 创建替换项;如果你是在扩容,请提高 count。
参考