Kubernetes 1.30版本即将在这个月发布。从2014年开源到现在,Kubernetes已经走过了十年,从一个简单的容器编排工具演变成了云原生时代的操作系统。每一个版本的更新,都在为大规模、高可用、高并发的场景做准备。

这篇文章不想罗列1.30版本的新特性清单(官方文档比我写得清楚),而是想从架构设计的角度,聊聊基于K8s 1.30及以上版本,如何构建一个真正能扛住高并发、保证高可用的生产级集群。这些经验来自于我这几年运维和设计大规模K8s集群的踩坑经历,希望能对正在做类似事情的朋友有所帮助。

控制面高可用:etcd是命根子

很多人谈K8s高可用,首先想到的是多副本部署、Pod反亲和、滚动更新这些应用层面的东西。但实际上,K8s集群的高可用首先是控制面的高可用,而控制面的核心是etcd。

etcd是K8s集群的"单一事实来源",所有的集群状态数据都存在etcd里。如果etcd出了问题,整个集群就会失控:API Server无法读写数据,Scheduler无法调度Pod,Controller Manager无法正常工作。所以etcd的高可用是整个集群高可用的基础。

在1.30版本中,etcd的性能和稳定性又有了一些改进,但基本的架构原则没有变。生产环境中,etcd应该部署为奇数节点的集群(通常是3个或5个),分布在不同的物理机或可用区上,避免单点故障。etcd节点之间通过Raft协议保持数据一致性,只要超过半数的节点存活,集群就能正常工作。

除了多节点部署之外,etcd的性能优化也很重要。etcd是一个强一致性的分布式KV存储,写操作需要同步到多数节点,所以延迟对性能影响很大。生产环境中,etcd应该使用SSD磁盘,最好是本地SSD而不是网络存储,因为etcd对磁盘IO延迟非常敏感。同时要监控etcd的磁盘同步延迟(walfsyncdurationseconds和dbcommitdurationseconds),如果这些指标持续偏高,说明磁盘性能不够,需要升级。

API Server是控制面的入口,所有的请求都要经过它。API Server应该多副本部署(至少3个),前面挂一个负载均衡器。API Server本身是无状态的,可以水平扩展。但要注意,API Server的性能瓶颈通常在etcd上,因为所有的写操作最终都要落到etcd。所以在高并发场景下,单纯增加API Server的副本数不一定能提升性能,还需要优化etcd和调整API Server的参数(比如请求限流、队列长度等)。

Scheduler和Controller Manager在高可用部署中需要选主(leader election)。同一时间只有一个leader在工作,其他的作为standby。这种模式保证了不会有多个调度器同时调度造成冲突,但也意味着Scheduler和Controller Manager不能水平扩展。如果调度成为瓶颈(比如集群规模很大、Pod创建很频繁),需要考虑调度器的性能调优,比如增加调度周期、调整调度算法、使用调度器扩展等。

数据面高并发:节点和Pod的艺术

控制面解决了"管得过来"的问题,数据面要解决的是"扛得住"的问题。高并发场景下,数据面的设计直接决定了集群能承载多少流量。

首先是节点的选择和规划。K8s节点不是越多越好,也不是越大越好。节点太少,单节点压力大,故障影响面大;节点太多,管理成本高,Pod调度碎片化。一般来说,每个节点的CPU和内存资源要根据业务类型来定。计算密集型业务可以用CPU较多的节点,内存密集型业务可以用内存较大的节点。同时要预留足够的系统资源(kubelet、容器运行时、系统进程占用的资源),不要把节点塞得太满。

在1.30版本中,Kubelet的资源管理能力又有增强。比如CPU管理策略的static策略可以把独占CPU分配给延迟敏感的工作负载,内存管理策略可以减少内存碎片化。这些特性在高并发场景下很有用,可以减少资源竞争带来的性能抖动。

