MySQL, Oracle, Linux, 软件架构及大数据技术知识分享平台

网站首页 > 精选文章 / 正文

步步为营把k8s pvc存储从一个ceph集群迁移到另一个

2025-05-03 14:27 huorong 精选文章 12 ℃ 0 评论

由于 centos7 停止维护,公司需要把原先运行在 centos7 主机上的 ceph 集群迁移到 ubuntu。公司 k8s 集群 pvc 使用的存储也是 ceph,因此 ceph 迁移必然会影响 k8s 服务。 本文介绍如何把 k8s pvc 存储从 centos ceph 迁移到 ubuntu ceph。

迁移看似很难,步步为营,必将成功。下面迁移过程分为以下阶段:迁移前检查、迁移前备份、迁移、迁移后处理。迁移前检查阶段会确认当前 k8s 状态是否正常;迁移前备份阶段会把当前 k8s 资源备份,并生成迁移资源文件;迁移阶段会停止使用 pvc 的服务,使用迁移前备份阶段生成的迁移资源文件,恢复使用 pvc 的服务;迁移后处理会恢复 pv 回收策略、cronjob 状态。

获取新旧集群 ceph 配置

key

含义

NEW_CEPH_CLUSTER_ID

新 ceph 集群的cluster id

NEW_CEPH_CLIENT_ADMIN_KEY

新 ceph 集群的 client admin key

NEW_CEPH_CONFIG_MONITOR

新 ceph 集群的 monitor地址

CURRENT_CEPH_CLUSTER_ID

旧 ceph 集群的 cluster id

迁移前检查

备份 k8s 资源前若检查出问题,先解决问题再备份。

# 检查是否有节点不正常
kubectl get nodes -l node-role.kubernetes.io/edge!=true |grep -i NotReady
# 检查 k8s 控制面是否正常
kubectl -n kube-system get pod |grep -Pv '\s+([1-9]+)\/\1\s+' |grep -Ev "Completed|NAME|Evicted"
# 检查 k8s ceph rbd 使用的 cluster id 是否与旧 ceph 集群 cluster id 一致
kubectl get sc ceph-rbd-hdd-premium -ojsonpath='{.parameters.clusterID}'

确认 k8s 使用 ceph 正常,在 default namespace 进行下面验证:

  • 验证 k8s 使用 ceph rbd csi 正常
  • 验证 k8s 使用 ceph rbd intree 正常
  • 验证 k8s 使用 cephfs csi 正常
  • 验证 k8s 使用 cephfs intree 正常

迁移前备份

备份所有 pvc 相关 k8s 资源,以防迁移失败用来恢复。

  • 备份 cronjob

记录 pvc 和 cronjob 映射关系

# 获取 ${namespace} 下的 cronjob 名称和 pvc 名称对应关系
kubectl get cronjob -n ${namespace} -o json | jq -r '.items[] | "\(.metadata.name) \(.spec.jobTemplate.spec.template.spec | select(has("volumes")).volumes[] | select(has("persistentVolumeClaim")).persistentVolumeClaim.claimName)"' | grep -v null
# 获取 cronjob suspend 状态
kubectl get cronjob ${cronjob_name} -n ${namespace} -o=jsonpath='{.spec.suspend}'
# 将获取到的 cronjob,pvc 对应信息写入文件 backup/record/pvc_cronjob.txt
echo "${namespace} ${pvc_name} Cronjob/${cronjob_name} ${suspend}" >> backup/record/pvc_cronjob.txt

挂起 cronjob 防止在迁移过程中有 cronjob 往旧 ceph 集群写数据造成迁移后数据不一致,升级结束后恢复。

# 从文件backup/record/pvc_cronjob.txt 获取涉及到的 cronjob,将其挂起
kubectl -n ${namespace} patch ${cronjob_name} -p '{"spec":{"suspend":true}}'
  • 挂起所有使用 pvc 的 job/cronjob pod 和所有无主pod

也可以等待这些 pod 执行完毕,是挂起还是等待执行完毕需要根据 pod 对应服务来决定。

# 获取 ${namespace} 下所有使用 pvc 的 pod
kubectl get pod -n ${namespace} -o json | jq -r '.items[] | "\(.metadata.name) \(.spec|select(has("volumes")).volumes[] | select(has("persistentVolumeClaim")).persistentVolumeClaim.claimName)"' | grep -v null
# 获取  ${namespace} 下 ${pod_name} 的 ownerReferences 信息
# 根据 ownerReferences 信息找出使用 pvc 的 job/cronjob pod 和 无主 pod
# 若 ownerReferences kind 是Job,此 pod 是 Job 产生的 pod
# 若 ownerReferences kind 是CronJob,此 pod 是 CronJob 产生的 pod
# 若 ownerReferences 为空,此 pod 是 无主 pod
kubectl get pod ${pod_name} -n ${namespace} -o json | jq -r '.metadata.ownerReferences[0]'
  • 备份集群状态
