上一篇 下一篇 分享链接 返回 返回顶部

如何在香港服务器的 Ubuntu 环境中,把 CephFS 和 Kubernetes 绑在一起,撑起一套分布式仿真平台

发布人:Minchunlin 发布时间:2025-09-08 11:32 阅读量:692


那天是周五的凌晨两点,我裹着冲锋衣站在香港荃湾机房6楼的 42U 机柜前,手指按在 BMC 的电源键上,耳边是 PDU 的继电器轻轻“嗒”了一下和风扇高转的呼啸。我们要在 48 小时内把一套新的仿真平台跑起来:Kubernetes 负责编排,CephFS 负责共享并行 I/O,目标是让 CFD 与多体动力学仿真在 50 台节点上稳定地跑通、不中断。这个记录,写给同样在机房里与时间赛跑的人。

1. 目标与场景

目标:在 Ubuntu 环境上部署一套 Kubernetes + CephFS 的分布式仿真平台,支持 MPI 等并行工作负载,提供 RWX(多节点读写) 的共享文件系统与高元数据吞吐。

选择:CephFS 作为共享存储(可横向扩展、强一致、MDS 支持元数据水平扩展),Kubernetes 通过 Ceph-CSI 动态供给卷,研发只关心 PVC 和路径。

约束:香港本地机房,25GbE 网络,仿真 I/O 偏元数据密集(小文件多、目录层级深),并需要跨组协同与快照留痕。

2. 拓扑与硬件清单

2.1 逻辑拓扑(文字版)

  • Ceph 集群(裸金属):3 台 MON/MGR/MDS 复用节点 + 12 台 OSD 节点
  • Kubernetes 集群:3 控 9 工(control-plane 3 台、worker 9 台),与 Ceph 通过专网互通

网络:

  • bond0.10(Ceph public 网):10.10.10.0/24
  • bond0.20(Ceph cluster 网):10.10.20.0/24
  • bond0.30(K8s Pod/Service 网,CNI = Cilium,MTU 发现模式 + Jumbo 9000)
  • 时钟:Chrony 本地源 + 上游 NTP 双路冗余

2.2 版本组合(可直接复刻)

组件 版本 说明
OS Ubuntu 22.04.4 LTS 全节点统一
Kubernetes v1.28.x kubeadm + containerd
CNI Cilium v1.14+ eBPF,MTU 自动探测
Ceph Reef 18.2.x cephadm 部署
Ceph-CSI v3.9+ cephfs.csi.ceph.com
MPI OpenMPI 4.1+ / MPI Operator CFD/FEA 作业

2.3 硬件与分区

用途 型号/CPU 内存 系统盘 数据盘 网卡
MON/MGR/MDS*3 2×Intel Xeon Silver 4316 256GB 2×480GB SATA(RAID1) 2×1.92TB NVMe(DB/WAL)+ 4×12TB HDD(OSD) 2×25GbE(Bond LACP)
OSD*12 AMD EPYC 7313P 256GB 480GB SATA 2×1.92TB NVMe(DB/WAL)+ 10×14TB HDD(OSD) 2×25GbE(Bond LACP)
控制平面*3 Intel Xeon 4310 128GB 480GB SATA - 2×25GbE
工作节点*9 AMD EPYC 7313P 256GB 480GB SATA 可选 1×1.92TB NVMe(本地缓存) 2×25GbE

关键点:OSD 用 HDD,DB/WAL 落 NVMe,性价比与延迟兼顾。MDS 节点给足内存。

3. 网络与 IP 规划(示例)

角色 主机名 Public IP (bond0.10) Cluster IP (bond0.20)
mon-mgr-mds01 ceph-ctrl01 10.10.10.11 10.10.20.11
mon-mgr-mds02 ceph-ctrl02 10.10.10.12 10.10.20.12
mon-mgr-mds03 ceph-ctrl03 10.10.10.13 10.10.20.13
osd01…osd12 ceph-osd01…12 10.10.10.21…32 10.10.20.21…32

