替换或移除由 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

  1. 列出 OSD Pod,并记下 OSD ID 和节点。

    kubectl -n rook-ceph get pod -l app=rook-ceph-osd -o wide
  2. 查找支持该 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"}'
  3. 确认集群运行状况和剩余容量。

    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 并等待数据迁移

  1. 如果 OSD 仍在运行,请将其缩容。

    kubectl -n rook-ceph scale deploy rook-ceph-osd-<id> --replicas=0
  2. 从 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)处保留标签。

  1. 查找 PV 节点和本地路径。

    kubectl get pv <pv-name> -o jsonpath='node={.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values} path={.spec.local.path}{"\n"}'
  2. 可选:将 Rook operator 缩放到零,以免在清除期间绑定新的 PVC。

    kubectl -n rook-ceph scale deploy rook-ceph-operator --replicas=0
  3. 在该节点上以 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 必须为 {}。

  4. 如果你缩减了 Rook operator,则将其恢复。

    kubectl -n rook-ceph scale deploy rook-ceph-operator --replicas=1

然后,如果你是在替换 OSD,请返回等待 Rook 创建替换项;如果你是在扩容,请提高 count。

参考