# 备份 pv 状态到文件 backup/status/pv_status.txt
kubectl get pv > backup/status/pv_status.txt
# 备份 pvc 状态到文件 backup/status/pvc_status.txt
kubectl get pvc -A > backup/status/pvc_status.txt
# 备份 pod 状态到文件 backup/status/pod_status.txt
kubectl get pod -owide -A  > backup/status/pod_status.txt
# 备份 deploy 状态到文件 backup/status/deploy_status.txt
kubectl get deploy -A  > backup/status/deploy_status.txt
# 备份 statefulset 状态到文件 backup/status/sts_status.txt
kubectl get sts -A  > backup/status/sts_status.txt
  • 记录 pv 和回收策略映射关系
# 记录 pv 和其对应的回收策略到文件 backup/record/pv_policy.txt
kubectl get pv -o=jsonpath='{range .items[*]}{.metadata.name} {.spec.persistentVolumeReclaimPolicy}{"\n"}{end}' > backup/record/pv_policy.txt
  • 记录 pvc 和 pv 映射关系
# 记录 pvc 和 其对应的 pv 到文件 backup/record/tmp_pvc_pv_mapping.txt
kubectl get pvc --all-namespaces -o json | jq -r '.items[] | "\(.metadata.namespace) \(.metadata.name) \(.spec.volumeName)"' > backup/record/tmp_pvc_pv_mapping.txt
  • 记录 pvc 和 workload 映射关系
# 获取 pod 和 pvc 对应关系
kubectl get pod -n ${namespace} -o json | jq -r '.items[] | "\(.metadata.name) \(.spec|select(has("volumes")).volumes[] | select(has("persistentVolumeClaim")).persistentVolumeClaim.claimName)"' | grep -v null
# 获取 pod ownerReferences 信息
kubectl get pod ${pod_name} -n ${namespace} -o json | jq -r '.metadata.ownerReferences[0]'
# 若 ownerReferences 为空,要特殊处理此 pod, 在迁移前要结束此 pod 运行
# 若 ownerReferences kind 为 ReplicaSet,此 pod 对应的 workload 为 ReplicaSet 或 Deployment
# 获取 pod 对应的 ReplicaSet/Deployment 副本数记录到文件 backup/record/pvc_workload_replicas.txt
echo "${namespace} ${pvc_name} ReplicaSet/${controller_name} ${replica}" >> backup/record/pvc_workload_replicas.txt
echo "${namespace} ${pvc_name} Deployment/${deploy_name} ${replica}" >> backup/record/pvc_workload_replicas.txt
# 若 ownerReferences kind 为 StatefulSet,获取 StatefulSet 副本数记录到文件 backup/record/pvc_workload_replicas.txt
echo "${namespace} ${pvc_name} StatefulSet/${controller_name} ${replica}" >> backup/record/pvc_workload_replicas.txt
  • 修改 pv 回收策略为Retain

修改 pv 回收策略为 Retain,防止把 workload 副本数置为0时,pv 对应的 ceph 资源被删除。迁移完毕后恢复 pv 回收策略。

kubectl patch pv "${volume}" -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
  • 备份所有的 pvc和pv 资源
# 备份所有的 pv 资源
kubectl get pv ${volume} -ojson | jq 'del(
            .metadata.annotations,
            .metadata.creationTimestamp,
            .metadata.generation,
            .metadata.resourceVersion,
            .metadata.selfLink,
            .metadata.uid,
            .spec.claimRef.resourceVersion,
            .spec.claimRef.uid,
            .status
        )' > backup/pv/${volume}.json
# 备份所有的 pvc 资源
kubectl -n ${namespace} get pvc ${pvc_name} -ojson | jq 'del(
                .metadata.annotations."kubectl.kubernetes.io/last-applied-configuration",
                .metadata.annotations."pv.kubernetes.io/bind-completed",
                .metadata.annotations."pv.kubernetes.io/bound-by-controller",
                .metadata.annotations."volume.beta.kubernetes.io/storage-provisioner",
                .metadata.annotations."volume.kubernetes.io/storage-provisioner",
                .metadata.creationTimestamp,
                .metadata.generation,
                .metadata.resourceVersion,
                .metadata.selfLink,
                .metadata.uid,
                .status
            )' > backup/pvc/${namespace}_${pvc_name}.json
  • 备份所有的storageclass资源
kubectl get sc ${storageclass} -ojson | jq 'del(
            .metadata.annotations."kubectl.kubernetes.io/last-applied-configuration",
            .metadata.creationTimestamp,
            .metadata.generation,
            .metadata.resourceVersion,
            .metadata.selfLink,
            .metadata.uid,
            .status
        )' > backup/sc/${storageclass}.json
  • 备份所有的 ceph csi 配置文件