Pod的设计是高并发架构的核心。首先要合理设置资源请求(requests)和限制(limits)。requests用于调度,保证Pod能被分配到有足够资源的节点上;limits用于限制,防止单个Pod占用过多资源影响其他Pod。在高并发场景下,limits的设置尤其重要,否则一个失控的Pod可能把整个节点的资源吃光。

其次是Pod的副本数和分布。高可用要求Pod不能都调度到同一个节点上,要用反亲和性(podAntiAffinity)把Pod分散到不同的节点、不同的可用区。同时要设置合理的副本数,根据流量的峰值来算,还要考虑节点故障时的容量冗余。比如如果有3个可用区,每个可用区至少要能承载全部流量的50%以上,这样一个可用区挂了,剩下的两个还能扛住。

HPA(水平Pod自动扩缩容)是应对流量波动的重要手段。在1.30版本中,HPA支持基于自定义指标和外部指标的扩缩容,可以根据QPS、队列长度、业务延迟等指标来动态调整副本数。但HPA不是万能的,它有扩缩容的延迟(指标采集、计算、Pod启动都需要时间),对于突发流量的响应不够快。所以在高并发场景下,通常需要HPA配合集群自动扩缩容(Cluster Autoscaler)和预热机制来使用。

网络:高并发的隐形瓶颈

很多人在设计K8s高并发架构的时候,把注意力都放在了计算和存储上,却忽略了网络。实际上,网络往往是高并发场景下最先成为瓶颈的地方。

K8s的网络模型要求每个Pod有独立的IP,Pod之间可以直接通信。这个模型的实现依赖于CNI插件。不同的CNI插件在性能、功能、复杂度上有很大差异。在高并发场景下,CNI插件的选择非常重要。

目前主流的CNI插件中,Calico和Cilium是性能比较好的选择。Calico基于BGP路由,性能接近原生网络,支持网络策略。Cilium基于eBPF,性能更好,功能更丰富,支持更精细的可观测性和安全策略。在1.30版本中,K8s对eBPF的支持进一步增强,Cilium也越来越成为主流选择。

Service的实现方式也会影响性能。默认的kube-proxy用iptables来实现Service的负载均衡,在Service和Endpoint数量很多的时候,iptables规则会非常庞大,影响性能。在高并发场景下,可以考虑用IPVS模式的kube-proxy,IPVS的性能更好,支持更多的负载均衡算法。或者用Cilium等基于eBPF的方案,完全绕过iptables,性能更好。

Ingress是集群流量的入口,也是高并发的关键。Ingress Controller的选择和配置直接影响集群能承载的入口流量。Nginx Ingress是最常用的,但在超高并发场景下,可能需要考虑Envoy(Istio的Ingress Gateway)、HAProxy、Traefik等性能更好的方案。同时Ingress Controller本身也要多副本部署、分散到不同节点,前面再挂一层负载均衡器。

Service Mesh(比如Istio)在高并发场景下是一把双刃剑。它提供了丰富的流量管理、安全、可观测性能力,但Sidecar代理会带来额外的延迟和资源开销。在延迟敏感的高并发场景下,需要仔细评估Sidecar的性能影响,或者考虑使用无Sidecar的方案(比如Cilium Service Mesh、Istio的Ambient模式)。

存储:有状态服务的高可用

K8s最初是为无状态服务设计的,但现在越来越多的有状态服务(数据库、消息队列、缓存等)也跑在K8s上。有状态服务的高可用和高并发,是K8s架构设计中的难点。

StatefulSet是K8s中有状态服务的标准部署方式。它提供了稳定的网络标识、稳定的存储、有序的部署和扩缩容。但StatefulSet本身不保证高可用,它只是提供了一些基础能力,具体的高可用还是要靠应用本身来实现。比如数据库的主从复制、消息队列的集群模式、缓存的分片和副本等。

