将 Lustre 客户端挂载到多个容器并实现并发读写
解读
国内金融、运营商、超算中心普遍用 Lustre 做并行文件系统,容器化后又要求“一次挂载、多容器复用”且保证 POSIX 语义一致、性能不降、故障域不扩大。面试官想确认你是否同时理解 Lustre 客户端内核态原理 与 Docker 运行时隔离机制,并能在 国产化内核(麒麟、统信、Anolis OS) 下给出可落地的工程方案,而不是简单“-v 映射”。
知识点
- Lustre 客户端本质:内核模块 lustre、ldiskfs、ko2iblnd,依赖 /dev/ 下设备节点与 /proc/fs/lustre/ 状态接口,必须共享宿主机内核。
- Docker 的 mount namespace 隔离:默认新容器有私有 mount ns,内核级文件系统挂载事件不会传播,导致“宿主机 mount 后容器不可见”。
- 特权容器与 CAP_SYS_ADMIN:挂载操作需要 CAP_SYS_ADMIN;国产化宿主机强制启用 SELinux 时,还需 CAP_DAC_READ_SEARCH。
- 传播挂载(rshared/rslave):systemd 默认把 / 设为 shared,但 CentOS 7.6 之前为 slave,需手动
mount --make-rshared /。 - 并发读写一致性:Lustre 本身提供 分布式锁(LDLM),但 缓存一致性依赖客户端的 lru_size 与 osc.*.max_dirty_mb 参数,需统一调优。
- 国产化坑点:麒麟 V10 SP2 内核 4.19.90-23.6 缺 ko2iblnd 模块,需提前编译 kmod-lustre 并做 DKMS 签名,否则容器内 ls 直接挂死。
- DevOps 集成:镜像里不能带内核模块,CI 阶段只打包 lfs setstripe、lfs getstripe 等用户态工具;真正挂载由宿主机 Ansible playbook 统一完成,保证 “基础设施层统一、业务层无感知”。
答案
步骤一:宿主机一次性准备
- 安装与内核严格匹配的 kmod-lustre-client(国产环境用 DKMS 签名)。
- 加载模块并挂载 MGS/MDT:
modprobe lustre mount -t lustre 10.10.10.1@tcp0:/lustre /mnt/lustre - 确认传播属性:
mount --make-rshared /mnt/lustre findmnt -o TARGET,PROPAGATION /mnt/lustre # 输出应为 shared
步骤二:容器侧声明 Dockerfile 里不装内核模块,只放用户态:
FROM registry.cn-hangzhou.aliyuncs.com/amd64/centos:7.9
RUN yum -y install lustre-client-dkms && yum clean all
构建后镜像仅 120 MB,不含 ko,避免合规风险。
步骤三:运行多容器
docker run -d --name app1 \
--cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH \
--security-opt label=disable \
-v /mnt/lustre:/data:rw,rshared \
my/lustre-app:1.0
docker run -d --name app2 \
--cap-add SYS_ADMIN \
-v /mnt/lustre:/data:rw,rshared \
my/lustre-app:1.0
关键点:
- 必须加 rshared 标志,否则容器重启后挂载点消失;
- 国产化 SELinux 强制模式下需
--security-opt label=disable或打自定义策略,否则touch报 EACCES; - 非 root 用户运行时,容器内 uid/gid 要与 Lustre 服务端一致,提前在 LDAP/AD 统一。
步骤四:并发读写验证 容器 1 执行:
lfs setstripe -c 4 -S 4M /data/test.big
dd if=/dev/zero of=/data/test.big bs=1M count=1024 oflag=direct
容器 2 同时:
dd if=/data/test.big of=/dev/null bs=1M iflag=direct
观察 /proc/fs/lustre/osc/*/stats 的 read_bytes 与 write_bytes 同时上涨,无 MD5 不一致即验收通过。
步骤五:生产加固
- 把挂载操作下沉到 DaemonSet,容器只负责
mount --bind避免重复挂载; - 通过 Kubernetes CSI-lustre 插件(社区版已支持 ARM64)做动态卷,屏蔽 CAP_SYS_ADMIN;
- 统一调优:
减少并发写抖动;lctl set_param osc.*.max_dirty_mb=256 lctl set_param llite.*.max_read_ahead_mb=128 - 监控:Prometheus + node_exporter 文本文件收集
/proc/fs/lustre/*/stats,告警项包括ldlm_canceld超时与osc.*.ost_disconnect。
拓展思考
- 多架构国产化:在鲲鹏 920 + 麒麟 V10 SP3 场景,内核 5.10 已内置 LNet self-test,但仍需关闭 ARM64 的 64K page 以兼容老 OST,如何在 Dockerfile 中探测 page size 并给出启动警告?
- 跨云混合挂载:公有云容器实例(如阿里云 ECI)无法加载自定义内核模块,是否考虑 用户态 FUSE-lustre?其性能损失 30%+,如何 通过 RDMA-FUSE 补丁降到 10% 以内?
- 安全最小化:如果监管要求“容器不得携带 CAP_SYS_ADMIN”,能否利用 systemd-mount 的 setuid helper 在宿主机预挂载,然后容器通过 bind-mount + readonly 路径 实现“只读并发、写操作走 sidecar 代理”?请给出 sidecar 与主容器共享 POSIX 写锁的代码框架。