保存 kube-system namespace 下面资源:
保存 configmap ceph-csi-config 到文件
backup/ceph/ceph-csi-config.json

保存 secret csi-cephfs-secret 到文件
backup/ceph/csi-cephfs-secret.json

保存 secret csi-rbd-secret 到文件
backup/ceph/csi-rbd-secret.json

保存 secret ceph-rbd-admin 到文件
backup/ceph/ceph-rbd-admin.json

  • 备份用于升级测试 k8s 资源文件

单独备份迁移前检查阶段测试 k8s 是否正常的 pvc 和 pv 到目录 backup/migtest/pvc、backup/migtest/pv

  • 生成新的 ceph csi 资源文件

复制文件
backup/ceph/ceph-csi-config.json 到
new/ceph/ceph-csi-config.json,修改文件中的 clusterID 为 NEW_CEPH_CLUSTER_ID 对应值,修改 monitors 为 NEW_CEPH_CONFIG_MONITOR 对应值

复制文件
backup/ceph/csi-cephfs-secret.json 到
new/ceph/csi-cephfs-secret.json,修改文件中的 adminkey、userKey 为 NEW_CEPH_CLIENT_ADMIN_KEY 对应值的base64

复制文件
backup/ceph/csi-rbd-secret.json 到
new/ceph/csi-rbd-secret.json,修改文件中 userKey 为 NEW_CEPH_CLIENT_ADMIN_KEY 对应值的base64

复制文件
backup/ceph/ceph-rbd-admin.json 到
new/ceph/ceph-rbd-admin.json,修改文件中 key 为 NEW_CEPH_CLIENT_ADMIN_KEY 对应值的base64

  • 生成新的 pv资源文件

复制文件夹 backup/pv 到 new/pv,更改 pv 文件中 clusterID 为 NEW_CEPH_CLUSTER_ID 对应值;更改pv 文件中 spec.rbd.monitors then .spec.rbd.monitors 和 spec.cephfs.monitors then .spec.cephfs.monitors 为 NEW_CEPH_CONFIG_MONITOR 对应值

  • 生成新的 storageclass 资源文件

复制文件夹 backup/sc 到 new/sc,更改 sc 文件中 clusterID 为 NEW_CEPH_CLUSTER_ID 对应值;更改 monitors 为 NEW_CEPH_CONFIG_MONITOR 对应值

  • 生成用于测试的资源文件

分别复制文件夹 backup/migtest/pvc、backup/migtest/pv 到 new/migtest/pvc、new/migtest/pv。更改 new/migtest/pv 目录文件 clusterID 为 NEW_CEPH_CLUSTER_ID 对应值;spec.rbd.monitors then .spec.rbd.monitors 和 spec.cephfs.monitors then .spec.cephfs.monitors 为 NEW_CEPH_CONFIG_MONITOR 对应值。

迁移

  • 确保所有 pv 回收策略为 Retain

检查所有 pv 回收策略是否为 Retain,防止把 workload 副本数置为0时,pv 对应的 ceph 资源被删除。迁移完毕后恢复 pv 回收策略

# 获取所有 pv 回收策略,检查是否都为 Retain
kubectl get pv -o=jsonpath='{range .items[*]}{.metadata.name} {.spec.persistentVolumeReclaimPolicy}{"\n"}{end}'
  • dryrun 生成出来的 k8s 资源

用下面命令 dryrun 生成出来的 ceph csi 资源文件,pv资源文件,storageclass 资源文件,检查资源文件是否有语法问题。

kubectl apply -f ${k8s_dir} --dry-run=client
  • 停止使用 pvc 的 workload


backup/record/pvc_workload_replicas.txt 记录的 workload 副本数都置为0,这样没有服务使用 ceph,就不会产生新的 ceph 数据。

kubectl -n ${namespace} scale ${workload} --replicas=0

然后检查各个 namespace 是否还有使用 pvc 的 pod, 若还有,单独处理这些 pod

# 检查是否还有使用 pvc 的 pod
kubectl get pod -n ${namespace} -o json | jq -r '.items[] | "\(.metadata.name) \(.spec|select(has("volumes")).volumes[] | select(has("persistentVolumeClaim")).persistentVolumeClaim.claimName)"' | grep -v null
  • 迁移 ceph 数据

把 ceph 数据从旧集群迁移到新集群,忽略具体迁移过程。

  • 更新 ceph csi 控制面
 # 更新 ceph csi 资源
