算力中心的运维跟传统互联网机房完全是两个物种。传统机房你关心的是CPU、内存、磁盘顶多再加个负载均衡到了算力中心你面对的是几十上百台带GPU的高密度服务器每台卡的显存、驱动版本、NVLink拓扑都可能不一样跑在上面的任务要么是十几个小时的模型训练要么是延迟敏感的在线推理任何一次节点配置失误轻则任务失败重则把整池算力拖垮。在做了几年GPU服务器运维之后我把整个算力中心的运维体系收敛成了三个核心工具Ansible负责“批量管机器”Jenkins负责“自动化交付应用”K8s负责“动态调度算力”。这套组合覆盖了算力中心从硬件纳管到业务发布的关键路径也是今天想重点拆解的内容。这篇东西适合正在做GPU集群、HPC集群、AI训练平台运维的同学也适合刚接触自动化运维但不知道怎么把工具组合起来的新手。我会按照实际落地的顺序讲清楚每个工具在算力中心里的定位、踩过的坑、以及它们是怎么串联在一起的。1. 先搞清楚算力中心运维到底在运维什么1.1 算力中心的设备构成和运维痛点很多人一听到“算力中心”就想到成排的GPU服务器但真实的算力中心至少包含三类节点GPU计算节点、CPU存储节点、带外管理节点实际运维时还会牵扯到高性能网络设备。GPU计算节点通常装着NVIDIA的A100、H800、L40S这类加速卡也可能有国产加速卡混在里面异构程度远比传统机房高。每台机器上不只有操作系统还有GPU驱动、CUDA toolkit、NVIDIA容器工具链、高性能网卡的驱动和固件这一堆东西的版本之间还存在依赖关系换一个就得联动很多个。运维痛点首先是“量”。几十台节点的初始化、参数调整、驱动升级靠手工一台台登上去敲命令效率低且容易出错。其次是“异构”。不同型号的GPU对应不同的驱动版本不同厂商的网卡需要不同的固件和配置还有很多国产化算力卡的管理方式跟NVIDIA完全不一样这意味着你没法用一套脚本打天下必须得让配置跟着节点类型走。还有一个隐蔽的痛点是“算力不可中断”。训练任务跑一半被打断浪费的是几千卡时推理服务抖动一下线上业务就受影响。所以在做任何节点级别的变更时都要有批量执行、分批灰度、可回滚的思路。1.2 为什么偏偏是 Ansible、Jenkins 和 K8s选型这件事一开始也纠结过。配置管理这块SaltStack、Puppet都是成熟方案SaltStack还自带master-minion架构实时下发能力更强但它的部署和维护成本比Ansible高。算力中心这种场景大多数操作不是秒级响应的而是“每天定时对齐一次状态”、“发版前批量改配置”Ansible这种无代理、走SSH的模型反而更省心控制机上装个客户端就行被管节点连agent都不用装对大规模集群尤其友好也省去了agent版本不一致带来的麻烦。Jenkins做CI/CD也是权衡过的。GitLab CI的Pipeline写起来很简洁但如果公司已经用了大量Jenkins插件、沉淀了构建脚本迁移成本并不低。而且算力中心的构建环境经常是离线的很多东西得离线装Jenkins的插件管理机制和外围生态对离线环境更友好。K8s这边基本没悬念容器编排在算力中心已经是事实标准训练任务、推理服务、数据预处理任务都能用工作负载描述清楚。这三个工具的职责边界很清晰Ansible管的是“机器的状态”比如内核参数、驱动版本、用户权限、NTP配置Jenkins管的是“代码到产物的流转”也就是构建、测试、打包、推送镜像K8s管的是“产物运行时的调度”容器在哪个节点上跑、分配多少GPU、挂了怎么恢复。三者各管一层又通过代码和配置串成一条链这样运维人员面对的不再是碎片化的命令行而是一套可控的流程。2. 第一步用 Ansible 把几百台服务器的地基铺平2.1 算力中心的网络规划与批量纳管思路Ansible干活的前提是能连上所有目标机器所以在算力中心里网络规划会直接决定自动化能走多远。我这边是把网络分成了管理网、业务网、存储网三类管理网负责SSH和带外管理业务网承载容器流量和GPU通信存储网专门跑数据读写。Ansible的通信全部走管理网这样即使业务网出现故障运维通道依然是通的节点在业务上被“打挂”了Ansible还能连上去抢救。inventory文件建议按照算力中心的物理结构来组织比如把节点分成[gpu_nodes]、[cpu_nodes]、[storage_nodes]这些组再用子组把不同GPU型号分开。下面是个简化版的分组示例实际生产环境里还会再套一层机房或者集群维度的分组[gpu_nodes] gpu-01 ansible_host192.168.10.11 gpu-02 ansible_host192.168.10.12 [gpu_nodes:vars] ansible_userops ansible_ssh_private_key_file/home/ops/.ssh/ansible_key [gpu_a100] gpu-01 gpu-02 [gpu_h800] gpu-03 gpu-04分组的意义不只是为了执行效率更关键的是可以让配置差异化。比如gpu_a100组的机器驱动版本要求是535.xgpu_h800组要求是550.x通过组变量就能做到一套Playbook跑不同节点的不同配置不用拆成好几套脚本。批量纳管的第一步是分发SSH密钥。生产上我建议为Ansible单独生成一对密钥把公钥通过ssh-copy-id或者带外批量注入的方式分发到所有节点的authorized_keys里然后确认控制机能免密登录所有目标。随后用一条Ad-Hoc命令快速验证连通性ansible -i hosts gpu_nodes -m ping连通之后再把ansible.cfg里几个关键参数调好不然批量操作稍微大一点就会卡住。下面是我生产环境的配置[defaults] inventory hosts host_key_checking False forks 30 timeout 20 ssh_args -o ControlMasterauto -o ControlPersist60sforks默认是5意味着同时只能操作5台机器几十台节点跑下来会等得人发慌。我一般根据控制机配置调到30到50之间。SSH连接复用参数也是必须的否则每次执行都需要重新建连握手延迟会集中在控制机上。2.2 Ansible 离线安装与基础配置踩坑记录算力中心有个很现实的问题生产环境经常是内网隔离的不能随意连外网。Ansible的离线安装是热词里提到比较多的场景实际做起来有两条路一条是在有外网的机器上用pip先把ansible和所有依赖包下载到一个目录再拷贝进内网用pip安装另一条是把ansible的rpm包和依赖打进本地yum源直接用yum安装。我这边用的是pip下载的方式因为版本锁定更精确操作也相对简单。在有外网的机器上执行pip download ansible9.1.0 -d /opt/ansible-offline/ -r requirements.txt然后把整个目录拷进内网控制机执行pip install ansible --no-index --find-links/opt/ansible-offline/离线安装时最容易踩的坑是依赖版本冲突比如paramiko版本不对导致SSH连接失败或者Jinja2版本太老导致模板渲染出错。我的建议是下载的时候把依赖一起pip download完整装的时候用一个全新的虚拟环境避免和系统Python包互相干扰。离线环境还有个需要注意的地方如果被管节点也要用Ansible的yum、dnf模块装软件那就需要在节点上配置本地源或者提前把rpm包放到内网仓库里。Ansible Playbook里的yum模块可以指定disable_gpg_checkyes以及本地源地址但底层还是依赖于节点能访问到安装包这一点比配置Ansible本身更费事需要提前规划好软件分发仓库。2.3 高频 Playbook 实战系统初始化、GPU 驱动与节点巡检算力中心的系统初始化是我用Ansible最多的一块。新节点上架之后从操作系统安装完成到可以分配算力中间要经过一堆配置动作修改主机名和DNS、设置时区和NTP、调整内核参数、优化SSH配置、创建运维账号、配置sudo权限、部署日志采集和监控agent。这些操作全部要幂等也就是Playbook跑第二遍也不会报错或产生副作用Ansible的模块机制天然适合这种需求。内核参数这块算力中心跟普通机房最大的差异是网络和共享内存。GPU训练特别是多机多卡训练对网络缓冲区、连接追踪表、vm.max_map_count这些参数很敏感如果不调大大规模训练经常莫名其妙挂掉。我这边的一个系统初始化任务通常会包含下面这些配置- name: 调优内核参数 sysctl: name: {{ item.name }} value: {{ item.value }} state: present loop: - { name: vm.max_map_count, value: 6553000 } - { name: net.core.rmem_max, value: 134217728 } - { name: net.core.wmem_max, value: 134217728 } - { name: net.ipv4.tcp_rmem, value: 4096 87380 134217728 } - { name: net.ipv4.tcp_wmem, value: 4096 87380 134217728 }GPU驱动的安装是另一个重头戏。NVIDIA驱动要求内核版本、GCC版本、kernel-devel包和驱动版本严格匹配在内网环境里建议先把.run驱动包放到本地仓库用Ansible统一执行静默安装。核心的Playbook逻辑大概是- name: 安装 NVIDIA GPU 驱动 shell: /opt/driver/NVIDIA-Linux-x86_64-550.90.07.run --silent --dkms args: creates: /usr/bin/nvidia-smi when: ansible_local.nvidia_driver is not defined or ansible_local.nvidia_driver 550.90.07安装驱动有几个非常关键的注意点。第一是必须先禁用Nouveau开源驱动否则NVIDIA官方驱动会拒绝安装这一般在/etc/modprobe.d/blacklist-nouveau.conf里加两行然后重建initramfs。第二是--dkms参数建议加上这样内核升级后驱动能自动重新编译不然换了内核后驱动就失效了节点上的GPU直接没法用。第三是装完之后要验证nvidia-smi输出的Driver Version和CUDA Version符合预期再做一次GPU压力和带宽测试确认不是只装了驱动壳子。节点巡检也是个很值得用Ansible做的场景。GPU服务器的健康状态不只是CPU负载和磁盘空间还包括GPU温度、显存使用率、ECC错误计数、NVLink带宽、网卡收发包丢包率、风扇转速等一系列指标。可以设计一个定时执行的巡检Playbook把nvidia-smi --query-gpu... --formatcsv的采集结果统一汇总超过阈值的节点写入报告并触发告警。这样既能提前发现显存颗粒老化的隐患也能在训练任务出问题的时候定位到是不是硬件故障导致的。3. 第二步用 Jenkins 把构建和发布做成流水线3.1 Jenkins 部署的两种姿势与选型建议Jenkins在算力中心有单机部署和K8s动态agent两种典型姿势。节点规模不大、业务相对单一的时候单机部署最简单一台8核16G的机器足够跑日常构建而且和外部系统的网络打通也容易。但我自己后来还是把Jenkins迁进了K8s因为算力中心的构建任务往往是“突发重负载”的多个团队同时提交训练镜像构建时单机Jenkins的构建队列会排得很长而K8s动态agent能做到低峰期不占用资源、高峰期自动扩展执行节点。如果是老机器部署Jenkins会遇到一个经典问题CentOS 7.9环境只带JDK 8但新版Jenkins强制要求JDK 11或17。网上热词里也有人在搜“linux centos7.9安装兼容jdk1.8版本的jenkins”这时要么给机器单独装一套JDK 11并切换默认版本要么干脆用Jenkins老版本。我个人不太建议在生产环境用太老的Jenkins安全漏洞和插件兼容性问题会很多更推荐的方式是用Docker或K8s部署镜像里直接固定好JRE版本宿主机上是什么JDK根本不重要。在K8s里部署Jenkins核心在于让Jenkins的controller跑一个Deployment然后安装Kubernetes插件配置一个Pod Template作为构建执行器。每次构建任务进来Jenkins自动在K8s集群里创建一个Pod构建完自动删除。这样构建环境是完全隔离的不会出现“上次构建装的依赖污染了这次构建”的问题。3.2 Pipeline 流水线的一个可落地骨架算力中心里的构建任务典型流程是拉取代码或算法包做编译或打包构建Docker镜像推送到Harbor镜像仓库最后触发K8s滚动更新。我习惯用声明式Pipeline把所有阶段白纸黑字写进代码仓库这样所有改动都有迹可查也方便团队间评审和复用。下面是我这边一个推理服务发布流水线的骨架pipeline { agent { label builder } environment { IMAGE_REPO harbor.example.com/ai-platform IMAGE_TAG ${env.BUILD_NUMBER} } stages { stage(拉取代码) { steps { git branch: main, url: http://git.example.com/ai/infer-service.git } } stage(单元测试) { steps { sh pytest tests/ -x --tbshort } } stage(构建镜像) { steps { sh docker build -t ${IMAGE_REPO}/infer:${IMAGE_TAG} -f docker/Dockerfile . } } stage(推送镜像) { steps { sh docker push ${IMAGE_REPO}/infer:${IMAGE_TAG} } } stage(触发部署) { steps { sh kubectl set image deployment/infer infer${IMAGE_REPO}/infer:${IMAGE_TAG} -n ai } } } }在设计流水线时有件事一定要想清楚你希望构建和部署是一个Pipeline还是一个拆分Pipeline。我的经验是拆成“构建”和“发布”两个Pipeline构建负责产出镜像并打tag发布负责把某个tag部署到指定环境。这么做的好处是线上想回滚时不必重新跑一遍构建直接用旧的镜像tag触发发布就行。如果构建和发布混在一起每次发布都要重新构建代码回滚成本就上去了。另外算力中心的镜像都偏大。一个GPU推理服务的镜像经常动不动就好几个GB因为基础镜像就得用nvidia/cuda:12.2-base-ubuntu22.04这种带CUDA运行时的镜像。镜像大了构建和推送都会变慢甚至超过Jenkins默认的stage超时时间。我一般会在Pipeline里单独设置options { timeout(time: 30, unit: MINUTES) }并且把镜像写入Harbor时启用压缩和分块传输Harbor本身的垃圾回收策略也要定期跑否则镜像仓库会变成磁盘杀手。3.3 算力中心特有的发布场景模型服务版本化算力中心的CI和传统Web开发有一个本质差异要交付的不只是一个war包或者jar包而是一个“模型推理代码依赖库固定运行时”的完整环境。模型文件往往几个GB甚至几十GB如果每次发布都重新构建镜像CI时间和存储成本完全吃不消。我这边采取的做法是把模型文件作为独立数据集存放在对象存储或NAS上服务启动时动态挂载镜像里只保留代码和依赖库。这种做法有个额外的好处模型热更新不必重建镜像只要在K8s里把新的模型版本挂载到Pod中灰度几个实例验证没问题后再全量切换。Jenkins在这个流程里的作用是自动触发模型数据同步和K8s工作负载更新比如直接用kubectl rollout restart让Pod重新挂载新的模型版本。这样做之后模型发布的时间从“构建镜像几十分钟”降到“同步数据几分钟”对算法团队来说体感好非常多。还有一点值得提镜像内的Python依赖库版本一定要锁定。很多线上疑难问题都是因为构建时没锁版本某天依赖库更新了同一套代码就构建不出来了。在Dockerfile里用pip install -r requirements.lock比requirements.txt可靠得多。最好再加一层依赖缓存把经常不变的依赖层放在Dockerfile前面代码放到后面这样每次构建只需要重传代码层镜像构建速度会有质的提升。4. 让 Jenkins 和 Ansible 联动配置变更跟着发布一起走4.1 为什么必须联动我见过很多团队的发布流程是断层的Jenkins负责部署应用节点配置有专人手工去改。这种做法在算力中心风险极大。GPU节点配置和应用版本之间强相关比如新版本的推理服务要求宿主机的NVIDIA驱动不低于某个版本要求内核网络参数做了调整如果发布流程里没有配置变更这一步应用新版本跑在老配置的节点上大概率出各种莫名其妙的问题。所以我的原则是应用发布和配置变更必须放进同一条流水线。Jenkins Pipeline里不仅可以构建镜像、更新K8s也可以主动调用Ansible Playbook去更新目标节点的系统配置而且是通过同一个版本号关联起来。这样每次发布都对应一份完整的变更记录出问题回滚时也能把系统配置一起回滚。4.2 联动落地从 Jenkins 调用 Ansible Playbook实现联动的技术方式不复杂关键是把权限和密钥管好。Jenkins控制机上安装Ansible把SSH私钥放到Jenkins的凭据管理里然后Pipeline里直接用credentials步骤把私钥写到临时位置再用ansible-playbook执行。下面是一个简化的流水线片段stage(更新GPU节点配置) { steps { withCredentials([sshUserPrivateKey(credentialsId: ansible-key, keyFileVariable: SSH_KEY, usernameVariable: SSH_USER)]) { sh ANSIBLE_PRIVATE_KEY_FILE${SSH_KEY} \\ ansible-playbook -i /opt/ansible/hosts \\ /opt/ansible/playbooks/update-gpu-node.yml \\ --limit gpu_a100 } } }这里有个容易被忽略的细节Ansible的inventory和Playbook应该纳入Git仓库管理而不是直接在Jenkins服务器上散落一堆文件。我这边是单独建了一个ops-ansible仓库Jenkins发布Pipeline先拉取这个仓库到工作目录再执行里面的Playbook。这样配置变更能被审计、能回滚、能被评审而不是某天某个人手动在服务器上改了一下就再也查不到来源了。4.3 联动过程中的安全与幂等联动之后Jenkins就成了一个“有权限控制所有GPU节点”的系统。它的安全级别必须提上来否则等于给攻击者留了一扇后门。我的做法是Jenkins本身不保存大量系统密钥SSH私钥靠凭据系统集中管理并定期轮换只有受信用户才能触发发布流水线生产环境和测试环境的Ansible inventory完全分开生产环境的执行会加一个人工确认步骤防止误触发生成不可控变更。而Ansible Playbook本身幂等性是在联动场景里最重要的约束。因为发布流水线会被反复触发Playbook如果写得不幂等跑一次改一次状态就永远收敛不了。比如改配置文件时用lineinfile或template模块而不是shell直接追加改系统参数用sysctl模块而不是手写命令这些习惯在联动场景下会避免很多生产事故。5. 把 GPU 调度交给 K8s算力真正用起来的最后一环5.1 K8s 和 Docker 到底是什么关系很多初学者被一个经典问题卡住K8s和Docker有什么区别回答这个问题需要先理解K8s并没有替代Docker它们不是一个层面的东西。Docker擅长的是把应用连同运行环境打包成一个标准化的容器镜像然后在单机上把容器跑起来而K8s解决的是“一大堆容器到底怎么调度”的问题它决定哪个容器跑在哪台机器上、怎么保证容器挂了能拉起、怎么把流量均衡分配到各个副本上。也就是说如果算力中心只有几台机器用Docker Compose就够用了一旦节点规模上来GPU资源要动态分配、多团队要共享集群、业务要弹性伸缩就必须引入K8s这种编排系统。现在很多K8s集群已经直接用containerd做运行时Docker只是其中一个兼容的运行时选项。所以准确的理解是Docker解决“镜像和容器”问题K8s解决“大规模容器的调度与治理”问题。5.2 GPU 调度与节点打标K8s本身不知道GPU是什么它默认只调度CPU和内存。要让GPU变成集群里的可调度资源需要安装NVIDIA device plugin。这个组件运行在每个GPU节点上负责向API Server上报该节点有多少张卡、每张卡的显存多大而且在Pod调度成功后把宿主机上的GPU设备映射进容器。装好之后在Pod的resources.limits里声明nvidia.com/gpu: 1K8s才会知道这个Pod要占用一张完整的GPU卡。但算力中心的GPU节点往往型号混杂A100、H800、L40S这些卡的处理能力、显存大小、适用场景都不一样。所以节点打标非常重要我一般会给每个GPU节点打上几类标签GPU型号、显存大小、驱动版本、所在机柜。比如kubectl label node gpu-01 acceleratornvidia-a100-80g gpu-driver550.90.07打标之后调度策略就清晰了。训练任务如果跑大模型就要求调度到显存80G的节点推理服务如果对延迟敏感就调度到靠近业务入口的低负载节点。用nodeSelector或者affinity指定调度目标spec: nodeSelector: accelerator: nvidia-a100-80g containers: - name: trainer image: harbor.example.com/ai-platform/train:latest resources: limits: nvidia.com/gpu: 2GPU调度的坑主要集中在资源不匹配上。最常见的是Pod调度失败报错0/8 nodes available: 7 Insufficient nvidia.com/gpu, 1 node(s) didnt match node selector。排查方向很简单kubectl describe pod看一下具体的调度事件是GPU资源不够还是标签没匹配上。要避免这类问题建议在节点不够的情况下用污点和容忍度把某些节点专门留给大任务小任务别挤上去。还有一点是关于显存碎片化。一张80G的A100卡只能被一个Pod独占如果一个小推理服务申请了半张卡K8s本身并没有办法把一个Pod塞进已有的半个空闲显存里除非用了支持显存切分的Device Plugin。对于30G、40G这些小于单卡显存的任务可以直接在Pod里申请nvidia.com/gpu: 1然后利用NVIDIA MPS或MIG做卡内切分否则会出现大量空闲碎片算力整体利用率很低。5.3 训练任务与推理服务的编排差异K8s里跑训练和跑推理服务用的工作负载类型完全不同。训练任务的特点是“一次性”启动之后跑一两个小时甚至一整天跑完就退出整个过程要么成功要么失败。这种任务在K8s里适合用Job或CronJob管理失败的话K8s可以自动重试重试次数和并行数量都能配置。多机多卡训练在K8s原生环境里还需要配合PaddlePaddle、PyTorch等框架的Operator或者直接用kubeflow里的PyTorchJob才能真正实现分布式训练。推理服务则是长期运行的在线服务得用Deployment来管理。比如部署一个Nginx PHP-FPM MySQL的LNMP架构应用如果直接在K8s里硬整MySQL需要StatefulSet保证存储和网络标识稳定Nginx和PHP-FPM用Deployment各自维护副本数再通过Service做内部负载均衡Nginx配置里指向PHP-FPM服务的名称。用K8s部署LNMP这类典型应用最大的收益不是单个组件而是整个应用的扩容缩容、故障自愈、滚动发布都自动化了。推理服务的弹性伸缩要特别小心。GPU资源不像CPU那样可以秒级缩容多一个新的Pod就要多占一张卡所以新增副本要提前评估集群里的空闲GPU数量。我建议推理服务以稳定性优先节点预留一定的空闲GPU缓冲HorizontalPodAutoscaler别配得太激进否则POD频繁创建删除反而破坏了GPU的亲和性和显存连续性延迟抖动会更严重。6. 生产实战中的典型故障与排查方法6.1 Ansible 批量操作失效的几个原因Ansible执行失败的场景我印象最深的几个原因都跟网络和SSH有关。第一个是管理网的负载太高大批量forks并发执行的时候SSH握手建立不过来报错Timeout (12s) waiting for privilege escalation prompt。第二个是SSH密钥复制后没有设置好节点上的authorized_keys权限sshd直接拒绝免密登录。第三个也常见被管节点磁盘写满连Ansible的setup模块都跑不动。排查这类问题有两种实用手段。一是执行时加上-vvv查看详细连接日志定位到具体卡在哪一步。二是先限制一小批机器做“金丝雀”执行比如ansible-playbook init.yml --limit gpu-01确认没问题后再放开到全量。我从来不在生产环境第一次就跑全量Playbook批量变更的风险必须控制在小范围内。6.2 Jenkins 构建环境不一致与磁盘打满Jenkins最经典的问题是“在我机器上是好的”在构建节点上却失败。原因通常是构建节点和开发环境的依赖版本不一致。用K8s动态agent之后这个问题能被极大缓解因为每个构建任务都跑在一个全新的干净Pod里。另一个经典问题是构建节点的Docker磁盘被打满因为镜像越堆越多尤其算力中心的镜像大而多几分钟磁盘就能到80%。建议在Jenkins里配置Harbor的清理策略再定期执行docker image prune和docker builder prune把无用的镜像层和构建缓存清掉。Pipeline里的环境变量也是个容易踩坑的点。Jenkins有内置环境变量比如BUILD_NUMBER、WORKSPACE也有你在environment里自定义的变量。如果自定义变量名跟内置变量撞了就会出现很隐蔽的值覆盖问题。我建过一个习惯自定义环境变量都加APP_或IMG_前缀比如IMG_TAG避免和内置变量或插件注入的变量冲突。6.3 K8s 中 GPU Pod 调度失败与节点故障GPU Pod调度失败是算力中心最高频的K8s问题。碰到Unschedulable事件时我在现场的第一反应是看节点上的可分配GPU数量是不是已经满了其次看标签和污点是否匹配最后看驱动是否正常。驱动出问题时kubectl describe node看到的nvidia.com/gpu数量可能直接从8变成了0这时候设备插件已经报错了需要到节点上看kubectl logs -n kube-system device-plugin-pod的事件信息。还有一种情况是Pod运行中突然GPUError或者进程崩溃经常跟宿主机的NVIDIA驱动版本和容器内CUDA版本不匹配有关。容器内的CUDA依赖通过镜像固定宿主机的驱动版本必须足够新二者之间存在兼容矩阵。我的经验是GPU节点驱动统一选择较新的稳定版本比如NVIDIA 550系列并尽量在集群内保持一致避免不同节点驱动版本差异过大导致任务被调度上去后表现不一致。再看节点NotReady问题。GPU服务器的带外管理虽然独立但业务网卡或NVIDIA驱动崩溃会导致K8s节点失联。遇到NotReady先别急着重启节点因为重启可能让正在运行的训练任务全部中断。可以先登录带外管理口看系统是否活着再用systemctl status kubelet看Kubelet状态必要时只重启Kubelet和containerd让存量Pod尽量平滑迁移。6.4 一条实战排障流程从告警到恢复最后分享一个比较完整的排障例子。某天凌晨监控告警某个训练任务失败Pod状态显示Error。我的处理顺序是先看任务是用Job还是Deployment跑的是不是被K8s自动拉起了然后看Pod事件发现调度失败原因是GPU资源不足接着看集群GPU分配情况发现某几个高性能节点虽然总卡数很多但都被推理服务占用了而训练任务又指定了nodeSelector必须跑到那几台节点上调度器当然就失败了。找到原因之后调整策略一方面给训练任务放宽nodeSelector让它能调度到集群里其他可用GPU节点另一方面给推理服务设了节点亲和性不让它们占满所有高性能卡。最后在Jenkins里加了一步任务发布前自动检查集群GPU余量GPU余量不足直接阻断发布并通知值班人员。这样处理之后类似问题再也没在深夜反复出现过。算力中心的运维本质上是用自动化工具替换经验直觉用标准化流程对抗异构复杂性。Ansible、Jenkins、K8s这三个工具我不觉得是什么新技术但组合在一起确实把一个容易失控的GPU集群变成了有章可循的体系。真正难的不是记命令而是想清楚每一层工具该管什么、怎么衔接、出问题往哪儿排查。希望这篇东西能给你一点参考。