存储类(StorageClass)和持久卷(PV)的选择很重要。在高并发场景下,存储的性能直接影响有状态服务的表现。本地存储(Local PV)性能最好,但可用性差,节点挂了数据就丢了。网络存储(比如Ceph、GlusterFS、云厂商的云盘)可用性好,但性能受网络影响。需要根据业务对性能和可用性的要求来选择。

在1.30版本中,K8s的存储能力又有增强。比如Container Storage Interface(CSI)的功能更完善,支持快照、克隆、容量扩展等。这些特性在管理有状态服务的时候很有用。但要注意,存储的高可用最终还是要靠底层存储系统来保证,K8s只是提供了编排能力。

对于数据库这类关键的有状态服务,我的建议是:如果团队没有足够的K8s存储运维经验,不如把数据库放在K8s外面,用专门的数据库服务或者自己在虚拟机上部署。K8s适合跑无状态服务和对存储要求不高的有状态服务,把核心数据库放在K8s里需要非常谨慎。

安全与可观测性:高可用的保障

高可用不只是"不出故障",还包括"出了故障能快速发现和恢复"。安全和可观测性是高可用架构中不可或缺的部分。

安全方面,首先要做好RBAC权限控制,遵循最小权限原则。不要给服务账号过大的权限,不要用cluster-admin跑应用。其次要做好镜像安全,使用可信的基础镜像,定期扫描镜像漏洞,不要用latest标签。第三要做好网络隔离,用NetworkPolicy限制Pod之间的通信,默认拒绝,只开放必要的端口。第四要做好Secret管理,敏感信息不要写在镜像里或配置文件里,用K8s的Secret或专门的密钥管理服务。

可观测性是高可用的眼睛。一个没有监控的K8s集群就像一辆没有仪表盘的汽车,跑起来心里完全没底。监控至少要覆盖三个层面:基础设施层面(节点的CPU、内存、磁盘、网络),K8s层面(Pod的状态、重启次数、资源使用、调度情况),应用层面(业务指标、延迟、错误率、QPS)。

Prometheus + Grafana是K8s监控的标准组合。在1.30版本中,K8s的监控指标更丰富了,kubelet、kube-state-metrics、node-exporter提供了大量的指标。但要注意,大规模集群中Prometheus本身也会成为性能瓶颈,需要考虑联邦集群、远程存储、指标降采样等方案。

日志方面,EFK(Elasticsearch + Fluentd + Kibana)或Loki是常用的方案。高并发场景下日志量很大,要做好日志的采样、轮转、归档,不要把所有日志都永久保存。同时要注意日志中的敏感信息,做好脱敏。

链路追踪(Tracing)在微服务架构中非常重要。Jaeger、Zipkin、OpenTelemetry是常用的方案。通过链路追踪,可以快速定位高并发场景下的性能瓶颈和故障点。

写在最后

构建一个高可用高并发的K8s集群,不是一件容易的事情。它涉及控制面、数据面、网络、存储、安全、可观测性等多个方面,每个方面都有很多细节和坑。

K8s 1.30版本带来了一些新的特性和改进,但架构设计的基本原则没有变:消除单点故障、合理规划资源、做好容量冗余、完善监控告警、定期演练故障恢复。这些原则说起来简单,真正做到位需要大量的实践和积累。

我见过太多团队,K8s集群搭起来了,应用也跑起来了,但一到流量高峰就出问题。要么是etcd磁盘不够快,要么是节点资源超卖了,要么是Ingress扛不住,要么是监控缺失故障发现不了。这些问题往往不是K8s本身的问题,而是架构设计和运维经验的问题。

技术在不断进步,K8s的版本在不断更新,但对高可用和高并发的追求是永恒的。希望这篇文章能给正在设计或运维K8s集群的朋友一些参考。如果有不同的看法或者补充,欢迎交流。

最后想说一句:K8s是工具,不是银弹。好的架构不是靠工具堆出来的,而是靠对业务的理解、对技术的掌握、对细节的把控一点一点打磨出来的。