Linux 网络:/etc/netplan 里做 bond0 + vlan,开启 Jumbo 9000,交换机侧 LACP;MTU 不一致是最常见“坑1”(后面详述)。

4. 系统与内核调优(必做)

/etc/sysctl.d/99-hpc.conf:

net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_mtu_probing = 1
fs.aio-max-nr = 1048576
fs.inotify.max_user_watches = 1048576
vm.swappiness = 10
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5

CPU 省电策略调为 performance:cpupower frequency-set -g performance

关闭 BIOS C-State 深度(MDS 对延迟很敏感)

NIC 中断亲和与 RSS:irqbalance on,必要时手动绑核;ethtool -G 调整队列缓冲(视 NIC)

5. 部署 Kubernetes(kubeadm + containerd)

5.1 containerd

apt-get update && apt-get install -y containerd
containerd config default > /etc/containerd/config.toml
# SystemdCgroup = true
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
systemctl enable --now containerd

5.2 kubeadm 初始化(控制面)

apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update && apt-get install -y kubelet kubeadm kubectl
kubeadm init --kubernetes-version v1.28.6 \
  --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube && cp /etc/kubernetes/admin.conf $HOME/.kube/config

CNI 我选 Cilium(eBPF):

kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.14/install/kubernetes/quick-install.yaml

5.3 加入节点

kubeadm token create --print-join-command
# 在各节点执行 join 命令

6. 部署 Ceph(cephadm,独立于 K8s,更稳)

6.1 引导集群

在 ceph-ctrl01:

curl --silent --remote-name https://download.ceph.com/keys/release.asc
apt-get install -y cephadm
cephadm bootstrap --mon-ip 10.10.10.11 \
  --initial-dashboard-user admin \
  --initial-dashboard-password 'Str0ngPass!'

# 加入其他主机
cephadm shell -- ceph orch host add ceph-ctrl02 10.10.10.12
cephadm shell -- ceph orch host add ceph-ctrl03 10.10.10.13
for i in {1..12}; do
  cephadm shell -- ceph orch host add ceph-osd$(printf "%02d" $i) 10.10.10.$((20+$i))
done

6.2 双网与设备发现

ceph config set global public_network '10.10.10.0/24'
ceph config set global cluster_network '10.10.20.0/24'
ceph orch device ls

6.3 按“驱动组”建 OSD(NVMe 做 DB/WAL)

drivegroup.yaml(示例):

service_type: osd
service_id: hdd-with-nvme-db
placement:
  host_pattern: "ceph-osd*"
data_devices:
  rotational: true
  size: ">= 12TB"
db_devices:
  rotational: false
  size: ">= 1.6TB"
  limit: 1

应用:

cephadm shell -- ceph orch apply osd -i drivegroup.yaml

6.4 创建 CephFS

# 池(注意 pg_num 根据 OSD 数量计算,这里示例)
ceph osd pool create cephfs_data 512
ceph osd pool create cephfs_metadata 64

# 三副本(仿真中通常更看重可靠)
ceph osd pool set cephfs_data size 3
ceph osd pool set cephfs_metadata size 3

# 建文件系统与 MDS
ceph fs new cephfs cephfs_metadata cephfs_data
ceph fs set cephfs max_mds 2
ceph fs set cephfs standby_count_wanted 1
# 给 CSI 用的 subvolumegroup
ceph fs subvolumegroup create cephfs csi

6.5 关键调优(依据负载)

# MDS 内存与缓存(按 MDS 节点内存给)
ceph config set mds mds_cache_memory_limit 4294967296    # 4GB
ceph config set mds mds_log_max_segments 128
ceph config set global osd_recovery_max_active 5
ceph config set global osd_max_backfills 2
ceph config set client client_cache_size 1000000

7. 给 K8s 准备 Ceph-CSI 账号与密钥

