1. 项目概述:基于裸金属环境的RKE2 Kubernetes集群MLOps平台构建

在当今数据驱动的业务环境中,机器学习模型的工业化部署已成为企业数字化转型的核心挑战。我们最近在裸金属服务器上基于Rancher RKE2 Kubernetes集群成功部署了完整的MLOps平台,实现了从模型开发到生产部署的全生命周期管理。这种架构特别适合对数据隐私要求严格、需要最大化硬件利用率的场景,相比云环境可降低30%以上的长期运营成本。

裸金属环境意味着我们直接操作物理服务器而非虚拟机,这带来了性能优势(避免了虚拟化层开销),但也面临硬件兼容性、驱动管理等独特挑战。选择RKE2作为Kubernetes发行版,主要看中其同时满足轻量化和企业级需求的特点——它继承了RKE的易用性,又增加了FIPS合规、自动证书轮换等生产级功能,特别适合需要长期稳定运行的ML工作负载。

2. 核心架构设计解析

2.1 硬件资源配置方案

我们的裸金属集群由6台Dell PowerEdge R740组成,具体配置如下:

角色 CPU 内存 存储方案 网络配置
控制平面节点 2×Xeon 6248R 256GB 2×480GB SSD (RAID1) 2×25Gbps SFP28 (LACP)
Worker节点 2×Xeon 6348 512GB 4×1.92TB NVMe (JBOD模式) 2×25Gbps + 1×100Gbps
GPU节点 2×Xeon 8360Y 1TB 4×3.84TB NVMe + 8×A100 80GB 2×100Gbps (RDMA支持)

关键经验:在裸金属环境中,建议为Kubernetes控制平面预留至少15%的CPU和内存余量。我们曾因资源超额分配导致etcd性能下降,表现为API响应延迟超过500ms,通过增加控制节点数量到3个并限制工作负载调度得以解决。

2.2 RKE2集群部署要点

安装RKE2时需特别注意裸金属环境的以下配置:

# 主节点安装配置示例(/etc/rancher/rke2/config.yaml)
token: "自定义安全令牌"
tls-san:
  - "mlops-cluster.example.com"
node-taint:
  - "CriticalAddonsOnly=true:NoExecute"
kubelet-arg:
  - "max-pods=150"
  - "kube-reserved=cpu=2,memory=8Gi"
cni: "cilium"
disable:
  - "rke2-ingress-nginx"

安装后需手动配置硬件相关组件:

  1. 加载SR-IOV驱动以实现网络加速:
    modprobe -a ib_core mlx5_core
    echo "options mlx5_core log_debug=1" > /etc/modprobe.d/mlx5.conf
    
  2. 配置GPU节点的NVIDIA容器运行时: nvidia-container-runtime config --runtime=containerd > /etc/nvidia-container-runtime/config.toml

2.3 MLOps平台组件选型

我们采用模块化架构设计,核心组件矩阵如下:

功能领域 选择方案 关键考量因素
流水线编排 Kubeflow Pipelines v2 原生K8s集成,支持递归执行
特征存储 Feast 0.19 离线/在线一致性,支持BigQuery连接器
模型注册 MLflow 1.28 多框架支持,实验对比功能完善
服务部署 Seldon Core 1.13 灰度发布、AB测试路由配置灵活
监控告警 Prometheus-Operator + Grafana 与K8s监控体系无缝集成
日志管理 Loki + Promtail 轻量级,适合高频ML日志

3. 关键实现细节

3.1 持久化存储方案优化

裸金属环境无法使用云厂商的存储类,我们通过以下组合解决存储需求:

  1. 高性能存储 :为训练作业配置Local Path Provisioner,直接挂载NVMe盘

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-nvme
    provisioner: rancher.io/local-path
    volumeBindingMode: WaitForFirstConsumer
    reclaimPolicy: Retain
    
  2. 共享存储 :使用Rook Ceph集群提供S3兼容对象存储

    # Ceph集群性能调优参数(部分)
    osd_memory_target = 8GB
    bluestore_cache_autotune = true
    osd_op_num_threads_per_shard = 4
    
  3. 关键配置 :在Kubeflow中设置默认存储类

    from kfp.dsl import PipelineVolume
    def pipeline():
        shared_vol = PipelineVolume(
            name="workspace",
            volume_claim_template=V1PersistentVolumeClaimTemplate(
                spec=V1PersistentVolumeClaimSpec(
                    storage_class_name="local-nvme",
                    access_modes=["ReadWriteOnce"],
                    resources=V1ResourceRequirements(
                        requests={"storage": "100Gi"}
                    )
                )
            )
        )
    

3.2 网络性能调优

裸金属网络的低延迟特性需要特别配置才能充分发挥:

  1. 启用Multus CNI实现多网卡支持

    apiVersion: k8s.cni.cncf.io/v1
    kind: NetworkAttachmentDefinition
    metadata:
      name: rdma-net
    spec:
      config: '{
        "cniVersion": "0.3.1",
        "type": "macvlan",
        "master": "ens786f1",
        "mode": "bridge",
        "ipam": {
          "type": "whereabouts",
          "range": "192.168.100.0/24"
        }
      }'
    
  2. 训练任务Pod注解示例

    annotations:
      k8s.v1.cni.cncf.io/networks: rdma-net
      sriov.network/trusted: "true"
    resources:
      limits:
        rdma/rdma_shared_device_a: 1
    

3.3 GPU资源管理实践

