MySQL Redis 存储迁移local-path → Longhorn一、背景1.1 为什么需要迁移集群初期部署时Longhorn 尚未就绪MySQL 和 Redis 的 PVC 使用了local-path作为存储后端。local-path 的核心问题数据绑定在单节点PVC 对应的目录只存在于 Pod 所在节点。Pod 漂移后数据丢失节点故障后Pod 被调度到其他节点原节点的目录访问不到数据相当于丢了。不支持多副本没有数据冗余节点磁盘坏了数据就没了。不支持 RWX无法多节点共享。Longhorn 解决这些问题数据多副本每个卷默认 3 副本分散在不同节点。Pod 漂移后数据仍在任意节点故障其他副本接管Pod 重新调度后能挂载数据。支持 RWX通过 NFSv4 实现多节点共享。支持快照和备份。结论生产环境必须用 Longhornlocal-path 只适合测试。1.2 迁移时机MySQL 和 Redis 当时都没有业务数据所以可以直接重建不需要备份迁移。如果已经有业务数据迁移步骤会更复杂备份数据。停掉服务。导出数据。重建 PVC。恢复数据。启动服务。本文档只覆盖“无业务数据”的场景。1.3 迁移目标服务迁移前迁移后MySQLlocal-pathlonghornRedislocal-pathlonghorn二、前置条件2.1 Longhorn 已就绪kubectl get storageclass这条命令看 StorageClass 列表预期看到longhorn。kubectl get pods -n longhorn-system这条命令看 Longhorn 组件预期全部Running。2.2 确认没有业务数据MySQLkubectl exec -it production-mysql-0 -c mysql -- mysqlsh --uri rootlocalhost --sql -e SHOW DATABASES;这条命令列出 MySQL 里的数据库如果只有系统库information_schema、mysql、performance_schema、sys说明没有业务数据。Rediskubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a 密码 DBSIZE这条命令看 Redis 里的 key 数量返回0说明没有数据。2.3 调整 Longhorn 存储设置这是关键步骤不改的话Longhorn 会因为“空间不足”拒绝调度副本。kubectl patch settings.longhorn.io storage-over-provisioning-percentage -n longhorn-system --typemerge -p {value:200}这条命令允许 Longhorn 超配到磁盘总容量的 200%。kubectl patch settings.longhorn.io storage-minimal-available-percentage -n longhorn-system --typemerge -p {value:10}这条命令把最小可用空间从 25% 降到 10%。kubectl patch settings.longhorn.io replica-replenishment-wait-interval -n longhorn-system --typemerge -p {value:0}这条命令把副本补充等待间隔设为 0立即补充副本。kubectl patch settings.longhorn.io replica-soft-anti-affinity -n longhorn-system --typemerge -p {value:true}这条命令开启软反亲和节点少时避免副本调度失败。三、迁移 MySQL3.1 删除旧 MySQLkubectl delete innodbcluster production-mysql这条命令删掉 InnoDBCluster 资源Operator 会清理相关 Pod 和 Service。kubectl delete pvc -n default --all这条命令删掉 default 命名空间下所有 PVC包括 MySQL 的三个。kubectl delete secret mysql-root-credentials这条命令删掉 MySQL 的 root 密码 Secret。3.2 确认 PVC 和 Longhorn 卷清理kubectl get pvc -n default这条命令确认 PVC 已删。kubectl get volumes.longhorn.io -n longhorn-system这条命令看 Longhorn 里还有没有 MySQL 的卷。如果有删掉它们kubectl delete volume.longhorn.io 卷名 -n longhorn-system3.3 修改 mysql-cluster.yaml把storageClassName从local-path改成longhornspec: datadirVolumeClaimTemplate: storageClassName: longhorn resources: requests: storage: 20Gi3.4 重新创建 Secretkubectl create secret generic mysql-root-credentials \ --namespace default \ --from-literalrootUserroot \ --from-literalrootHost% \ --from-literalrootPassword$(openssl rand -base64 24)这条命令创建新的 root 密码 Secret密码随机生成。kubectl get secret mysql-root-credentials -o jsonpath{.data.rootPassword} | base64 -d echo这条命令查看新密码保存好。3.5 重新安装 MySQLkubectl apply -f mysql-cluster.yaml这条命令提交 InnoDBCluster 资源Operator 会创建新的 Pod 和 PVC。3.6 观察启动kubectl get pods -o wide | grep production-mysql这条命令看 MySQL Pod 状态。kubectl get pvc -n default这条命令看 PVC 是否用上longhorn。kubectl get innodbcluster production-mysql -w这条命令观察集群状态按CtrlC退出预期从PENDING→INITIALIZING→ONLINE。3.7 如果卷 degraded排查kubectl get volume.longhorn.io volume-name -n longhorn-system -o yaml | grep -A5 type: Scheduled这条命令看卷的调度状态如果报insufficient storage说明 Longhorn 空间调度问题。解决kubectl get engines.longhorn.io -n longhorn-system | grep volume-name kubectl delete engine.longhorn.io engine-name -n longhorn-system这两条命令删掉卷的 engine触发副本重建。四、迁移 Redis4.1 删除旧 Redishelm uninstall production-redis -n redis这条命令卸载 Redis 的 Helm release。kubectl delete pvc -n redis --all这条命令删掉 redis 命名空间下所有 PVC。4.2 确认 PVC 和 Longhorn 卷清理kubectl get pvc -n redis这条命令确认 PVC 已删。kubectl get volumes.longhorn.io -n longhorn-system这条命令看 Longhorn 里还有没有 Redis 的卷。如果有删掉它们kubectl delete volume.longhorn.io 卷名 -n longhorn-system4.3 重新安装 Redis指定 longhornhelm install production-redis ./redis-cluster-13.0.4.tgz \ --namespace redis \ --set password强密码 \ --set cluster.nodes6 \ --set cluster.replicas1 \ --set persistence.storageClasslonghorn这条命令重新安装 Redis指定用longhorn存储。4.4 处理镜像拉取失败Bitnami 从 2025 年 8 月 28 日起移除了 Docker Hub 公共目录的免费镜像直接拉会返回 403。需要从bitnamilegacy拉旧版镜像然后打标签。ansible k8s_cluster -i inventory.ini -m shell -a crictl pull docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0 -b这条命令在所有节点上从bitnamilegacy拉镜像。ansible k8s_cluster -i inventory.ini -m shell -a ctr -n k8s.io images tag docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0 docker.m.daocloud.io/bitnami/redis-cluster:8.2.1-debian-12-r0 -b这条命令给镜像打标签让 containerd 认为本地有docker.m.daocloud.io/bitnami/redis-cluster。kubectl delete pod -n redis --all这条命令删掉所有 Redis PodStatefulSet 会自动重建。4.5 手动初始化 Redis 集群Bitnami chart 的集群初始化 Job 有时不会自动跑需要手动初始化。kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a 密码 --cluster create \ production-redis-redis-cluster-0.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ production-redis-redis-cluster-1.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ production-redis-redis-cluster-2.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ production-redis-redis-cluster-3.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ production-redis-redis-cluster-4.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ production-redis-redis-cluster-5.production-redis-redis-cluster-headless.redis.svc.cluster.local:6379 \ --cluster-replicas 1 --cluster-yes这条命令手动创建 Redis 集群3 主 3 从。4.6 观察启动kubectl get pods -n redis这条命令看 Redis Pod 是否变成1/1 Running。kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a 密码 cluster info这条命令看集群状态预期cluster_state:ok。kubectl get pvc -n redis这条命令看 PVC 是否用上longhorn。五、验证迁移结果5.1 确认 PVC 都用上 Longhornkubectl get pvc -A | grep -E mysql|redis这条命令看所有 MySQL 和 Redis 的 PVCSTORAGECLASS列应该是longhorn。5.2 确认 Longhorn 卷全部 healthykubectl get volumes.longhorn.io -n longhorn-system这条命令看所有 Longhorn 卷的ROBUSTNESS列应该是healthy。5.3 确认 MySQL 正常kubectl get innodbcluster production-mysql这条命令看 MySQL 集群状态预期ONLINE。kubectl exec -it production-mysql-0 -c mysql -- mysqlsh --uri rootlocalhost --sql -e SHOW DATABASES;这条命令看 MySQL 数据库列表确认能正常连接。5.4 确认 Redis 正常kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a 密码 cluster info这条命令看 Redis 集群状态预期cluster_state:ok。kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -c -a 密码 set test-key hello kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -c -a 密码 get test-key这两条命令测试 Redis 读写。六、常见问题6.1 MySQL 卷 degraded原因Longhorn 调度副本失败。排查kubectl get volume.longhorn.io volume-name -n longhorn-system -o yaml | grep -A5 type: Scheduled如果报insufficient storagekubectl patch settings.longhorn.io storage-over-provisioning-percentage -n longhorn-system --typemerge -p {value:200} kubectl patch settings.longhorn.io storage-minimal-available-percentage -n longhorn-system --typemerge -p {value:10}然后触发副本重建kubectl get engines.longhorn.io -n longhorn-system | grep volume-name kubectl delete engine.longhorn.io engine-name -n longhorn-system6.2 Redis 镜像拉取失败原因Bitnami 移除了 Docker Hub 公共目录的免费镜像。解决从bitnamilegacy拉镜像并打标签见 4.4 节。6.3 Redis 集群状态fail原因集群初始化 Job 没跑。解决手动初始化集群见 4.5 节。6.4 Redis PodREADY 0/1原因Redis 容器起来了但健康检查失败因为集群没初始化。解决手动初始化集群见 4.5 节。七、总结7.1 迁移对比项目迁移前迁移后MySQL 存储local-pathlonghornRedis 存储local-pathlonghorn数据副本1单节点3多节点节点故障数据丢失数据不丢Pod 漂移数据访问不到自动挂载其他副本7.2 关键操作步骤命令调整 Longhorn 设置kubectl patch settings.longhorn.io ...删除旧 MySQLkubectl delete innodbcluster production-mysql删除旧 Redishelm uninstall production-redis -n redis重新安装 MySQLkubectl apply -f mysql-cluster.yaml重新安装 Redishelm install production-redis ... --set persistence.storageClasslonghorn手动初始化 Redis 集群redis-cli --cluster create ...7.3 踩过的坑坑原因解决Longhorn 卷degraded空间调度保守改over-provisioning200和minimal-available10Redis 镜像 403Bitnami 移除免费镜像从bitnamilegacy拉并打标签Redis 集群fail初始化 Job 没跑手动redis-cli --cluster createRedis Pod0/1集群没初始化同上7.4 一句话MySQL 和 Redis 的存储已经从 local-path 迁移到 Longhorn数据从“单节点、无副本”变成“多节点、多副本”节点故障不再丢数据。