kubectl -n kube-system apply -f new/ceph/ --wait=true
# 重启 ceph csi pod
kubectl -n kube-system delete pod -l app=csi-rbdplugin-provisioner
kubectl -n kube-system delete pod -l app=csi-rbdplugin
kubectl -n kube-system delete pod -l app=csi-cephfsplugin-provisioner
kubectl -n kube-system delete pod -l app=csi-cephfsplugin
  • 更新 storageclass 配置
# 删除原来的 storageclass(使用了旧 ceph 集群)
kubectl delete -f new/sc/${sc_file} --wait=true --ignore-not-found=true
# 使用最新的 storageclass(即使用新 ceph 集群)
kubectl apply -f new/sc/${sc_file} --wait=true
  • 检查 ceph csi 可用性

k8s 使用新的 ceph 集群时,验证 k8s 能正常使用 ceph rbd csi,ceph rbd intree,cephfs csi ,cephfs intree

  • 检查迁移过来的 pv/pvc/deployment
# 删除原来的测试 pv/pvc 资源
kubectl delete -f new/migtest/pv/${pv_file} --wait=true --ignore-not-found=true
kubectl delete -f new/migtest/pvc/${pvc_file} --wait=true --ignore-not-found=true
# 使用最新的测试 pv/pvc 资源
kubectl apply -f new/migtest/pv/${pv_file} --wait=true
kubectl apply -f new/migtest/pvc/${pvc_file} --wait=true
# 把 default namesapce 下的 deployment(确认 k8s 使用 ceph 正常)副本数设置为1
# 检查迁移过来的 pv/pvc/deployment 是否都正常
kubectl -n default scale deployment ${name} --replicas=1
# 检查完毕后,重新把 default namesapce 下的 deployment 副本数置为0,防止影响后续步骤
kubectl -n default scale deployment ${name} --replicas=0
  • 重建 pvc/pv 前检查
# 检查是否有 pod 使用 pvc/pv
kubectl get pod -n ${namespace} -o json | jq -r '.items[] | "\(.metadata.name) \(.spec|select(has("volumes")).volumes[] | select(has("persistentVolumeClaim")).persistentVolumeClaim.claimName)"' | grep -v null
  • 删除涉及到的 pvc/pv
# 删除涉及到的 pvc
kubectl delete -f new/pvc/${pvc_file} --wait=true --ignore-not-found=true
# 删除涉及到的 pv
kubectl delete -f new/pv/${pv_file} --wait=true --ignore-not-found=true
  • 重建涉及到的 pvc/pv
# 重建涉及到的 pv
kubectl apply -f new/pv/${pv_file} --wait=true
# 重建涉及到的 pvc
kubectl apply -f new/pvc/${pvc_file} --wait=true
  • 等待 pvc正确 bound pv

从文件
backup/record/pvc_pv_mapping.txt 获取正在重建的 pvc,检查 pvc 正确 bound pv

 kubectl -n ${namespace} wait --for=jsonpath='{.status.phase}'=Bound pvc/${pvc_name} --timeout=60s
  • 启动应用服务

查看
backup/record/pvc_workload_replicas.txt 文件记录的 workload 和 对应副本数,恢复对应workload

 kubectl -n ${namespace} scale ${workload} --replicas=${replicas}

迁移后处理

  • 恢复 pv 的回收策略

在迁移前把所有 pv 回收策略设置为 Retain,防止把 workload 副本数置为0时,pv 对应的 ceph 资源被删除。现在查看
backup/record/pv_policy.txt 文件记录的 pv 回收策略并恢复。

kubectl patch pv "${pv_name}" -p "{\"spec\":{\"persistentVolumeReclaimPolicy\":\"$pv_policy\"}}"
  • 恢复挂起的 cronjob

迁移前挂起 cronjob 防止在迁移过程中有 cronjob 往旧 ceph 集群写数据造成迁移后数据不一致。查看
backup/record/pvc_cronjob.txt 文件记录的 cronjob 状态,若迁移前 cronjob 挂起现在开启它

kubectl -n ${namespace} patch ${cronjob_name} -p '{"spec":{"suspend":false}}'
  • 更新 ceph-expand

从新 ceph 集群中获取到 ceph.conf 和 ceph.client.admin.keyring 这2个配置文件,

# 生成对应的ceph configmap
kubectl -n ${namespace} create configmap ceph-configmap --from-file=ceph.client.admin.keyring --from-file=ceph.conf --dry-run=client -o yaml > ./ceph-configmap.yaml
 
# 直接更新
kubectl -n ${namespace} apply -f ./ceph-configmap.yaml
 
# 重启ceph-expand pod
kubectl -n ${namespace} delete po -l app=cephfs-expand



整个迁移过程耗时比较长,可以开发为自动化脚本。迁移过程中进行了全方位的验证,保证迁移成功。

Tags:yaml map

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言