去年我们接到一个挺现实的活儿:公司算法团队打算把一批大模型训练任务从自建的小集群迁到统一的云平台上。起初大家的想法很朴素——搞几台带GPU的服务器,装个Kubernetes,把PyTorch任务以Pod方式扔上去,不就完事了吗。直到第一批训练任务真的跑起来,NCCL超时、GPU显存碎片、镜像拉取风暴接连炸出来,我们才意识到,AI云基础架构和传统云平台根本是两种生物。这篇文章想把这一路从踩坑到落地的心得整理出来,聊聊AI云基础架构到底该怎么理解、怎么设计、怎么真正跑起来。面向的是正在搭建或打算搭建AI算力平台的研发、运维和架构师,也适合想搞清楚“云上跑大模型和跑Web服务到底哪里不同”的读者。
1. AI工作负载和传统云计算差在哪:先把“为什么”想清楚
很多人把AI云简单理解成“有GPU的云服务器”,这个认知会害死人。我在给团队做架构宣讲时经常用一张对比表格开场,把两类工作负载摆在一起看,差异立刻就很明显。
| 维度 | 传统Web/微服务负载 | AI训练/推理负载 |
|---|---|---|
| 任务形态 | 无状态、短请求、可水平扩展 | 长任务、有状态、强依赖GPU亲和性 |
| 核心资源 | CPU、内存、网络带宽 | GPU、显存、GPU间通信带宽 |
| 通信模式 | 南北向流量为主,外部请求进入 | 东西向流量为主,节点间梯度同步 |
| 数据访问 | 数据库、缓存、小文件 | 大文件数据集、Checkpoint、共享文件系统 |
| 失败容忍度 | 重启实例即可,无状态恢复 | 训练中断几小时,代价极高 |
| 调度需求 | 负载均衡、资源充足即可 | 批量调度、显存拓扑、避免碎片 |
这张表背后藏着一个容易被忽略的事实:传统云平台的核心抽象是“无状态实例”,你随时可以杀掉一个再拉起一个新的,数据在数据库里、会话在Redis里,实例本身可以随意替换。但AI训练任务不是这样,它天生是“有状态的”。
1.1 传统云是“无状态微服务”的游戏规则
云平台最早的成熟范式,是为Web服务、微服务、中间件这类负载设计的。它们的核心特点是无状态或者弱状态:请求来了处理一下,处理完就返回,数据持久化交给数据库。就算一个Pod挂了,副本控制器很快拉起一个新Pod,对外几乎没有感知。
所以传统云平台的调度器、网络模型、存储模型都在围绕“快速创建、随时销毁、水平伸缩”这三个关键词做优化。Kubernetes的默认调度器也是这么设计的——看资源够不够、看亲和性约束、选个最合适的节点,完事。
1.2 AI训练任务的三把枷锁:GPU亲和性、长稳运行、海量中间数据
到了AI负载这里,游戏规则全变了。
第一把枷锁是GPU亲和性。多卡训练任务不只要“有GPU”,还要“GPU之间通信快”。同一节点上的多张卡可以通过NVLink直连,带宽能到几百GB/s;跨节点就得走网卡,就算InfiniBand也只有几十GB/s。所以调度器必须知道任务的拓扑需求,尽量把同一个分布式训练任务的多个Pod调度到同一节点,或者至少保证它们所在的节点之间网络路径是短而稳的。
第二把枷锁是长稳运行。大模型预训练任务动辄跑几天甚至几周,中途哪怕只崩溃一次,光加载Checkpoint恢复状态就要花不少时间。更麻烦的是,很多分布式训练框架在某个节点故障时,整个任务都会卡住等待,如果调度系统不能及时处理,团队的人力和算力就同时浪费了。
第三把枷锁是海量中间数据。一个训练任务会持续读取数据集、周期性地写Checkpoint、保存日志和评估结果。一套LLaMA级别的训练,光Checkpoint可能就有几十GB到数TB。这些数据必须放在所有训练节点都能访问的共享存储上,同时还要保证高吞吐、低延迟,不能让训练流程卡在等数据上。
这三把锁决定了AI云基础架构不能直接照搬传统云那套方案,必须从硬件规划、调度系统到存储网络做一套专门的设计。这也是为什么很多公司明明已经有了Kubernetes集群,还非要单独搭一套AI计算平台——不是折腾,是被逼的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 硬件底座规划:GPU集群、存储和网络的选型逻辑
聊完了“为什么”,接下来是最实际的问题:硬件底子到底怎么搭。很多人上来就纠结“买A100还是H100”,但真正搞过AI云的人都知道,硬件选型从来不是单点选卡,而是算力、网络、存储三个维度一起决定。
2.1 算力层:GPU选型与异构管理的现实问题
GPU选型首先要分清场景。我的建议是至少分成三档:
- 预训练/大规模微调:追求高显存、高算力、强互联,H100、A100这类带NVLink和数据中心级设计的卡是主力。它们的显存通常在40GB到80GB,适合跑大Batch Size和模型并行。
- 常规微调/推理:L40S、A10、或者高配消费卡都可行。关键是看你对显存和精度(FP16/BF16/FP8)的要求。
- 推理服务:更看重延迟和吞吐,A10、T4这类卡有时候反而比旗舰卡更划算,因为推理瓶颈往往在显存带宽而非绝对算力。
但选卡只是一个开头,我在实际项目里吃过更大的亏:异构混用。有一阵子我们把一批A100和一批旧款卡混在一个资源池里,结果算法同事在代码里指定了某种CUDA能力版本,任务调度到了旧卡上直接崩。更隐蔽的是,如果一台物理机里插了不同代际的卡,NCCL初始化经常会出现莫名其妙的拓扑识别问题。
所以我的建议很直接:不同型号、不同代际的GPU尽量拆成独立的资源池,用标签或独立的NodePool隔离。调度器保证任务只落在同一型号的节点上。宁可让一部分卡闲置,也不要为了利用率把兼容性风险引进来。
2.2 网络层:梯度同步没你想象的那么轻松,IB还是RoCE?
很多人搭GPU集群时,网络方案是到最后才考虑的,这是个大坑。分布式训练每一轮迭代都要做梯度同步,也就是通过AllReduce操作把各个GPU上的梯度合并起来。模型越大,需要同步的数据量越大,对网络的要求也越苛刻。
目前主流的两个方向是InfiniBand和RoCE(RDMA over Converged Ethernet),各有各的适用场景。
| 对比项 | InfiniBand | RoCE |
|---|---|---|
| 性能 | 极高,确定性好 | 高,依赖无损网络配置 |
| 成本 | 贵,交换机和网卡都贵 | 相对便宜,复用以太网 |
| 生态 | NVIDIA原生支持完善 | 需要精细调优(PFC/ECN) |
| 典型场景 | 大模型预训练、HPC | 中小规模训练、推理集群 |
如果你的预算够、而且明确要长期做大模型预训练,直接上InfiniBand,省心省力。如果预算有限,RoCE也能用,但前提是必须把网络调好,我后面会专门讲我们踩到的RoCE坑。
不管选哪种,有几个基础参数都是必须设置的:MTU要开到9000(巨型帧),RoCE场景下必须开启PFC(优先级流控)和ECN(显式拥塞通知),还要给分布式训练流量划分独立的VLAN或优先队列,避免和业务流量抢带宽。这些配置不做,训练任务就会像堵车一样,时快时慢,最终表现为NCCL超时。
2.3 存储层:共享文件系统是第一个必踩的坑
AI训练的数据读取和Checkpoint保存,决定了你几乎不可能用纯粹的本机磁盘来支撑分布式任务。多机多卡训练时,每个GPU都要读取同一份数据集,每过一段时间所有节点都要同时写Checkpoint到同一个位置。没有共享文件系统,这个流程根本走不通。
存储方案的层次大概是这样的:
- 本地NVMe盘:只用来放操作系统、临时文件和镜像缓存,不承担训练数据共享。
- 并行文件系统(Lustre、GPFS):性能猛,支撑大规模并发读写没问题,但部署运维复杂度高,适合团队有专门存储工程师的情况。
- 分布式文件系统(JuiceFS、CephFS / GlusterFS):可用性和扩展性不错,中小规模训练的性价比很高。JuiceFS这类还能把数据放在对象存储上,训练节点本地缓存热点数据,成本控制上有优势。
我们的做法是训练数据集和中间产物放JuiceFS,Checkpoint的高频写入走并行文件系统,通过这种组合兼顾性能和成本。千万别用传统NFS跑几十上百GB的模型训练,NFS的元数据性能扛不住几万个小文件的并发访问,你会被卡到怀疑人生。
3. 资源池化与调度设计:Kubernetes之上的AI专用层
硬件底座弄好了,接下来就是让这些算力能被高效调度。这一步的关键是:为什么原生Kubernetes调度器管不了GPU任务,以及要怎么给它加装上AI专用能力。
3.1 为什么原生K8s调度器管不了GPU任务
Kubernetes默认调度器的逻辑,是找一个“满足资源请求”的节点把Pod放下去。它考虑的是CPU、内存、GPU数量这些标量资源,但完全不理解“一个训练任务的一组Pod必须同时启动”这件事。
举个例子:一个分布式训练任务有8个Worker,每个Worker需要4张GPU。调度器一个一个地往下放,结果集群里当时只有7个Worker的GPU是够的,第8个没有资源。这时候前7个Pod如果被启动了,它们会拿着GPU资源空等,第8个永远起不来——这就是死锁。而且在等待期间这些GPU被白白占住,其他任务也进不来。
AI领域的标准解法是Gang调度,也就是“All or Nothing”的批量调度:要么一组Pod全部满足资源条件,要么一个都不调度。原生K8s调度器不干这事,需要专门的调度组件。
3.2 调度器增强:Volcano / Kueue / 自研队列的选择
我调研过很多组合,目前生产环境里比较稳的搭配是:底层Kubernetes + Volcano提供Gang调度和队列能力,Kueue负责配额管理和排队,KubeFlow Training Operator负责管理PyTorch/TensorFlow训练任务的编排。
- Volcano(KubeBatch)是目前社区最常用的AI调度器,支持Gang调度、队列、优先级、抢占。它的核心概念是Queue和PodGroup,你提交一组Pod时把它们归为一个PodGroup,调度器会一次性判断整组资源是否满足。
- Kueue是近几年发展很快的云原生作业排队系统。它管的是“谁先用资源池”的排队逻辑,结合ClusterQueue和LocalQueue,可以给不同团队设置配额、优先级和排队时间。
- KubeFlow Training Operator则把训练任务抽象成PyTorchJob、TFJob这样的CRD,你不再需要手工管理一堆Pod,只需提交一个PyTorchJob对象。
这种组合的好处是各司其职:Volcano管“一格一格往下放”,Kueue管“先来后到和配额”,Training Operator管“任务生命周期”。三个组件咬合起来,比自研一套调度器省心得多。
Volcano队列配置大概是这个意思:
yaml复制apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
name: training-queue
spec:
weight: 10
capability:
nvidia.com/gpu: "128"
把一个训练任务声明为PodGroup,指定队列和minMember(需要的最少Pod数),调度器就会按Gang调度逻辑处理。
3.3 GPU资源切分:从MIG到显存隔离的几种做法
GPU资源池化还有一个绕不开的痛点:显存怎么切。
训练大模型时,单卡整卡最省心,显存大、性能稳。但推理服务或者小模型调参任务,常常用不满整张卡,把整卡分配过去就等于浪费。这时候需要GPU资源切分。
NVIDIA官方的方案是MIG(Multi-Instance GPU),能在A100/H100上把一张卡切成多个独立的GPU实例,每个实例有独立的显存和计算单元,隔离性很好。适合推理服务和小型训练任务。但它有两个限制,一是只有部分数据中心级GPU支持,二是切分粒度是固定的,不是你想切多细就切多细。
另一个思路是vGPU方案,把一张物理卡通过虚拟化技术切给多个虚拟机或容器用,灵活度高,但引入的软件层会增加性能损失和运维复杂度,一般中小团队不建议一上来就上。
除了硬切分,还有时间片方案,让多个任务分时复用一张GPU。成本低,但任务之间的性能干扰明显,不适合对训练时间敏感的生产任务。
我的建议是:预训练和重要微调任务一律整卡;推理和小任务用MIG切分;时间片只给那些低优先级的实验任务。把资源切分的粒度做细,集群利用率能提升不少,但也别为了利用率把关键任务的稳定性搭进去。
4. 构建一个可运行的AI云最小闭环:从裸机到首个训练任务
架构聊得再多,最后都要落到“能不能跑起来”。这一节我不讲太高级的东西,就把从裸机到第一个分布式训练任务跑通需要经过的步骤完整捋一遍。这套流程我们内部复用了很多次,基本可以当成AI云的新节点上线手册。
4.1 环境初始化:驱动、容器运行时和GPU Operator
GPU节点的基础环境初始化,传统做法是手动装驱动、配NVIDIA Container Toolkit、再部署Device Plugin。这套流程繁琐且容易出错,尤其是驱动版本跟CUDA版本不匹配的时候。
现在推荐直接用NVIDIA GPU Operator,它会自动处理驱动安装、容器运行时配置、Device Plugin部署和DCGM监控组件。用Helm一键部署之后,节点上的GPU资源就能被Kubernetes自动发现了。
提示:部署GPU Operator之前,确认节点内核版本和驱动版本兼容。踩过最痛的坑是升级内核后重启,NVIDIA驱动模块没重新编译,节点直接失去GPU能力,排查了半天才发现是驱动和内核版本脱节。
驱动就绪后,验证一下GPU资源是否上报:
bash复制kubectl get nodes -o json | jq '.items[].status.allocatable'
能看到nvidia.com/gpu这个键,说明Device Plugin工作正常。
4.2 镜像与训练框架:PyTorch镜像的标准化
镜像标准化是很多团队忽略的环节。算法工程师习惯直接在容器里pip install,这在开发环境没问题,但上了平台就要统一管理镜像,否则每次提交任务都在装依赖,慢而且不可复现。
我们的做法是做一个基础镜像,把常用的CUDA版本、PyTorch版本、分布式训练依赖(如NCCL库、horovod、deepspeed)和监控代理(比如DCGM exporter的sidecar)都打进去。算法同学在此基础上再封装自己的代码,基础镜像由平台团队维护,有安全更新时统一升级。
一个简单的镜像Dockerfile示意:
dockerfile复制FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-devel
RUN apt-get update && apt-get install -y \
vim \
curl \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir \
deepspeed==0.13.1 \
transformers==4.38.2 \
accelerate==0.27.2
COPY train.py /workspace/train.py
WORKDIR /workspace
镜像里的依赖版本最好锁定,避免过几天跑出来结果对不上。
4.3 提交第一个分布式训练任务并验证
环境就绪后,用PyTorchJob提一个简单的双机训练任务,验证两个关键点:GPU能否被正确分配,节点间的NCCL通信是否正常。
Python 启动脚本示意:
python复制import torch
import torch.distributed as dist
dist.init_process_group(backend="nccl")
local_rank = int(os.environ["LOCAL_RANK"])
device = torch.device("cuda", local_rank)
tensor = torch.ones(1024, 1024, device=device)
dist.all_reduce(tensor, op=dist.ReduceOp.SUM)
print(f"Rank {dist.get_rank()} all_reduce done, sum={tensor.sum().item()}")
提交PyTorchJob后,需要检查几件事:
- 所有Pod是否从Pending转为Running,有没有长时间Pending。如果卡在Pending,多半是Volcano的Gang调度条件不满足或配额不够。
- 查看训练日志里的
Rank X all_reduce done字样。如果能看到所有Rank都打印了这行,说明NCCL通信正常。 - 看DCGM监控,确认GPU利用率、显存占用确实上来了,而不是Pod在跑但GPU空转。
bash复制kubectl get pytorchjob -n training
kubectl logs -f pytorchjob-trainer-worker-0 -n training
第一个任务跑通,基本就算完成AI云的最小闭环了。但这时候只是起点,真正折磨人的是后面集群规模上来之后的各种问题。
5. 真实踩坑记录:集群跑起来之后最折磨人的三个问题
很多AI云项目死在不是“搭不起来”,而是“用起来之后三天两头出问题”。这一节我把我们在生产环境里真正踩过的三个大坑整理出来,每个都带完整的排查链路,希望能给大家省几个通宵。
5.1 镜像拉取风暴:大镜像让节点全都挂起
现象:集群新接入一批节点后,调度了一堆训练任务,结果节点陆续进入NotReady状态,Pod长时间Pending。
排查链路:先看节点状态,发现磁盘压力指标(Pressure)告警。接着用iostat看磁盘I/O,发现写等待(w_await)高得吓人。再看Kubelet日志,发现大量镜像解压失败和超时。
根因:AI训练镜像动辄十几GB,而且很多任务用的是同一个基础镜像。调度器在短时间内把大量任务分配到新节点,这些节点同时开始拉取和解压大镜像,直接把磁盘I/O打满,导致Kubelet心跳超时,节点被标记NotReady。
解决方式分三层:
- 提前预拉取:新节点上线时,先把常用镜像拉到本地并打上
tag,让节点就绪前就具备运行能力。 - 启用P2P镜像分发:用Dragonfly这类工具,配合镜像仓库做P2P加速,集群内拉包的速度提升好几倍。
- 控制并发拉取:给containerd/Kubelet设置并发拉取的限制,避免几十个Pod同时拉镜像。
这个坑几乎是每个AI云平台的必经之路,早做预拉取规划能省很多事。
5.2 NCCL通信超时:RoCE网络参数调优的血泪史
现象:分布式训练任务跑着跑着随机卡住,日志里出现NCCL timeout,但每次出错的位置不固定,重启后又正常。
排查链路:因为错误是随机出现的,先怀疑网络问题。用ibstat或rdma tool看RDMA端口状态,发现链路虽然是Up,但交换机上的PFC计数器在增长,说明发生了丢包和拥塞。再用netstat -s看TCP重传率,明显偏高。
根因:RoCE网络要求无损传输,但我们当时只开了ECN,PFC的优先级队列配置不对,导致拥塞时没有及时流控,数据包被丢弃,NCCL的同步机制直接超时。
解决方式:
- 重新配置交换机和网卡,正确开启PFC优先级流量控制。
- 调整NCCL环境变量,比如
NCCL_IB_TIMEOUT=22、NCCL_IB_RETRY_CNT=7,增加超时容忍度。 - 给训练流量独立VLAN,跟业务流量隔离,避免被动拥塞。
- 最简单也最有效的辅助手段:把同一训练任务的Pod用节点亲和性约束到同一网络拓扑下,降低跨Spine的概率。
网络参数调优之后,NCCL超时基本消失。这个坑的教训是:RoCE不是说开了RDMA就完事,无损网络是个系统工程,必须把PFC、ECN、缓冲、VLAN全部对齐。
5.3 显存碎片和残留进程:小任务反而把集群搞垮了
现象:集群看起来GPU分配率很高,但真正的大任务经常调度不进去,报“资源不足”。查看时发现有不少Pod已经退出,但GPU显存还被占着。
排查链路:先看Kubelet日志和容器运行时,发现部分任务退出时,GPU进程没有完全清理。用nvidia-smi在节点上查看,能看到一堆僵尸CUDA进程。
根因:一些推理服务或调试容器用了SIGKILL强杀,容器内的CUDA上下文没来得及释放;还有一些任务的resources.requests和limits设置不合理,导致Device Plugin上报的分配数和实际显存占用不一致。
解决方式:
- 给所有训练任务设置明确的
resources.requests和limits,尤其是nvidia.com/gpu,不要默认分配整卡又只用到一小块。 - 写一个巡检脚本,定期检查节点上是否有残留GPU进程,发现就清理。
- 在Pod的
preStop钩子里做优雅退出,让CUDA上下文正常释放。
这个坑提醒我们:GPU资源不能只盯着“分配了多少张卡”,更要看“实际显存和CUDA上下文有没有被正确释放”。AI云上线之后,这类“看不见的资源泄漏”最隐蔽。
6. 多租户、配额与成本治理:AI云上线之后的运维重点
AI云跑起来之后,下一步就是“多人用、多团队用”了。这一步搞不好,平台会变成资源部的噩梦——有人占着GPU不做正事,有人排不上队,月底账单还说不清花了多少。
6.1 配额管理:CPU/内存好设,GPU配额怎么设
多租户配额最基础的是用Kubernetes的ResourceQuota,限制每个Namespace能用的nvidia.com/gpu数量。但AI场景下,单限制GPU数量远远不够。
比如某个团队把数据集放共享存储上,写了大量小文件,直接把文件系统的元数据服务打爆;又比如某个团队忘记清理Checkpoint,把存储空间耗尽。这些都不是GPU配额能管的。
实践中的做法是给每个团队分配一个Namespace,同时设置:
- GPU数量配额:用ResourceQuota限定。
- 存储容量配额:在存储系统层面按目录做容量限制。
- 文件数/操作频率限制:防止单个租户的IO请求把元数据压垮。
6.2 成本可观测:如何把GPU成本分摊到每个业务方
AI云的“钱”主要烧在GPU上。月底财务问GPU花了多少钱、每个团队用掉多少,你不能说不知道。
我们的做法是两套体系并行:
- 资源分配层面的账单:按Namespace和Label统计GPU的申请量和占用时长,用
kube-cost这类工具做成本分摊。 - 实际使用层面的账单:通过DCGM Exporter采集GPU利用率、显存占用、功耗,按Pod维度汇总,算“有效算力消耗”。这能识别出那些“申请了8张卡但利用率只有5%”的浪费。
监控架构是Prometheus + DCGM Exporter + Grafana。DCGM Exporter是NVIDIA官方组件,可以采集GPU利用率、显存、温度、功耗等指标,配合Prometheus做长期存储和告警。这套下来,每个训练任务烧了多少钱、GPU利用率多高,全部一目了然。
6.3 弹性与队列优先级:训练任务排队不是靠K8s默认行为
最后一个运维重点是队列和优先级。Kubernetes默认的调度是先来先服务,但AI云不是这种情况——训练任务有优先级差异,实验任务可以让路给生产任务,低优任务可以抢占空闲GPU。
这部分靠Kueue的ClusterQueue和LocalQueue机制实现。你可以在ClusterQueue里定义不同优先级的队列,比如:
- 高优先级队列:给核心生产任务,配额保留充足,不允许被抢占。
- 普通队列:给常规微调和推理,排队时间长。
- 低优先级队列:给实验和开发任务,可以共享空闲GPU,一旦高优任务需要资源,可以驱逐低优任务腾出GPU。
驱逐低优任务时,要做Graceful Stop,让训练框架有机会保存Checkpoint,不至于白跑几小时。这是我们做可抢占队列时踩过的一个大坑——第一次测试直接强杀任务,训练损失全部丢失,算法同事差点掀桌子。
多租户和成本治理是AI云基础架构里最“运维”的部分,比技术方案更考验团队的管理能力。但这个环节做扎实了,平台才能真正长期稳定运行。
最后再分享一个我个人的体会:AI云基础架构建设,真正的难点不在任何一项单一技术上,而在于把算力、网络、存储、调度、成本这五条线串成一个整体。每一个环节都要为“AI负载的特殊性”做调整,照搬传统云的方案一定会翻车。我做这个项目最大的感受是,不要追求一步到位的完美架构,先搭最小闭环跑通一个真实任务,再顺着踩坑慢慢加能力,稳定性和团队信心都是这样一点点攒出来的。