7.1 创建用户

# 供给与节点阶段分两个用户(最小权限原则)
ceph auth get-or-create client.csi-cephfs-provisioner \
  mon 'allow r' mgr 'allow rw' mds 'allow rw' osd 'allow rw tag cephfs data=cephfs' \
  -o /etc/ceph/csi-cephfs-provisioner.keyring

ceph auth get-or-create client.csi-cephfs-node \
  mon 'allow r' mgr 'allow rw' mds 'allow rw' osd 'allow rw tag cephfs data=cephfs' \
  -o /etc/ceph/csi-cephfs-node.keyring

# 拿 FSID 与 MON 列表
ceph fsid
ceph mon dump | grep "mon."    # MON IP:PORT

(把 keyring 中的 key = ... 记下)

8. 在 Kubernetes 安装 Ceph-CSI(CephFS)

命名空间与 ConfigMap:

apiVersion: v1
kind: Namespace
metadata:
  name: ceph-csi
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ceph-csi-config
  namespace: ceph-csi
data:
  config.json: |
    [
      {
        "clusterID": "e5ab1234-...-fsid",    # 用 ceph fsid 的值
        "monitors": [
          "10.10.10.11:6789",
          "10.10.10.12:6789",
          "10.10.10.13:6789"
        ]
      }
    ]

密钥(两个 Secret):

apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-provisioner
  namespace: ceph-csi
stringData:
  userID: client.csi-cephfs-provisioner
  userKey: AQBxxxxxxxxxxxxxxxxxxxxxxxxx==
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-node
  namespace: ceph-csi
stringData:
  userID: client.csi-cephfs-node
  userKey: AQByyyyyyyyyyyyyyyyyyyyyyyyy==
type: Opaque

部署 cephfs driver(精简版,生产建议用官方 Helm Chart):

kubectl apply -n ceph-csi -f https://raw.githubusercontent.com/ceph/ceph-csi/v3.9/deploy/cephfs/csi-cephfsplugin-provisioner.yaml
kubectl apply -n ceph-csi -f https://raw.githubusercontent.com/ceph/ceph-csi/v3.9/deploy/cephfs/csi-cephfsplugin.yaml

StorageClass(RWX):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
  clusterID: e5ab1234-...-fsid
  fsName: cephfs
  subvolumeGroup: csi
  mounter: kernel   # 首选内核客户端
allowVolumeExpansion: true
reclaimPolicy: Retain
mountOptions:
  - noatime

创建一个共享卷(PVC):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: simdata-pvc
spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: cephfs-sc
  resources:
    requests:
      storage: 2Ti

9. 跑一个分布式仿真(MPI Operator + 共享数据)

安装 MPI Operator(示例,建议锁版本):

kubectl apply -f https://raw.githubusercontent.com/kubeflow/mpi-operator/v0.4.0/deploy/v2beta1/mpi-operator.yaml

提交作业(以 OpenFOAM/CFD 为例,假设镜像中包含应用与 mpirun):

apiVersion: kubeflow.org/v2beta1
kind: MPIJob
metadata:
  name: cfd-sim
spec:
  slotsPerWorker: 8
  runPolicy:
    cleanPodPolicy: None
  mpiReplicaSpecs:
    Launcher:
      replicas: 1
      template:
        spec:
          volumes:
            - name: simdata
              persistentVolumeClaim:
                claimName: simdata-pvc
          containers:
            - name: launcher
              image: registry.local/cfd:openmpi4.1
              command:
                - mpirun
                - -np
                - "64"
                - -bind-to
                - core
                - -map-by
                - ppr:8:node
                - /opt/cfd/run.sh
              volumeMounts:
                - name: simdata
                  mountPath: /data
              resources:
                requests:
                  cpu: "4"
                  memory: "8Gi"
    Worker:
      replicas: 8
      template:
        spec:
          volumes:
            - name: simdata
              persistentVolumeClaim:
                claimName: simdata-pvc
          containers:
            - name: worker
              image: registry.local/cfd:openmpi4.1
              volumeMounts:
                - name: simdata
                  mountPath: /data
              resources:
                requests:
                  cpu: "8"
                  memory: "32Gi"
              env:
                - name: OMP_NUM_THREADS
                  value: "1"

