去年这个时候,我满怀热情地开始了云原生AI的实践。那时候大模型正火,Kubernetes也越来越普及,把AI工作负载跑在K8s上,听起来是一件很酷、很前沿的事情。
我花了很多时间学习Kubernetes、Kubeflow、分布式训练、模型推理服务,搭建了一套看起来很美的云原生AI平台。但真正用起来的时候,才发现理想和现实之间的差距有多大。
这篇文章就来聊聊我在云原生AI实践中经历的事情,踩过的坑,遇到的困难,以及最终的一些感悟。不是劝退,而是希望大家能更理性地看待云原生AI,少走弯路。
热情开始:为什么要做云原生AI
最开始想做云原生AI,是因为遇到了一些实际问题。
我们团队有几个算法工程师,每个人都有自己的GPU工作站。问题是,GPU资源分配很不均匀。有的人GPU闲着,有的人GPU不够用,要排队等。而且每个人的环境都不一样,这个人用PyTorch 1.13,那个人用PyTorch 2.0,这个人用CUDA 11.7,那个人用CUDA 12.1,模型在这个人的机器上能跑,在那个人的机器上跑不起来。
还有模型部署的问题。算法工程师训练完模型,交给工程师部署,工程师要花很多时间搭环境、写服务代码、配置服务器。模型更新一次,就要重新部署一次,很麻烦。
这时候,云原生AI看起来就是完美的解决方案:
用Kubernetes管理GPU资源,把GPU池化,按需分配,提高利用率。 用容器封装训练和推理环境,保证环境一致性,解决"在我机器上能跑"的问题。 用Kubeflow做机器学习平台,整合数据处理、模型训练、模型部署,实现全流程自动化。 用KServe部署模型服务,自动扩缩容、滚动更新,提升运维效率。
听起来很美,对吧?我也是这么想的。于是我满怀热情地开始了云原生AI的实践。
第一步:搭建Kubernetes集群
第一步是搭建Kubernetes集群。
我以为搭集群很简单,用kubeadm几条命令就搞定了。但真正做起来才发现,坑很多。
第一个坑是GPU节点的配置。Kubernetes默认不支持GPU,需要安装NVIDIA Device Plugin。但安装Device Plugin之前,要先装NVIDIA驱动、CUDA、cuDNN、container-toolkit,版本还要对应,一个版本不对就用不了。我花了整整两天,才把GPU节点配置好,让Kubernetes能识别到GPU。
第二个坑是网络配置。Kubernetes的网络插件有很多,Calico、Flannel、Cilium,各有优缺点。我最开始用了Flannel,简单是简单,但性能不好,分布式训练的时候节点之间通信很慢。后来换成了Calico,性能好了一些,但配置又复杂了很多。
第三个坑是存储配置。AI训练需要大量的存储空间,还要多个节点共享数据。我最开始用了NFS,配置简单,但性能很差,训练的时候读数据很慢,GPU都在等数据,利用率很低。后来换成了Ceph,性能好了一些,但Ceph的配置和运维很复杂,出了问题很难排查。
第四个坑是集群高可用。单节点的控制平面很容易挂,挂了整个集群就用不了。要做高可用,需要至少三个控制平面节点,还要配负载均衡、etcd集群,很复杂。我最开始图省事用了单控制平面,结果有一次控制平面挂了,整个集群的训练任务都停了,花了半天才恢复。
搭集群花了我一周多的时间,踩了无数的坑。那时候我就开始觉得,云原生AI的门槛比我想象的高多了。
第二步:部署Kubeflow
集群搭好之后,下一步是部署Kubeflow。
我以为Kubeflow有官方的部署脚本,照着文档一步步来就行。但真正部署的时候才发现,Kubeflow的部署比我想象的复杂得多。
第一个坑是版本兼容性。Kubeflow对Kubernetes版本有要求,版本不对应就部署失败。我最开始用了最新的Kubernetes 1.29,结果Kubeflow 1.8不支持,降级到Kubernetes 1.27才部署成功。
第二个坑是依赖太多。Kubeflow依赖很多组件,Istio、Knative、Cert Manager、Dex、Argo Workflows,每个组件都要配置,每个组件都可能出问题。部署的时候,一个组件失败,整个部署就失败了,要排查是哪个组件的问题,很麻烦。
第三个坑是资源消耗大。Kubeflow本身就很耗资源,各种组件跑起来,控制平面的内存和CPU就用了不少。我们的集群本来GPU节点就不多,CPU节点也有限,Kubeflow占了很多资源,留给训练任务的资源就更少了。
第四个坑是文档不完善。Kubeflow的文档很多地方写得不清楚,或者过时了,照着文档做会出错。遇到问题只能去GitHub搜issue,去Stack Overflow提问,很多时候找不到答案,要自己摸索。
部署Kubeflow又花了我一周多的时间,中间无数次想放弃。但想着都走到这一步了,放弃太可惜了,还是坚持了下来。
第三步:运行第一个训练任务
Kubeflow部署好之后,我终于可以运行第一个训练任务了。
我写了一个简单的MNIST训练脚本,封装成Docker镜像,用Kubeflow的PyTorch Operator提交了一个分布式训练任务。
然后,问题又来了。
第一个问题是镜像构建。AI训练的镜像很大,动不动几个GB,构建一次要很久,推送也要很久。而且每次改代码都要重新构建镜像,很浪费时间。我最开始每次改代码都重新构建镜像,后来学会了用代码挂载的方式,把代码挂到容器里,不用每次都构建镜像,才快了一些。
第二个问题是数据访问。训练数据存在存储里,容器里怎么访问?我最开始用了PVC挂载,但PVC的权限、路径、性能都有很多问题。数据量大的时候,挂载很慢,读数据也很慢。后来用了对象存储,把数据存在S3兼容的存储里,训练的时候下载到本地,才解决了这个问题。
第三个问题是分布式训练。分布式训练需要多个Pod之间通信,要配置环境变量、网络、端口,很容易出错。我最提交的分布式训练任务,总是有一个Pod连不上其他Pod,排查了很久才发现是网络策略的问题,Istio的sidecar干扰了分布式训练的通信。关掉Istio的sidecar注入之后,才正常运行。
第四个问题是任务调度。Kubernetes的默认调度器不适合AI训练任务,分布式训练需要所有Pod同时启动(Gang Scheduling),默认调度器做不到,会出现有的Pod启动了,有的Pod还在等待,启动了的Pod一直在等其他Pod,浪费资源。后来装了Volcano调度器,支持Gang Scheduling,才解决了这个问题。
第一个训练任务跑通,又花了我好几天的时间。那时候我已经有点疲惫了,但看到任务跑起来,GPU利用率上去了,还是觉得很有成就感。
第四步:模型部署
训练任务跑通之后,下一步是模型部署。
我用KServe部署了一个模型推理服务,以为会很顺利。结果又遇到了很多问题。
第一个问题是推理框架的选择。PyTorch的模型,用什么框架部署?TorchServe、Triton、vLLM、BentoML,各有优缺点,选择困难。我最开始用了TorchServe,配置简单,但性能一般。后来试了Triton,性能好,但配置复杂。大模型推理又要用vLLM,又是一套新的东西。
第二个问题是模型格式转换。不同的推理框架需要不同的模型格式,PyTorch的模型要转成ONNX或者TensorRT,才能在某些框架里用。转换的过程中,经常遇到算子不支持、精度下降等问题,很折腾。
第三个问题是自动扩缩容。KServe支持基于请求量的自动扩缩容,但实际用起来效果不好。流量小的时候缩容到0,第一个请求过来的时候要冷启动,延迟很高。流量大的时候扩容又不及时,请求排队。调了很多参数,效果还是不理想。
第四个问题是GPU资源分配。推理服务用GPU,一个模型占一块GPU,利用率很低。多个模型共享一块GPU又很麻烦,要配置MPS或者vGPU,性能隔离也不好。GPU很贵,这样浪费很心疼。
第五个问题是监控和日志。推理服务的监控很重要,要监控延迟、吞吐量、错误率、GPU利用率。但KServe的监控配置很复杂,要装Prometheus、Grafana,配置各种指标,花了很多时间才搭好。
模型部署又折腾了很久,才勉强能用。那时候我已经开始怀疑,云原生AI是不是真的适合我们的团队规模。
第五步:日常运维
系统搭起来了,任务能跑了,模型能部署了,但日常运维才是噩梦的开始。
第一个问题是集群稳定性。Kubernetes集群本身就需要运维,加上Kubeflow、Istio、Volcano这些组件,出问题的概率大大增加。今天这个Pod CrashLoopBackOff,明天那个组件内存泄漏,后天节点NotReady,每天都在排查问题,很累。
第二个问题是版本升级。Kubernetes要升级,Kubeflow要升级,各种组件要升级。每次升级都是一场灾难,升级之后这个不兼容了,那个功能坏了,要花很多时间修复。后来我都不敢轻易升级了,能用就不升。
第三个问题是成本。云原生AI的成本很高,不仅是GPU的成本,还有运维的人力成本。我们花了很多时间在搭建和运维平台上,反而没有时间做真正的AI开发。算下来,还不如直接用云厂商的AI服务,或者用简单的方案,成本更低。
第四个问题是团队学习成本。云原生AI的技术栈太复杂了,Kubernetes、Docker、Kubeflow、分布式训练、推理服务,算法工程师根本学不过来。他们只想训练模型,不想学怎么写Dockerfile,怎么提交K8s任务,怎么排查Pod问题。最后还是我一个人在维护平台,其他人都不用,平台成了摆设。
第五个问题是数据安全和权限。Kubeflow的权限管理很弱,多用户隔离做得不好,所有人都能看到所有人的实验和数据。对于企业来说,这是很大的安全隐患。要做好权限管理,还要对接企业的SSO、RBAC,很复杂。
日常运维了几个月,我终于有点撑不住了。每天都在处理各种问题,平台用的人也不多,投入产出比很低。
转折点:重新评估
有一天,我停下来认真想了想:我们真的需要云原生AI吗?
我们的团队只有5个算法工程师,GPU只有8块,模型也不多,训练任务不是很多。这样的规模,真的需要Kubernetes、Kubeflow这么复杂的方案吗?
我列了一下我们的实际需求:
- GPU资源共享,提高利用率。
- 环境一致性,解决"在我机器上能跑"的问题。
- 模型部署简单,更新方便。
- 不要太复杂,算法工程师能直接用。
然后我发现,这些需求,不一定需要完整的云原生AI平台来解决。
GPU资源共享,可以用简单的任务队列+SSH的方式,或者用Slurm这种传统的HPC调度器,比Kubernetes简单多了。
环境一致性,用Docker就够了,不一定需要Kubernetes。每个人用Docker镜像跑训练,环境就一致了。
模型部署,用Docker Compose或者简单的脚本就够了,不一定需要KServe和自动扩缩容。我们的流量不大,单实例就够了。
算法工程师能直接用,这一点最重要。Kubeflow的界面虽然好看,但对算法工程师来说还是太复杂了。他们更习惯用Jupyter Notebook和命令行。
想清楚这些之后,我决定放弃完整的云原生AI方案,改用更简单、更适合我们团队规模的方案。
最终方案:简化再简化
我把方案简化了又简化,最终的方案是这样的:
- 用一台GPU服务器,装Docker和NVIDIA Container Toolkit,所有人通过SSH登录,用Docker容器跑训练任务。
- 用一个简单的任务队列脚本,管理GPU资源的分配,避免两个人同时用一块GPU。
- 训练环境用Docker镜像,统一基础镜像,每个人在基础镜像上装自己需要的依赖。
- 模型部署用Docker Compose,每个模型一个容器,用Nginx做反向代理和负载均衡。
- 用MLflow做实验跟踪和模型管理,部署在一台普通服务器上。
- 数据存在NAS上,通过NFS挂载到GPU服务器。
这个方案很简单,没有Kubernetes,没有Kubeflow,没有Istio,没有Volcano。但它满足了我们的所有需求,而且维护成本很低,算法工程师也能很快上手。
搭建这个简化方案,只花了我两天时间。而之前的云原生AI平台,花了我几个月的时间,还一直在出问题。
用了简化方案之后,大家的反馈反而更好了。算法工程师觉得简单好用,不用学复杂的K8s概念。我也不用每天排查集群问题了,有更多时间做真正有价值的事情。
我的感悟
经历了从入门到放弃的全过程,我有一些感悟,想分享给大家。
第一个感悟:不要为了技术而技术。
很多时候,我们追求新技术,是因为它听起来很酷、很前沿,而不是因为我们真的需要。云原生AI确实很好,但它适合大规模、多团队、复杂场景的企业。对于小团队、小规模的场景,简单的方案可能更合适。
选择技术方案的时候,要从实际需求出发,而不是从技术潮流出发。问问自己:这个技术解决了什么问题?这个问题是我现在真的遇到的吗?有没有更简单的解决方案?想清楚这些,再做决定。
第二个感悟:复杂度是有成本的。
每引入一个新的技术组件,就增加了一份复杂度,也就增加了一份运维成本和学习成本。Kubernetes、Kubeflow、Istio这些组件,每一个都很复杂,加在一起就是指数级的复杂度。
复杂度不是免费的,它需要人来维护,需要时间来学习,需要精力来排障。在引入复杂度之前,要想清楚:这个复杂度带来的收益,是否大于它的成本?如果收益不大,就不要引入。
第三个感悟:小团队要用小团队的方式。
大公司有专门的平台团队,有SRE,有运维工程师,他们能维护复杂的云原生AI平台。但小团队没有这些资源,每个人都要做很多事情,没有精力维护复杂的平台。
小团队应该用简单、轻量、易用的方案,把精力放在核心业务上,而不是平台运维上。等团队规模大了,需求复杂了,再考虑更复杂的方案也不迟。
第四个感悟:算法工程师的体验很重要。
AI平台的用户是算法工程师,平台好不好用,他们说了算。如果平台太复杂,他们学不会,不愿意用,那平台就没有价值。
设计AI平台的时候,要从算法工程师的角度出发,考虑他们的使用习惯和学习成本。最好的平台,是让他们感觉不到平台的存在,能专注于算法本身。
第五个感悟:云原生AI不是银弹。
云原生AI能解决很多问题,但它不是银弹,不能解决所有问题。它有自己的适用场景,也有自己的局限性。不要指望上了云原生AI,所有问题就都解决了。
而且,云原生AI的技术还在快速发展中,很多工具和平台还不成熟,坑很多。在生产环境大规模使用之前,要充分评估,做好踩坑的准备。
什么时候适合用云原生AI
虽然我放弃了完整的云原生AI方案,但我不是说云原生AI不好。在某些场景下,云原生AI确实是最好的选择。
适合用云原生AI的场景:
- 团队规模大,算法工程师多,GPU资源多,需要统一管理和调度。
- 有专门的平台团队和运维人员,能维护复杂的平台。
- 模型多,训练任务频繁,推理服务流量大,需要自动扩缩容和高可用。
- 多团队协作,需要统一的平台和权限管理。
- 对环境一致性、可复现性、自动化要求很高。
如果你的团队符合这些条件,云原生AI确实能带来很大的价值,值得投入。
不适合用云原生AI的场景:
- 小团队,算法工程师少,GPU资源少。
- 没有专门的运维人员,维护能力有限。
- 模型不多,训练任务不频繁,推理流量不大。
- 算法工程师对K8s等技术不熟悉,学习成本高。
- 业务还在探索期,需求变化快,不需要太复杂的平台。
如果你的团队符合这些条件,建议先用简单的方案,等规模大了再考虑云原生AI。
写在最后
从满怀热情地入门,到身心俱疲地放弃,再到找到适合自己的简化方案,这大半年的经历,让我学到了很多。
云原生AI是一个很好的技术方向,我相信它未来会越来越成熟,越来越普及。但它不是万能的,也不是适合所有团队的。选择技术方案,要从实际出发,不要盲目追新,不要为了技术而技术。
对我来说,这次"从入门到放弃"的经历,不是失败,而是一次宝贵的学习。我学到了Kubernetes、Kubeflow、分布式训练、模型部署等很多技术,也更深刻地理解了技术选型和复杂度管理的重要性。
以后如果团队规模大了,需求复杂了,我可能还会重新考虑云原生AI。但现在,简单的方案就是最好的方案。
希望我的经历能给正在考虑云原生AI的朋友一些参考。不要被技术潮流裹挟,想清楚自己的需求,选择最适合自己的方案,才是最重要的。
技术是为业务服务的,不要本末倒置。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录