ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

K8S算力架构全解:从集群高可用到GPU调度与迁移实战

K8S算力架构全解:从集群高可用到GPU调度与迁移实战 最早接触 K8S还是公司把容器化列为年度技术目标那会儿。当时团队讨论得最多的问题不是 Pod 怎么调度、镜像怎么写而是“我们的存量应用、GPU 训练任务、监控体系到底该以什么姿势搬到这堆新抽象概念上”。后来几年里我陆续搭过单节点验证环境、三 master 高可用集群也经历过证书过期导致整个集群调度停摆才慢慢把一套能扛住高并发的K8S 算力架构在脑子里拼完整。这篇文章就是围绕这套架构做的完整复盘。它不是什么新概念包装而是实实在在的踩坑总结从控制面与计算面如何分离到 GPU 算力怎么被调度从 kubeadm 和 Kubekey 怎么选到 Prometheus 监控怎么落再从“若依微服务不停机迁移”这个典型场景聊到 JMeter 压测验证承载能力。适合正在做 K8S 集群规划、想引入 GPU 算力池、或者准备把存量业务迁上容器平台的运维和开发同学参考。我尽量把当初踩过的坑、改过的方式、最后沉淀下来的做法都写清楚。1. 算力架构的整体设计思路1.1 为什么算力平台普遍选择 K8S 而不是虚拟机很多人会问跑算力任务用虚拟机不就行了吗为什么非要上 K8S我从实际运维角度给你拆一拆。虚拟机是把一台物理机切成多个“完整的小电脑”每个小电脑有自己独立的操作系统资源边界硬隔离但这带来的问题是你很难把零散的算力资源池化。比如一台 8 卡 GPU 服务器如果用传统方式给训练任务分卡你得手动建多台 GPU 虚拟机每台绑定两张卡任务用完那两张卡别人也用不了卡得死死的。K8S 解决的就是资源抽象和调度问题。它把物理机当成一个资源池通过节点上的 kubelet 上报 CPU、内存、GPU 等可分配资源调度器按任务需求去“找位置”。训练任务跑完资源自动释放下一批任务立刻能排上来。再加上 Deployment 的副本机制、HPA 自动扩缩容、滚动更新不中断这些能力承载在线推理和微服务也很顺手。用个生活类比虚拟机像装修好的单间你租下来就得整套用哪怕只睡一张床客厅也得空着K8S 更像青年公寓的按需服务你需要几张卡就给你安排几张卡东西退租了马上转给别人。之前我维护过一个内部推理平台原来用虚拟机高峰期 GPU 卡利用率不到四成迁移到 K8S 设备插件调度之后利用率能稳定到七成以上这就是“算力架构”里最实打实的收益。1.2 算力型集群的拓扑规划控制面、计算面与存储面分离搭建算力集群的时候最容易犯的错误就是把所有角色塞进同一批节点。我见过不少团队三台机器既当 master 又当 worker跑着跑着 etcd 的 IO 被业务应用挤爆整个集群的调度都跟着抖。正确的思路是按功能切分节点角色。控制面节点专门跑 kube-apiserver、kube-scheduler、kube-controller-manager 和 etcd。这些组件对磁盘 IO 和网络延迟比较敏感尤其是 etcd它要求低延迟、高一致性千万别让日志采集、批处理任务和它抢资源。计算面节点就是真正跑业务的微服务、训练任务、推理服务都堆在这里。存储面则要看数据量级小数据集用本地盘加 Local PV 就行数据集大了建议接独立存储集群或者云厂商的块存储数据面与控制面分离后重活累活不会拖累调度。网络拓扑也要提前想清楚。GPU 服务器之间的数据交互很频繁如果是分布式训练建议给计算节点之间留高速内网并且让调度器感知到这一点。我当时给集群打了node-role.kubernetes.io/gputrue这种自定义标签再把训练任务通过 nodeSelector 只调度到 GPU 节点避免 CPU 任务挤进 GPU 机器白白占用内存带宽。节点规模也要留余量。单节点环境只能拿来学习和验证生产环境至少要三台 master 组成高可用worker 数量按业务冗余来算通常“峰值所需算力 一台故障冗余”是最低要求。后面我再细说三 master 的搭建细节。2. 核心组件与关键选型解析2.1 部署工具kubeadm 还是 Kubekey搭建 K8S 集群的方式很多但在社区里主流的就是 kubeadm 和 Kubekey。kubeadm 是官方提供的工具yaml 一把梭能把控制面组件通过静态 Pod 方式拉起来逻辑透明出了问题你知道去哪看日志。Kubekey 是 KubeSphere 社区出的部署工具它的优势是交互式操作一条命令能装完整的 K8S 加 KubeSphere 管理面板对高可用场景做了很多封装。怎么选看你的场景。如果是学习为主或者你有自定义网络、自定义证书管理的需求选 kubeadm它的每一步都在你掌控之下。如果是生产快速交付团队里又没有太多精通 K8S 的运维选 Kubekey 会更省心装完自带管理界面日常看资源、看工作负载、看日志都比较方便。我自己是混着用的验证环境用 kubeadm 手动搭方便理解组件关系生产环境第一次交付用的是 Kubekey因为时间紧靠它快速拉起了三 master 高可用。但注意不管用哪个工具集群版本和组件版本要提前规划好比如 containerd 1.6.x 配 K8S 1.26 是没问题的但你要是拿着很旧的容器运行时配新集群各种诡异报错就来了。实操心得不要小看版本兼容性。K8S 每个版本都有自己支持的 kubelet/API 版本范围升级前务必看官方弃用与变更说明否则跨大版本升级时 API 兼容问题能让你崩溃一整晚。2.2 网络、存储与运行时的三件套选择一个集群要真正能用光把 control plane 拉起来还不够网络插件CNI、存储插件CSI、容器运行时这三样必须想好。容器运行时现在官方主推 containerdDocker 也能用但 Kubernetes 1.24 之后已经不再直接支持 Docker 作为运行时要通过 cri-dockerd 桥接。新项目直接用 containerd 就好省一层中间转换镜像管理和日志排查反而更稳。CNI 插件里Flannel 最简单适合小规模集群但功能少不支持网络策略。Calico 是生产环境最常见的选择支持 NetworkPolicy性能也不错BGP 模式下大规模跨节点通信更高效。Cilium 是后起之秀基于 eBPF性能很好但上手门槛略高。我日常用的最多的是 Calico按 IPIP 模式跑网络问题排查起来相对顺手。存储这块水更深。无状态应用直接挂 emptyDir 就行数据不需要持久化中间件类应用建议用云厂商的云盘或者自建的 NFS/PVC。Rook-Ceph 适合想自己搭软件定义存储的场景但运维成本确实高不是团队有矿不建议小规模硬上。如果只是给 GPU 训练任务放数据集可以考虑把数据集放到对象存储Pod 启动时再拉取这样存储成本和副本管理都轻松很多。2.3 工作负载控制器的合理分工很多新手接触 K8S 时以为 Deployment 就是全部反正都是跑容器。实际上 K8S 的工作负载控制器是分场景设计的用错了后面运维很难受。无状态服务用 Deployment这是最常用的多个副本之间没有身份区别滚动升级、回滚都很方便。有状态服务用 StatefulSet比如数据库、消息队列它给每个 Pod 一个稳定网络标识和独立存储卷Pod 重建后身份和存储都不变。每个节点必须跑一个的采集器、日志代理用 DaemonSet比如 node-exporter、fluent-bit节点加进来它就自动部署节点移除它自动清理。批处理任务用 Job定时跑数用 CronJob比如训练前的数据预处理、定时清理任务。站在“算力架构”的视角这个分工特别关键。训练任务通常是短时间高消耗的用 Job 或者配合 Argo Workflow 做编排任务跑完 Pod 自动结束资源释放。在线推理服务是常驻的用 Deployment 加 HPA根据 GPU 利用率和请求 QPS 自动扩缩容。模型预热、指标采集这类节点级任务用 DaemonSet 省心。我见过有人把数据库直接用 Deployment 部署一个滚更新就把主从全冲了这种坑真心疼。2.4 调度器与 GPU 算力分配方式算力架构里最重要的部分就是 GPU 怎么被 K8S 调度。默认情况下 K8S 调度器只看 CPU 和内存GPU 这种扩展资源需要设备插件Device Plugin来上报。NVIDIA 官方提供了 nvidia-device-plugin部署成 DaemonSet 之后每个带 GPU 的节点会把自己有多少张卡上报给 kubelet你在 Pod 里面就能通过nvidia.com/gpu: 1这样的字段申请算力。表面看起来很简单但实际使用有几个关键细节。第一GPU 资源不能超卖你申请 1 张卡就是独占 1 张卡Pod 之间不会共享显存调度器会保证同一张卡不会被分配给两个 Pod。第二节点打标要清晰把 GPU 型号、显存大小写到标签里比如gpu-typeA100、gpu-memory40Gi调度时用 nodeSelector 精确匹配。第三如果你要跑 CUDA/推理任务镜像里必须带对应的驱动版本和 CUDA runtimeK8S 可不负责给你装驱动节点上的 GPU 驱动版本决定了你镜像能跑什么。GPU 调度的另一个实践是“显存感知”。默认的 device-plugin 只报“有卡没卡”不感知显存剩余量那就要借助 NVIDIA MIG多实例GPU或者 GPU 显存调度方案来实现一张卡跑多个小任务。比如把一张 A100 切成 7 个 MIG 实例每个实例都有独立显存和计算单元配合 K8S 的扩展资源调度单卡利用率能大幅提升。我做推理服务混部时就是这个思路一个 A100 节点上能同时跑三四个小模型成本直接砍半。3. 集群搭建与核心配套实操3.1 三节点高可用集群搭建要点三 master 高可用是生产环境的入门配置核心要解决两个问题apiserver 的入口高可用以及 etcd 的数据一致性。apiserver 是无状态的前面用负载均衡把流量分发给多个 master 就行常见方案是 keepalived haproxy 或者 kube-vip。etcd 则比较讲究推荐用“堆叠式 etcd”也就是 etcd 和 master 共存每个 master 上跑一个 etcd 实例三个 etcd 自动组成集群多数派写入保证一致性。如果你用 kubeadm 搭建整体步骤大概是先在负载均衡节点配好 VIP 和健康检查然后初始化第一个 master再依次把第二、第三个 master 加入最后把 worker 节点 join 进来。关键点是kubeadm init时通过--control-plane-endpoint指定 VIP 地址所有 master 和 worker 都用这个地址访问 apiserver。worker 节点的 kubelet 拿到的是 VIP这样即使某个 master 挂掉负载均衡会把请求转发给存活节点集群对外表现始终稳定。注意etcd 的磁盘性能直接决定集群稳定性。尽量给 etcd 单独配 SSD并且不要让 etcd 数据盘和应用日志混用。之前我遇到过 etcd 延迟飙高查到最后是同一块盘上还有大量容器日志在写把 IO 吃满了。生产环境第一次跑通之后别急着上线先把备份做了。etcd 备份、master 节点配置备份、存储类定义备份该写脚本写脚本。我有一次手滑删错了 namespace全靠 etcd 快照救回来的那次之后我就把“先备份再操作”写进了团队的操作规范。3.2 证书过期自动续签K8S 集群的证书是个很容易被忽视的定时炸弹。kubeadm 默认签发的证书有效期只有一年到期之后 kubelet 无法和 apiserver 通信表现为节点 NotReadykubectl 命令也开始报 x509 证书过期错误。最麻烦的是你如果不看日志很难直观判断这是证书问题还是网络问题。解决方法分两个方向。第一个是手动续签执行kubeadm certs renew all更新证书然后重新生成 kubeconfigkubeadm kubeconfig reconfig --kubeconfig/etc/kubernetes/admin.conf接着重启 kubelet 相关组件。这个操作在证书到期前做就行但千万别等到真过期了再做节点都失联了命令都执行不进去。第二个方向是自动化。写一个 systemd timer 或者 CronJob定期检查证书剩余时间临近 90 天时自动执行续签。K8S 社区也有 cert-manager 这类开源项目但 cert-manager 主要用于管理 Ingress 的 TLS 证书集群内部证书比如 kubelet 证书还得靠 kubeadm 自带的机制。我的建议是集群证书用 kubeadm renew 定时脚本Ingress 证书用 cert-manager Let‘s Encrypt 自动签发和续期两条线各管各的。实战排查技巧遇到节点连续 NotReady先用kubectl logs -n kube-system kubelet容器看日志如果出现certificate has expired or is not yet valid基本可以直接判定证书问题不用再绕去看网络。另外kubeadm certs check-expiration这个命令可以直接列出所有证书的剩余时间养成定期巡检的习惯很重要。3.3 Prometheus 监控部署监控体系是算力架构里最容易“事后补课”的部分我强烈建议集群刚搭好就部署。主流方案是 kube-prometheus-stack一个 Helm chart 里集成了 Prometheus、Alertmanager、Grafana、node-exporter 和 kube-state-metrics装完就有一个能看全集群状态的监控大屏。核心链路是node-exporter 采集节点指标kubelet 内置的 cAdvisor 采集容器指标kube-state-metrics 把 K8S 对象状态Pod 数量、Deployment 副本、PVC 使用量转换成指标Prometheus 周期性拉取Grafana 负责展示。如果你的网络规模不小建议在采集层加上层级化设计每个节点部署 node-exporter 和 kube-state-metricsPrometheus 通过 serviceMonitor 自动发现目标规则文件里配置好告警阈值。告警规则至少要覆盖四类节点不可用、CPU 使用率过高、内存使用率过高、Pod 频繁重启。GPU 机器还要额外接 DCGM exporter把显存利用率、温度、功耗数据也采进来。仪表盘别只看平均值。我建议重点盯三个节点资源水位、Pod 资源水位、GPU 利用率分布。节点水位决定要不要加机器Pod 水位决定要不要调 requests/limitsGPU 分布决定算力有没有打满。有一次我们排查推理服务响应变慢就是在 Grafana 上看到某节点的 CPU steal 异常升高最后定位到宿主机上还有其他租户在跑重负载这才给了调度器加了反亲和规则。3.4 业务系统部署示例以若依微服务为例业务上云验证阶段我经常用若依微服务这套 Java 微服务做实验因为模块齐全网关、认证、系统管理、文件服务都有正好可以演示 K8S 的多服务编排。大致流程是先把每个模块打成镜像然后为每个模块编写 Deployment、Service、ConfigMap 三件套。以网关模块为例Deployment 声明副本数和资源限制requests设成预测的闲时资源limits设为峰值资源这样调度器有参考数运行时也有护栏。Service 用 ClusterIP 类型做集群内负载均衡每个模块之间通过 service 名访问而不是写死 IP。ConfigMap 放所有模块共享的配置比如 Redis 地址、数据库地址这样改配置不用重新打镜像。最后用 Ingress 把网关暴露到集群外部Traefik 或 Nginx Ingress Controller 都行。健康检查一定要配。readinessProbe 和 livenessProbe 分别负责“是否可对外提供服务”和“是否还活着”配置不对会出现流量打到没启动完的 Pod 上或者容器假死但一直不重启的情况。若依这类 Spring Boot 应用健康检查可以用/actuator/health这个端点initialDelaySeconds 给 30 秒以上等 Java 应用启动完再探活。4. 微服务迁移与高并发验证实录4.1 不停服、不丢数据的迁移思路“准不停服、不丢数据”的迁移是微服务迁移里最考验架构的事。当时拿到这个需求单节点 K8S 上的若依微服务整套环境要迁到阿里云 ECS 上业务不能断数据不能丢迁完还要用 JMeter 压测验证承载能力。我的核心思路是“双跑互备、灰度切换”。先在阿里云 ECS 上新起一套 K8S 集群包括三个 master 和若干 worker同时把镜像仓库也迁移或同步过去。应用层用 Deployment 编排新旧两套环境同时运行通过 Ingress 或者负载均衡的权重配置逐步切流量先切 1% 验证连通性再切 10%、50%最后全量。每切一档观察错误率和响应时间确认没问题再继续。数据层的“不丢数据”是另一个难点。数据库不能直接用停库导出导入的方式那肯定停机。常规做法是使用数据库的主从复制或者云厂商的数据迁移服务让旧库和新库保持数据同步等切换窗口到来时短暂暂停写入确认两边数据一致再进行最终切换。这里有一个经验切换前一定做一次数据校验关键表行数对比、最大值时间戳对比都要看别只依赖同步工具的同步状态。4.2 配合 JMeter 做高并发压测迁移完成后压测人员用 JMeter 脚本做高并发验证这一步本质是给新集群做“极限体检”。压测不能上来就怼 1000 并发那是乱来。我当时定的节奏是阶梯式加压先 50 并发跑 5 分钟再 100、200、500每次观察几个核心指标TPS、平均响应时间、错误率、Pod CPU/内存水位。每个梯度跑完停下来分析数据再升下一档。JMeter 脚本里要重点关注几个参数线程组里的线程数决定并发量Ramp-Up Period 决定启动时间循环次数决定单线程请求数。比如 500 并发、Ramp-Up 30 秒意思是 30 秒内逐步建起 500 个线程模拟真实用户慢慢爬坡的效果比瞬间全部发起更接近真实场景。每个 Sampler 后面我习惯加一个断言响应时间超过阈值就标记为失败这样能直观看到“从哪个并发量开始劣化”。压测过程中一定要同时开监控。Grafana 上盯集群水位JMeter 的聚合报告看 TPS 和响应时间。数据要按梯度记录成表格比如“并发数、平均响应、P99 响应、TPS、错误率、CPU、内存”这组数据既是迁移验收的依据也是后续做容量规划的底稿。4.3 瓶颈定位与扩容策略一次压测跑下来最常见的瓶颈有三个方向。第一个是应用自身比如数据库连接池满了、代码里有慢 SQL表现为 TPS 上不去但 CPU 还有余量第二个是资源水位节点 CPU 或内存被打满表现为 Pod 被驱逐、响应时间陡增第三个是中间件比如 Redis 连接数打满、Ingress 转发能力到顶表现为整体超时。定位顺序我一般先从监控看资源水位排除了硬件问题再往应用层查。比如压测时发现 TPS 在 300 上不去了但节点 CPU 只有 60%那问题大概率不是集群不够而是应用线程池或数据库瓶颈。这时候再用 Arthas 或者看线程栈定位到具体阻塞点该调连接池调连接池该优化 SQL 优化 SQL。集群层扩容也有章法。worker 节点横向扩容是最直接的加机器之后调度器会把部分 Pod 调度过去。如果需要快速扛住峰值可以先调低镜像的 CPU requests提高单节点 Pod 密度但这会降低隔离性压测通过后要记得回调。对于没有状态的服务优先打开 HPA配置好 CPU 指标和最小/最大副本数让它自己扩缩省掉半夜爬起来加节点的人工操作。5. 常见问题与排查技巧实录5.1 高频故障速查表下面这张表是我这些年处理过的高频问题整理症状、可能原因、处理方式一条条列出来遇到类似情况可以先对照排查。症状可能原因处理方式Pod 一直 Pending节点资源不足、调度约束不满足kubectl describe pod看调度事件检查 requests 是否超过节点可分配CrashLoopBackOff启动命令错误、配置缺失、健康检查失败看日志kubectl logs --previous检查 ConfigMap 和启动参数ImagePullBackOff镜像名错误、仓库认证失败kubectl describe pod看镜像拉取详情检查 Secret 和镜像 tag节点 NotReadykubelet 异常、证书过期、资源耗尽先看 kubelet 日志验证证书有效期检查磁盘 inode跨节点访问不通CNI 异常、安全组限制检查 Calico 的 pod 状态用calicoctl node status验证CoreDNS 解析不稳定CoreDNS 副本不足、节点 DNS 配置问题检查 CoreDNS Pod 状态扩容副本数检查/etc/resolv.confService 不通Selector 不匹配、端口配置错误kubectl get endpoints看是否有后端检查 Service 端口和目标端口GPU Pod 一直 Pending节点缺少 device-plugin、GPU 资源不足确认 nvidia-device-plugin 是否运行kubectl describe node看 GPU 可分配数5.2 高效排查套路与常用命令排查 K8S 问题有个固定套路我称之为“三层看现场”。第一层看对象概览kubectl get pods -n namespace一眼扫出哪些不是 Running。第二层看事件kubectl describe pod pod调度失败、镜像拉取失败、健康检查失败原因都会写在这。第三层看日志kubectl logs -f pod [--previous]业务层的问题多数在这里露出真相。容器运行时的排查也要顺手。用 containerd 时crictl ps -a能列出所有容器比 docker ps 更贴近 K8S 视图crictl logs containerId可以直接看容器日志省得进 Pod 再执行命令。节点资源占用可以直接用kubectl top nodes和kubectl top pods它会实时显示 CPU、内存的实际使用量结合 requests/limits 判断是调度问题还是运行问题。我还习惯把几个高频操作做成小脚本一键查看所有 namespace 的健康状态、一键清理 Evicted Pod、一键导出某个 Deployment 的完整 yaml。这些脚本不复杂但能省很多重复敲命令的时间。特别是清理 Evicted 的僵尸 Pod命令是kubectl get pods --all-namespaces | grep Evicted | awk {print $1, $2} | xargs -L1 kubectl delete pod -n写进脚本后每次排查都顺手跑一遍。5.3 管理工具与服务网格的补充集群多了以后纯命令行管理确实效率低。KubeSphere、Rancher、Lens 这些管理界面我都试过KubeSphere 和 Kubekey 配合得好装完自带多集群管理、日志查询、告警配置入口适合团队协作。Rancher 老牌稳定多集群切换体验好。Lens 是桌面端工具看资源、看日志、连终端都很快适合单人多集群的场景。选择一个团队统一的入口能减少很多“谁在哪个节点上敲了什么命令”的混乱。服务网格这块热点里提到的 Dubbo MeshK8S Service Mesh是微服务治理的方向之一。它的思路是把流量管理、服务发现、负载均衡这些能力从业务代码里抽出来下沉到 Sidecar 代理。Spring Cloud 或者 Dubbo 的应用想上 Service Mesh需要梳理清楚现有服务发现机制迁移成本不低。如果团队规模不大我建议先把 K8S 原生 Service 用熟再去碰 Service Mesh否则一下子引入太多抽象层线上问题排起来会让你怀疑人生。最后分享一点个人体会。回看这几年的经历K8S 算力架构真正的难点一直不在“怎么把集群建起来”而在“怎么在长尾运维中不出事”。我见过太多团队集群搭得很漂亮但证书忘了续、监控没配告警、GPU 节点没有打标结果一上线就手忙脚乱。在建集群的那一天就把备份、监控、证书巡检、资源规划这些配套事项全部落地后面才会真正省心。如果这篇文章能让你少踩几个我当年踩过的坑那就算值了。
返回列表