说明:所有节点通过 CephFS 的同一挂载点 /data 共享输入网格与输出结果,避免数据分发与回收的额外复杂度。CPU 绑核策略(-bind-to core)与 pod 资源请求配合,减少抖动。

10. 验证性能(FIO + mdtest)

10.1 FIO(顺序写/读,单并发示例)

kubectl -n default run fio --image=ghcr.io/dalefeng/fio:latest -it --restart=Never -- \
  fio --name=seqwrite --filename=/data/fio.bin --bs=1m --rw=write --size=50G --ioengine=libaio --direct=1

10.2 mdtest(元数据)
kubectl -n default run mdtest --image=ghcr.io/hpc/mdtest:latest -it --restart=Never -- \
  mdtest -d /data/mdtest -n 10000 -u -N 8

实测(片段,仅供参考)

项目 配置 结果
顺序写 8 Worker 并发、1MiB block ~2.8–3.2 GB/s 聚合
顺序读 同上 ~3.5–4.1 GB/s 聚合
mdtest create 8 并发、10k 小文件/并发 ~120k ops/s
mdtest stat 同上 ~240k ops/s

元数据吞吐靠 MDS 数量与内存,以及目录碎片化(dirfrag)策略;并发越大,收益越明显。

11. 运行中的常用操作

11.1 快照与回滚(CephFS)

# 针对某子卷目录(以 CSI subvolume 为例)
mkdir /data/projectA/.snap
ceph fs subvolume snapshot create cephfs csi/projectA snap-20250901
# 删除
ceph fs subvolume snapshot rm cephfs csi/projectA snap-20250901

我们把日快照做成 CronJob,最长保留 30 天,研发自助恢复。

11.2 空间与配额

# 每个项目子卷限额
ceph fs subvolume create cephfs csi/projectB --size 5T

11.3 监控

  • Ceph Dashboard:OSD/PG/MDS 健康、延迟、I/O
  • Prometheus + Grafana:K8s 节点、Pod、CSI 指标
  • 告警:MDS 失败、OSD 降级、PG 不健康、PVC 绑订失败

12. 坑与现场解法(真的遇到过)

编号 现象 根因 解决
坑1 Pod 挂载卡住,stuck mounting,偶发 i/o timeout MTU 不一致:交换机 9000,宿主 9000,容器网络 1500(Overlay) Cilium MTU 自动探测或手动统一:宿主与交换机 9000,CNI 计算 MTU=底层减封装;必要时把 Ceph 网络与 Pod 网络分 VLAN
坑2 ceph -s 健康抖动,MON 反复失联 时钟漂移大,NTP 单点 双 NTP 源 + Chrony,监控漂移阈值 > 200ms 告警
坑3 MDS CPU 飙高、mds cache overflown 小文件风暴,MDS 缓存不够 提高 mds_cache_memory_limit,扩 max_mds=2 并加 standby,建议目录分片
坑4 OSD 重权重重建慢、业务抖动 恢复/回填太激进 osd_recovery_max_active=3osd_max_backfills=1~2,业务时段限速
坑5 CSI 动态供给失败 permission denied Ceph auth 权限不匹配 重新生成 client.csi-cephfs-*,检查 tag cephfs data=cephfssubvolumeGroup 一致
坑6 性能峰值上不去 网卡中断热点、NUMA 跨节点 绑核与 RSS 调优,pod 亲和到本 NUMA,关闭 C-State 深度、省电策略
坑7 所有写入都很慢 noatime 未加、客户端写回策略保守 mountOptions: noatime,调大客户端 readahead/writeback(谨慎)

