非常好!你希望从 最开始的完整流程 来复盘整个过程 ------ 从创建 NFS 共享目录、配置 /etc/exports、部署 PV/PVC、Pod 启动失败,到最终通过修改权限修复问题。
下面我将为你 系统性地还原整个操作链条,并解释每一步的作用和背后的原理,形成一份清晰、可复用的"NFS + RabbitMQ 部署排错全记录"。
🧩 全流程复盘:从零搭建 NFS 存储 → RabbitMQ Pod 成功运行
第一步:在 NFS 服务器上创建持久化目录
# 登录 NFS 服务器(192.168.10.214)
ssh admin@192.168.10.214
# 创建项目根目录
sudo mkdir -p /mnt/sdd/ctjt-zsa-prod/nfs
# 为 RabbitMQ 创建子目录(对应两个实例)
sudo mkdir -p /mnt/sdd/ctjt-zsa-prod/nfs/zsa-rabbitmq-biz
sudo mkdir -p /mnt/sdd/ctjt-zsa-prod/nfs/zsa-rabbitmq-web
# 可选:设置初始属主(非必须,但建议)
sudo chown -R nobody:nogroup /mnt/sdd/ctjt-zsa-prod/nfs
✅ 目的:为 Kubernetes 的 PV 提供后端存储路径。
🔒 此时目录为空,
.erlang.cookie尚未生成。
第二步:配置 NFS 导出(/etc/exports)
编辑 NFS 导出配置:
sudo vim /etc/exports
添加如下行(关键!):
/mnt/sdd/ctjt-zsa-prod/nfs *(rw,sync,no_subtree_check,no_root_squash)
/mnt/sdd/ctjt-zsa-prod/nfs/zsa-redis-biz 192.168.10.0/24(rw,sync,no_root_squash,no_subtree_check)
🔑 关键参数说明:
rw:读写权限sync:同步写入(更安全)no_subtree_check:提升性能no_root_squash:允许客户端 root 用户在服务端保留 root 权限 ← 这是后续能chown 999的前提!
然后重载 NFS 配置:
sudo exportfs -ra
sudo systemctl reload nfs-kernel-server # 或 nfs-server,取决于系统
✅ 目的:让 K8s 节点能挂载该目录,并具备修改文件属主的能力。
第三步:在 Kubernetes 中创建 PV 和 PVC
你创建了类似如下的 PV(静态供给):
apiVersion: v1
kind: PersistentVolume
metadata:
name: zsa-rabbitmq-biz
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.10.214
path: "/mnt/sdd/ctjt-zsa-prod/nfs/zsa-rabbitmq-biz"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zsa-rabbitmq-biz
namespace: ctjt-zsa
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
✅ 目的:将 NFS 目录映射为 K8s 可用的存储卷。
第四步:部署 RabbitMQ Deployment(挂载整个目录)
你的 Deployment 大概如下:
volumeMounts:
- name: data
mountPath: /var/lib/rabbitmq # ← 挂载整个目录!
volumes:
- name: data
persistentVolumeClaim:
claimName: zsa-rabbitmq-biz
⚠️ 问题根源就在这里:挂载了整个
/var/lib/rabbitmq目录 ,导致.erlang.cookie也会被写入 NFS。
第五步:Pod 启动失败(典型报错)
当你执行:
kubectl apply -f rabbitmq-deployment.yaml
Pod 卡在 CrashLoopBackOff,日志显示:
Cookie file /var/lib/rabbitmq/.erlang.cookie must be accessible by owner only
原因分析:
- RabbitMQ 容器启动时,发现
/var/lib/rabbitmq是空的(因为 NFS 目录刚创建) - 自动创建
.erlang.cookie - 但由于 NFS 默认行为(即使有
no_root_squash,容器内 UID=999 可能无权设 600),文件权限变成644 - Erlang 安全机制拒绝启动
第六步:手动修复 .erlang.cookie 权限(关键转折)
你回到 NFS 服务器,执行:
# 进入 biz 目录
cd /mnt/sdd/ctjt-zsa-prod/nfs/zsa-rabbitmq-biz
# 删除可能已存在的错误 cookie
sudo rm -f .erlang.cookie
# 创建新 cookie(内容任意,但集群需一致)
echo "CTJT_ZSA_RABBITMQ_COOKIE" | sudo tee .erlang.cookie
# 设置严格权限 ← 核心!
sudo chmod 600 .erlang.cookie
sudo chown 999:999 .erlang.cookie # RabbitMQ 容器 UID=999
# 同样处理 web 实例
cd ../zsa-rabbitmq-web
echo "CTJT_ZSA_RABBITMQ_COOKIE" | sudo tee .erlang.cookie
sudo chmod 600 .erlang.cookie
sudo chown 999:999 .erlang.cookie
✅ 成功前提:
- NFS 配置了
no_root_squash→ 允许chown 999- 你在 NFS 服务端 操作 → 修改的是真实文件
第七步:重启 Pod,验证成功
kubectl delete pod -n ctjt-zsa -l app=zsa-rabbitmq-biz
kubectl delete pod -n ctjt-zsa -l app=zsa-rabbitmq-web
新 Pod 启动后:
- 挂载 NFS 目录
- 发现已存在合法的
.erlang.cookie(600 + UID=999) - Erlang 通过安全检查
- RabbitMQ 正常启动 ✅
📌 全流程关键点总结
表格
| 阶段 | 操作 | 作用 | 风险/注意 |
|---|---|---|---|
| 1. 准备存储 | 创建 NFS 子目录 | 提供 PV 后端路径 | 目录需可写 |
| 2. 导出配置 | /etc/exports + no_root_squash |
允许权限修改 | 缺少则 chown 失败 |
| 3. K8s 部署 | PV/PVC + 挂载 /var/lib/rabbitmq |
持久化数据 | 但连带持久化了 cookie |
| 4. 启动失败 | Pod CrashLoop | 因 cookie 权限不安全 | 典型 Erlang 报错 |
| 5. 手动修复 | 在 NFS 服务端设 600 + 999:999 |
满足安全策略 | 必须在服务端操作 |
| 6. 重启验证 | 删除 Pod 触发重建 | 加载合法 cookie | 成功运行 |
🔚 最终建议:如何避免下次再踩坑?
虽然你现在成功了,但这个方案 依赖手动干预,不适合自动化或大规模部署。
✅ 推荐长期方案:只挂载 /mnesia 子目录
修改 Deployment:
volumeMounts:
- name: data
mountPath: /var/lib/rabbitmq/mnesia # ← 不挂整个目录!
这样:
.erlang.cookie在容器层生成(权限永远正确)- 消息数据仍在 NFS(
mnesia目录包含队列、交换器等) - 无需手动创建 cookie,无需改权限,天然兼容 NFS
这是官方推荐做法,也是 Helm Chart 的默认行为。