juicefs-test-dump-binary
JuiceFS 元数据迁移演练手册(测试集群实战版)
目标:在你的测试 K8s 集群里,把"Redis → TiKV 元数据迁移"完整演练一遍:
只读导出 → 临时 TiKV → 导入验证 → 真挂载 → 完整切换回滚。
所有命令已按你的实测环境写好,照敲即可;玩坏了随时推倒重来。
0. 已实测的环境信息(直接可用)
| 项目 | 实测值 | 来源 |
|---|---|---|
| 文件系统名 | my-jfs | Mount Pod 的 mount 输出 |
| Redis 地址 | juicefs-redis.juicefs-system.svc.cluster.local:6379 db 0 | Mount Pod cmdline |
| Redis Pod | juicefs-system/juicefs-redis-0(StatefulSet + local-path) | kubectl get pod |
| Mount Pod ×2 | kube-system/juicefs-liu-node1-pvc-18d437a4-1d22-4b9b-b2a9-2bbeb9d6c7bb-spcuko(node2 上还有一个 -ijvuhm) | kubectl get pod |
| 业务 PVC | default/nginx-www-pvc(动态)+ default/juicefs-archive-pvc(静态,当前闲置) | kubectl get pv/pvc |
| Secret ×4 | kube-system/juicefs-sc-secret、kube-system/juicefs-pvc-18d4...-secret、kube-system/juicefs-juicefs-archive-pv-secret、juicefs-system/juicefs-redis-secret | kubectl get secret |
| Redis 密码 | <REDIS密码> ← 占位,执行 §1.2 解码获得 | |
| master 内网 IP | <MASTER_IP> ← 占位,kubectl get nodes -o wide 查看 |
# 全文统一用这两个变量,先 export 一次
export MOUNT_POD=juicefs-liu-node1-pvc-18d437a4-1d22-4b9b-b2a9-2bbeb9d6c7bb-spcuko
export MASTER_IP=<MASTER_IP>1. 阶段 0:现状确认(部分已完成)
# 1.1 挂载确认 ✅ 已完成,输出:JuiceFS:my-jfs on /jfs/pvc-... type fuse.juicefs
kubectl -n kube-system exec $MOUNT_POD -- sh -c "mount | grep -i juicefs"
# 1.2 拿密码(解码主 Secret 的 metaurl,顺手看有没有 secret-key 字段)
kubectl -n kube-system get secret juicefs-sc-secret \
-o go-template='{{range $k,$v := .data}}{{$k}}: {{$v | base64decode}}{{"\n"}}{{end}}'
# 1.3 版本(≥1.3.0 才能用 --binary,低了就去掉 --binary 改用 .json)
kubectl -n kube-system exec $MOUNT_POD -- juicefs version
# 1.4 活跃会话(对应生产"三道闸"第一道;现在有 1~2 个会话是正常的)
kubectl -n kube-system exec $MOUNT_POD -- \
juicefs status redis://:<REDIS密码>@juicefs-redis.juicefs-system.svc.cluster.local:6379/0
# 1.5 Redis 里的 key 总量(等下和 dump 条目数对账)
kubectl -n juicefs-system exec juicefs-redis-0 -- redis-cli -a '<REDIS密码>' --no-auth-warning info keyspace
kubectl -n juicefs-system exec juicefs-redis-0 -- redis-cli -a '<REDIS密码>' --no-auth-warning -n 0 dbsize质量门 G0:版本明确、密码拿到、keyspace 有输出。
2. 阶段 1:只读导出演练(业务不停,零风险)
dump 对 Redis 只有读操作,随便跑。正式迁移的区别只是"停写后再导一次"。
# 2.1 导出(计时!这个耗时就是未来评估真实窗口的依据)
kubectl -n kube-system exec -it $MOUNT_POD -- sh -c "
time juicefs dump \
'redis://:<REDIS密码>@juicefs-redis.juicefs-system.svc.cluster.local:6379/0' \
/tmp/meta-test.zstd --binary --keep-secret-key &&
ls -lh /tmp/meta-test.zstd"
# 记录:输出里的 entry 数量、耗时、文件大小
# entry 数应≈dbsize 数量级;差太多要贴出来分析
# 2.2 拷到 master 异地备份(养成习惯:导完必拷出)
kubectl cp kube-system/$MOUNT_POD:/tmp/meta-test.zstd ~/meta-test.zstd
md5sum ~/meta-test.zstd质量门 G1:dump 无报错、文件已拷出、md5 已记录。
3. 阶段 2:临时 TiKV + 导入 + 免挂载验证
3.1 master 上起 tiup playground(前台运行,Ctrl+C 即销毁)
curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
source ~/.bash_profile 2>/dev/null || source ~/.bashrc
tiup playground v8.1.0 --db 0 --kv 1 --pd 1 --tiflash 0 --without-monitor
# 启动后打印 PD 地址(127.0.0.1:2379);另开一个 SSH 终端继续下面操作playground = 一次性玩具集群,只起 PD+TiKV(JuiceFS 用不上 TiDB/TiFlash)。生产的区别是 tiup cluster 部署 3+3 并常驻,原理相同。3.2 master 上装 JuiceFS 客户端并导入
从 master 直连 127.0.0.1:2379,网络最简单,排除 Pod→节点网络的变数。
curl -sSL https://d.juicefs.com/install | sh -
juicefs version
time juicefs load tikv://127.0.0.1:2379/jfs ~/meta-test.zstd3.3 免挂载验证(重点教学:ls/fsck 不经过 FUSE,直接查元数据引擎)
# 新引擎侧
juicefs ls tikv://127.0.0.1:2379/jfs /
juicefs fsck tikv://127.0.0.1:2379/jfs /
# 旧引擎侧(master 访问不了 svc 域名,用 ClusterIP 或回 Mount Pod 执行)
kubectl -n juicefs-system get svc juicefs-redis # 拿到 ClusterIP
juicefs ls 'redis://:<REDIS密码>@<ClusterIP>:6379/0' /
# 两边目录树一致 + fsck 通过 = 迁移数据正确质量门 G2:load 完成无报错、两侧 ls 一致、fsck 通过。
4. 阶段 3(可选):真·FUSE 挂载 TiKV 版
mkdir -p /mnt/jfs-test
juicefs mount tikv://127.0.0.1:2379/jfs /mnt/jfs-test &
sleep 3
mount | grep jfs-test # 确认挂上
ls -R /mnt/jfs-test | head -50 # 文件树对比
find /mnt/jfs-test -type f | head -5 | xargs -I{} sh -c 'echo "== {}"; head -c 200 {} ; echo'
# 抽样读内容:能读出 = 元数据→对象存储全链路通
umount /mnt/jfs-test5. 进阶 A:去掉 --keep-secret-key 重跑(演练 SK 丢失预案)
对应生产最大风险项:dump 默认不导出对象存储 SK,load 后要手动补。
# 5.1 重新导出(去掉 --keep-secret-key)+ 换个 TiKV 前缀
kubectl -n kube-system exec -it $MOUNT_POD -- sh -c "
juicefs dump 'redis://:<REDIS密码>@juicefs-redis.juicefs-system.svc.cluster.local:6379/0' \
/tmp/meta-nosk.zstd --binary"
kubectl cp kube-system/$MOUNT_POD:/tmp/meta-nosk.zstd ~/meta-nosk.zstd
juicefs load tikv://127.0.0.1:2379/jfs-nosk ~/meta-nosk.zstd
# 5.2 此时 fsck 会报访问对象存储失败(SK 缺失)→ 演练补密钥
juicefs config tikv://127.0.0.1:2379/jfs-nosk \
--access-key <AK> --secret-key <SK> # AK/SK 从 juicefs-sc-secret 解码获得
# 5.3 再次 fsck 验证恢复
juicefs fsck tikv://127.0.0.1:2379/jfs-nosk /6. 进阶 B:完整 CSI 切换演练(生产最险一步的彩排)
流程:备份 Secret → 试连通 → 改 metaurl → 重建 Mount Pod → 验证 → 回切。
在测试集群随便玩,玩坏回切即可。
# 6.1 备份所有相关 Secret(回滚的命根子)
mkdir -p ~/secret-backup
for s in "kube-system juicefs-sc-secret" \
"kube-system juicefs-pvc-18d437a4-1d22-4b9b-b2a9-2bbeb9d6c7bb-secret" \
"kube-system juicefs-juicefs-archive-pv-secret"; do
set -- $s
kubectl -n $1 get secret $2 -o yaml > ~/secret-backup/$2.yaml
done
ls -la ~/secret-backup/
# 6.2 前置试连通:Pod 能否访问 master:2379(不通则本进阶做不了,看下方备注)
kubectl -n kube-system exec $MOUNT_POD -- sh -c "nc -zv $MASTER_IP 2379 || echo UNREACHABLE"
# 6.3 停写(演练版):缩容业务 Deployment,确认 Mount Pod 消失
kubectl get deploy -n default # 找到用 nginx-www-pvc 的 deploy
kubectl -n default scale deploy <业务DEPLOY名> --replicas=0
sleep 10
kubectl -n kube-system get pod | grep juicefs-liu # Mount Pod 应消失(CSI 按需创建)
# 6.4 正式导出(停写后的"一致性版本")→ 导入新前缀 /jfs-prod
kubectl -n kube-system run juicefs-migrator --image=juicedata/mount:ce-v1.3.0 \
--restart=Never --overrides='{"spec":{"hostNetwork":true,"dnsPolicy":"ClusterFirstWithHostNet",
"containers":[{"name":"juicefs-migrator","image":"juicedata/mount:ce-v1.3.0",
"command":["sleep","3600"],"securityContext":{"privileged":true}}]}}'
kubectl -n kube-system exec -it juicefs-migrator -- sh -c "
juicefs dump 'redis://:<REDIS密码>@juicefs-redis.juicefs-system.svc.cluster.local:6379/0' \
/tmp/meta-prod.zstd --binary --keep-secret-key &&
juicefs load tikv://$MASTER_IP:2379/jfs-prod /tmp/meta-prod.zstd &&
juicefs fsck tikv://$MASTER_IP:2379/jfs-prod /"
# 6.5 计算新 metaurl 的 base64 并 patch 三个 CSI Secret
NEW_B64=$(echo -n "tikv://$MASTER_IP:2379/jfs-prod" | base64 -w0)
echo $NEW_B64
for s in juicefs-sc-secret juicefs-pvc-18d437a4-1d22-4b9b-b2a9-2bbeb9d6c7bb-secret juicefs-juicefs-archive-pv-secret; do
kubectl -n kube-system patch secret $s --type merge -p "{\"data\":{\"metaurl\":\"$NEW_B64\"}}"
done
kubectl -n kube-system get secret juicefs-sc-secret -o jsonpath='{.data.metaurl}' | base64 -d; echo
# 确认显示 tikv://...
# 6.6 拉起业务 → CSI 用新 metaurl 重建 Mount Pod
kubectl -n default scale deploy <业务DEPLOY名> --replicas=2
sleep 15
kubectl -n kube-system get pod | grep juicefs-liu # 新的 Mount Pod 出现
# 6.7 验证切换生效(cmdline 里应该是 tikv:// 了)
NEWPOD=$(kubectl -n kube-system get pod | grep juicefs-liu-node1 | awk '{print $1}' | head -1)
kubectl -n kube-system exec $NEWPOD -- sh -c "cat /proc/1/cmdline | tr '\0' ' '; echo"
kubectl -n default get pods # 业务 Running
# 进业务 Pod 读写一个文件验证(按你的业务实际路径)
# 6.8 回切演练(完整走一遍回滚)
kubectl -n default scale deploy <业务DEPLOY名> --replicas=0
for s in juicefs-sc-secret juicefs-pvc-18d437a4-1d22-4b9b-b2a9-2bbeb9d6c7bb-secret juicefs-juicefs-archive-pv-secret; do
kubectl replace -f ~/secret-backup/$s.yaml --force
done
kubectl -n default scale deploy <业务DEPLOY名> --replicas=2
kubectl -n kube-system exec $(kubectl -n kube-system get pod | grep juicefs-liu-node1 | awk '{print $1}' | head -1) \
-- sh -c "cat /proc/1/cmdline | tr '\0' ' '; echo" # 确认回到 redis://
# 6.9 清理迁移 Pod
kubectl -n kube-system delete pod juicefs-migrator6.2 不通的备选:把 playground 绑到 node 节点上起、或给 playground 所在网卡放通、或跳过进阶 B(生产 TiKV 在同 VPC ECS 上,天然可达)。先搞清楚为什么不通,这个排错过程本身就是学习。
质量门 G3:切换后 cmdline 显示 tikv:// 且业务读写正常;回切后显示 redis:// 且业务正常。
7. 清场
# playground 终端按 Ctrl+C(TiKV 数据随之销毁,无所谓)
umount /mnt/jfs-test 2>/dev/null; rmdir /mnt/jfs-test
kubectl -n kube-system delete pod juicefs-migrator 2>/dev/null
# Secret 备份目录留着,正式迁移时还是模板
# ~/meta-test.zstd ~/meta-nosk.zstd 留作纪念/对比8. 演练 ↔ 生产对照表
| 演练里做的 | 生产对应 |
|---|---|
juicefs status 看会话 | 停写三道闸第一道(Sessions 必须为空) |
| dump 计时 | 正式窗口时长测算 |
| tiup playground(1 PD + 1 TiKV) | tiup cluster 部署 PD×3 + TiKV×3 + 监控 |
| load + ls/fsck 验证 | 正式导入 + 质量门(含 entry 对账) |
| 去掉 --keep-secret-key + config 补 SK | SK 丢失应急预案 |
| 改 3 个 Secret + 重建 Mount Pod | 生产 CSI 切换的标准动作 |
| kubectl replace 回切 | 生产回滚预案 |
| master 装客户端挂载 | 宿主机场景的验证方式 |
9. 自查题(能答才算练会)
- 为什么 dump 可以业务不停随便跑,正式切换却必须停写后再导一次?
- load 中断为什么可以直接重试?要不要重新 dump?
- 为什么
juicefs ls/fsck不需要挂载就能验证元数据? --keep-secret-key加与不加的区别?生产怎么选?- 改完 Secret 为什么要重建 Mount Pod 才生效?(提示:metaurl 是什么时候被读进挂载命令的)
- 为什么切换前要试
nc -zv $MASTER_IP 2379?生产上对应的检查是什么? - playground 和 tiup cluster 部署的集群,运维上有什么本质区别?