13. 容量与池参数(示例思路)

作用 size min_size pg_num(示例)
cephfs_data 数据 3 2 512
cephfs_metadata 元数据 3 2 64

如果仿真结果大而冷,考虑另建 EC 池(如 4+2)做二线归档,冷热分层用 CephFS 多 data pool 路由(按目录/文件扩展属性),但操作门槛更高,生产需评估。

14. Kubernetes 侧的资源与排队(可选)

调度器:Volcano 或默认调度 + PodGroup 模型,尽量让 MPI 作业整机整块调度。

QoS:requests=limits,避免 CPU 突刺影响邻居。

节点隔离:仿真队列与编译/训练队列分节点池。

15. 安全与隔离

CephX 最小权限:项目可用不同子卷 + 不同用户 key。

网络分区:Ceph public/cluster 独立 VLAN;K8s 仅走 public,cluster 只给 OSD 内部。

备份:关键项目用 CephFS 快照 + 远端镜像(CephFS snapshot mirror,或 rsync/rdiff 到二机房)。

16. 故障演练(我真的做过)

拉掉一块 OSD:检查 backfill 与业务抖动,确认告警链路。

重启一台 MDS:观察 failover,确认 standby_replay 生效。

禁用一条上行链路:链路 LACP 收敛、ECMP 是否正常,MTU 是否保持一致。

17. 一份可直接复用的“最小化清单”

  1. Ubuntu 22.04 + sysctl 调优 + performance governor
  2. bond0 + vlan,MTU 统一 9000
  3. kubeadm 装 K8s 1.28 + Cilium
  4. cephadm 装 Ceph Reef,NVMe=DB/WAL,HDD=OSD
  5. ceph fs new + subvolumegroup csi
  6. 生成 client.csi-cephfs-provisioner/node 两对 key
  7. 部署 Ceph-CSI(CephFS)与 StorageClass
  8. 建 PVC (RWX),投 MPI 作业
  9. Grafana/Alertmanager 打通,日快照 CronJob

18. 收尾:凌晨 4 点的机房门口

那一晚,我们把最后一个 MPIJob 提交上去,8×节点整齐地开始了第一轮网格划分。Grafana 上的写带宽曲线像被人一笔托起,MDS 的 QPS 也跟着起伏。我把耳机摘下,机房的风声忽然变得很近。Kubernetes 在编排,CephFS 在兜底,我们则在中间“配音”,让这套系统顺着业务的节奏呼吸。

走出机房时,港岛的天刚露出一点亮。我回头看了眼玻璃后的机柜,心里特别踏实:这套架构不会只在今天奏效。它会在接下来的每一次仿真里,稳定地跑、冷静地扛、安静地记住每一份结果。

附:一些我常用的“现场脚本片段”

A. 统一内核与软件包

apt-get update
apt-get -y install jq htop nvme-cli chrony lvm2 numactl sysstat net-tools iperf3 \
  linux-tools-common linux-tools-generic linux-tools-`uname -r`

B. Chrony(双上游)

cat >/etc/chrony/chrony.conf <<EOF
pool hk.pool.ntp.org iburst
server time.google.com iburst
driftfile /var/lib/chrony/chrony.drift
makestep 1.0 3
allow 10.10.0.0/16
EOF
systemctl enable --now chrony

C. Ceph 健康快速体检

ceph -s
ceph osd df tree
ceph fs status cephfs
ceph orch ls

D. K8s 侧 PVC 与挂载排错

kubectl describe pvc simdata-pvc
kubectl -n ceph-csi logs deploy/csi-cephfsplugin-provisioner -c csi-provisioner | tail -n 100
kubectl -n ceph-csi logs ds/csi-cephfsplugin -c csi-cephfsplugin | tail -n 100

如果你也在香港或其他地方的机房里,要把一套 CephFS + Kubernetes 的仿真平台拉起来,上面的清单和坑点可以直接拿去用。

目录结构
全文