基于Kubernetes的AI算力平台——大规模集群运维篇
本文参考了 OpenAI Scaling Kubernetes to 2,500 nodes 和 Scaling Kubernetes to 7,500 nodes 两篇文章,再结合自己在大规模集群运维方面的经验,给大家一些最佳实践以及建设大规模集群的运维需要哪些能力。
Kubernetes 最佳实践
ETCD
ETCD是控制面的核心组件,主要负责集群状态存储,对性能和稳定性的要求是非常高。
我们需要做:
- 使用性能最高的SSD。
- 拆分ETCD集群:将Kubernetes中的Event存储在单独的ETCD集群。进而降低主ETCD集群的压力。
- 增加quota-backend-bytes大小,ETCD默认存储默认2G,需要改为8G。
- 开启auto-compaction-retention:开启自动压缩,由于MVCC机制,历史版本需要定期压缩清理。
- 注意心跳周期 heartbeat-interval和选举超时时间 election-timeout 两个参数的设置,防止由于网络带来的频繁选主的问题。
- 做好数据备份。
社区解决方案:Kstone 。该项目源自腾讯内部大规模 etcd 集群治理和最佳实践,很好的实现了对各类业务场景下的 etcd 集群的可视化管理和运维,极大简化了各类场景的 etcd 运维复杂度,将帮助你及时发现各种潜在的 etcd 集群隐患,显著提高 K8s 和 etcd 集群的稳定性和数据安全性,助力业务更稳更快运行。
APIServer
很多组件都会和APIServer交互,其挂掉,对于整个集群的影响是比较大的。所以:
- 横向增加副本数,纵向增加CPU和内存的设置。内存是一定要给足,防止大查询导致OOM。
- 做好限流:合理配置全局限流和精细化限流。
- 减少不避免的连接。比如各种daemonset形式部署的agent。其实很多agent连接APIServer,只是为了获取本Node的Pod信息。需要将获取方式改为从本Node的Kubelet 组件接口获取。
- 采用正常的方式获取对象。使用 Informer,不要使用list,尤其是all namespace。
- 引入专门定制的七层网关,解决请求不均衡的问题。
社区解决方案:kubegateway
CoreDNS
CoreDNS 是 Kubernetes 的核心组件,支持内部域名解析。我们需要做:
增加应用的反亲和性,防止coredns调度到一台主机上
coredns 所需要的资源非常小,所以很容易调度到一台主机上。coredns是一个系统组件,我们应该尽量让coredns分散部署,增强其可用性。
选择合理的coredns扩缩机制
默认是部署两个coredns 实例,但是当我们集群逐步变大的时候,2个实例是不能满足需求的。因而coredns的伸缩就非常重要了。切记coredns千万不要用hpa来弹性伸缩coredns。频繁的伸缩,会导致业务很多dns解析失败的情况。需要用
cluster-proportional-autoscaler组件,我一般是选择根据node节点数来伸缩dns。具体的伸缩策略大家可以选择。
社区解决方案:
cluster-proportional-autoscaler
Kubelet
- 做好系统组件的资源预留,防止雪崩。
容器和镜像
为了加速容器拉取镜像和启动速度,主要是:
- Dockerfile的优化,优化镜像大小。
- 镜像的懒加载。
- 镜像P2P分发。
- Docker挂载的盘使用SSD。
- 业务Pod不要写大量的数据到docker盘。
社区解决方案:
镜像懒加载 stargz
镜像P2P分发 Dragonfly
其他
- 清理不再使用的CR资源。
- 如果使用cluster autoscaler,控制加入集群节点的速度。
大规模集群运维
对于大规模集群的运维,核心主要是两点:
- 建设覆盖所有核心组件的监控体系,基于监控数据,做到故障快速发现。
- 提升自动化运维能力,减少故障处理时间,降低故障影响,做到故障快速处理。
监控
核心组件包括硬件设备以及系统组件,需要覆盖这些核心组件。并配置好报警策略,打通oncall系统。
实际上,OpenAI遇到的很多问题都是prometheus相关的问题。比如经常OOM。实际上,基于prometheus构建一个高可用的监控架构,主要需要做到以下几点:
- 采集和查询分离。
- 减少不避免label,减少series。
- 预聚合。
具体大家可以看我的一些分享:
- 利用Prometheus 打造企业分布式监控平台(1)--扩展性
- 利用Prometheus 打造企业分布式监控平台(2)--服务发现
- 利用Prometheus 打造企业分布式监控平台(3)--远程读写之战
- 利用Prometheus 打造企业分布式监控平台(4)--Recording Rules
- 利用Prometheus 打造企业分布式监控平台(5)--数据模型
- 利用Prometheus 打造企业分布式监控平台(6)--用Telegraf解放Exporter运维
- 利用Prometheus 打造企业分布式监控平台(7)--Thanos和VictoriaMetric
- 利用Prometheus 打造企业分布式监控平台(8)--VictoriaMetrics集群
- 利用Prometheus 打造企业分布式监控平台(9)--最后的洼地Alertmanager
社区解决方案:主机监控 node exporter 、 GPU监控 dcgm exporter 。
除了metrcis监控,在 Kubernetes中也需要将event监控起来。利用kube-eventer项目,将一些重要的event 持久化下来,一方面可以对接报警系统,另外一方面便于分析故障。
在Kubernetes中,有一些主机级别的问题,比如:
- 基础架构守护程序问题:ntp服务关闭;
- 硬件问题:CPU,内存或磁盘损坏;
- 内核问题:内核死锁,文件系统损坏;
- 容器运行时问题:运行时守护程序无响应
当kubernetes中节点发生上述问题,在整个集群中,k8s服务组件并不会感知以上问题,就会导致pod仍会调度至问题节点。
为了解决这个问题,我们需要引入node-problem-detector,从各个守护进程收集节点问题,并使它们对上游层可见。一旦上游层面发现了这些问题,我们就可以讨论补救措施。
自动化运维
简单来说,我们主要需要将人工运维方式固化成程序。
主要有:
- 使用 cluster autoscaler 组件管理节点,负责新增或是减少节点。新增节点环节,需要增加预检的步骤。减少节点需要严格执行排空操作。
- 需要有一套完善的故障监测+备用机器自动替换故障机器以及故障机器下线维修的机制。对于GPU节点来说,由于GPU的故障率比较高,更是依赖该机制。
- 基于Kubernetes申明式控制和CRD机制,我们可以编写一些运维operator,自动执行一些常规的运维操作。比如英伟达提供了NVIDIA GPU Operator,该 operator 可以自动管理所依赖的组件(包括开启CUDA、GPU device plugin 、NVIDIA Container Toolkit、用于监控的DCGM、使用GFD自动给Node节点打标以及其他)。
比如实际场景中,我们通过污点的方式划分了多个资源池。每个集群会存在一个buffer池,该池主要放置了一定量的备用机器。当某个资源池中有机器发生了故障,cluster autoscaler 自动从buffer池选择机器放置到对应的buffer池。进而该资源池的作业可以重新训练。当然如果某个资源池长时间空闲机器,cluster autoscaler 也会将空闲机器放置到 buffer池。
未来自动化运维,一定向智能化运维发展。比如故障的提前预测、容量智能管理以及智能报警。
总结
当然大规模集群运维,少不了稳定性管控。比如要做到变更灰度、回退、管控等等。