在共享GPU集群中实现公平调度:

  1. 配置GPU时间切片 (适用于小模型推理):

    nvidia-ctk runtime configure --set-default-runtime=nvidia --time-slicing-config=time-slicing.yaml
    

    time-slicing.yaml内容:

    devices:
      - name: nvidia.com/gpu
        replicas: 4  # 将单卡虚拟为4个设备
    
  2. 使用GPU拓扑感知调度 (适用于分布式训练):

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: gpu-topology-job
    spec:
      template:
        spec:
          containers:
          - name: trainer
            resources:
              limits:
                nvidia.com/gpu: 4
          nodeSelector:
            nvidia.com/gpu.topology: nvlink  # 优先选择NVLink互连的GPU
    

4. 运维监控体系构建

4.1 定制化监控指标采集

除常规K8s监控外,我们增加了ML特有的监控维度:

  1. 模型服务指标 (通过Seldon Analytics采集):

    from seldon_core.user_model import SeldonResponse
    from prometheus_client import Counter
    
    REQ_COUNTER = Counter('model_calls_total', 'Total model API calls')
    
    class MyModel:
        def predict(self, X):
            REQ_COUNTER.inc()
            return SeldonResponse(data=X*2)
    
  2. GPU利用率告警规则

    - alert: GPUOverutilization
      expr: avg(rate(DCGM_FI_DEV_GPU_UTIL[1m])) by (pod, gpu) > 90
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "GPU {{ $labels.gpu }} in pod {{ $labels.pod }} overutilized"
    

4.2 日志收集优化方案

针对ML任务日志量大的特点,我们调整了Loki的配置:

# values.yaml 部分配置
loki:
  config:
    limits_config:
      ingestion_rate_mb: 50
      ingestion_burst_size_mb: 100
    chunk_store_config:
      max_look_back_period: 240h
  persistence:
    size: 500Gi

同时为不同组件设置日志级别:

  • 训练任务:INFO级别
  • 模型服务:WARNING级别
  • 数据流水线:DEBUG级别(仅在故障排查时开启)

5. 典型问题排查实录

5.1 OOMKilled问题深度分析

现象:模型训练Pod频繁被终止,Exit Code 137

排查步骤:

  1. 检查Pod描述中的Last State:
    kubectl describe pod/training-pod-xyz -n kubeflow
    
  2. 确认是内存不足导致(OOMKilled)
  3. 分析内存增长模式:
    kubectl top pod/training-pod-xyz --containers
    
  4. 最终发现是Pandas读取CSV时未指定dtype导致内存膨胀

解决方案:

# 优化前
df = pd.read_csv("large_dataset.csv")

# 优化后
dtypes = {
    "user_id": "int32",
    "value": "float32"
}
df = pd.read_csv("large_dataset.csv", dtype=dtypes)

5.2 GPU设备插件常见故障

现象:nvidia.com/gpu资源不可见

诊断流程:

  1. 检查设备插件Pod日志:
    kubectl logs -n kube-system ds/nvidia-device-plugin-daemonset
    
  2. 验证节点驱动状态:
    nvidia-smi -q | grep "Driver Version"
    
  3. 常见修复方法:
    • 重新加载nvidia-uvm内核模块
    • 重启containerd时指定--gpu选项
    • 更新DCGM exporter配置

5.3 分布式训练通信瓶颈

现象:多节点训练速度不随GPU数量线性增长

性能分析工具链:

  1. 使用PyTorch内置分析器:
    with torch.profiler.profile(
        activities=[torch.profiler.ProfilerActivity.CPU,
                   torch.profiler.ProfilerActivity.CUDA],
        schedule=torch.profiler.schedule(wait=1, warmup=1, active=3)
    ) as prof:
        for step in range(10):
            train_step()
            prof.step()
    print(prof.key_averages().table())
    
  2. 检查NCCL调试信息:
    NCCL_DEBUG=INFO python train.py
    
  3. 优化方案:
    • 设置NCCL_ALGO=Tree避免星型通信
    • 增加NCCL_NSOCKS_PERTHREAD=4
    • 使用GPUDirect RDMA加速跨节点通信

6. 安全加固实践

6.1 镜像扫描策略

在CI流水线中集成Trivy扫描:

# .gitlab-ci.yml 示例
scan-image:
  stage: test
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  script:
    - trivy image --exit-code 1 --severity CRITICAL ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

6.2 网络策略配置

限制MLflow服务访问范围:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mlflow-allow-only-from-internal
spec:
  podSelector:
    matchLabels:
      app: mlflow-server
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kubeflow
    ports:
    - protocol: TCP
      port: 5000

6.3 认证集成方案

将Kubeflow与公司LDAP对接:

# Dex配置片段
connectors:
- type: ldap
  id: corporate-ldap
  name: Corporate LDAP
  config:
    host: ldap.corp.example.com:636
    insecureNoSSL: false
    bindDN: "cn=kubeflow-bind,ou=services,dc=corp,dc=example,dc=com"
    bindPW: "$LDAP_BIND_PASSWORD"
    userSearch:
      baseDN: "ou=people,dc=corp,dc=example,dc=com"
      filter: "(objectClass=person)"
      username: "mail"
      idAttr: "uid"
      emailAttr: "mail"

经过半年生产环境运行,该平台已稳定支持以下工作负载:

  • 日均执行训练任务120+次
  • 同时在线模型服务80+个
  • 特征仓库存储量达15TB
  • 最复杂流水线包含217个步骤

关键性能指标:

  • 模型部署时间从小时级缩短至<3分钟
  • GPU平均利用率从35%提升至68%
  • 推理服务P99延迟稳定在50ms以内

更多推荐