开头先交代一个场景:我自己有一台装k3s的小服务器,跑着几个内部服务,平时流量不算大,但偶尔会有某个接口被定时任务或者爬虫扫到,CPU直接飙满。一开始图省事,手动kubectl scale deployment临时把副本数顶上去,但半夜出问题的时候,爬起来扩副本真的不是人干的事。所以我决定给k3s配上HPA,让副本数自己跟着负载走。
在动手之前,我对HPA的理解还停留在“Kubernetes自带功能,应该开箱即用”的程度。真正开始配置才发现,k3s作为轻量级发行版,在这条路上少了很重要的一环:它默认不装metrics-server。没有它,HPA控制器连Pod当前的CPU占用都读不到,扩缩容就无从谈起。这篇文章把我从“装metrics-server”到“HPA真正跑起来”的完整过程、踩过的坑、以及最后怎么调优都记录下来。内容适合在k3s、K3d、MiniKube这类轻量集群上折腾自动扩缩容的人参考,也适合刚接触HPA、不清楚它到底怎么工作的人对照理解。
1. 为什么k3s上的HPA要先过“缺一个组件”这道坎
1.1 HPA的工作链路:它到底从哪里拿数据
很多人第一次配HPA的时候,直觉是“我创建一个HorizontalPodAutoscaler对象,Kubernetes就会自动帮我扩容”。这句话对,但它忽略了中间的数据链路。HPA不是直接去读容器运行时或者kubelet的原始数据的,它通过Kubernetes的metrics API获取指标,这个API的实现者就是metrics-server。
整条链路是这样的:kubelet内置的cAdvisor负责采集节点上每个容器的CPU和内存使用量,然后metrics-server通过kubelet的摘要接口把这些数据取走,聚合成标准指标,再暴露成一个叫metrics.k8s.io的API。到了这一步,HPA控制器才能通过kubectl top pod同源的那个接口拿到数据,计算期望副本数,最后去修改Deployment的replicas字段。
如果你对这两个概念还不太熟,可以把metrics-server理解成“仪表盘的中枢”:kubelet是各个传感器,负责感知数据;HPA是自动控制系统,负责根据仪表盘的读数决定要不要加机器。传感器有了,中枢没装,自动控制系统就只能看到一片空白。
1.2 k3s和标准Kubernetes在这件事上的差异
标准Kubernetes集群,尤其是云厂商托管的那种,往往会替你装好metrics-server,或者至少给你一个一键开启的选项。k3s出于轻量化的考虑,默认没有内置metrics-server,所以你在k3s上创建HPA时,如果没做任何前置操作,大概率会看到HPA的状态一直是Unable to fetch metrics,事件里反复出现类似failed to get cpu utilization: unable to fetch metrics from resource metrics API的报错。
另外一个k3s特有的情况是:k3s默认自带Traefik作为Ingress Controller,还会有svclb(Service Load Balancer)组件。在小内存节点上,这些系统组件的资源占用是实实在在的。资源紧张的时候,它们会和业务Pod抢CPU,直接影响HPA观察到的业务Pod负载,这一点后面讲排错的时候会再展开。
给k3s装HPA,第一件事不是写YAML,而是先把metrics.k8s.io这条数据链路打通。否则后边所有操作都是空中楼阁。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 装好metrics-server才算拿到扩缩容的“仪表盘”
2.1 安装方式:直接kubectl apply还是塞进k3s的manifests目录
安装metrics-server本身不难,官方仓库提供了现成的components.yaml,一条命令就能部署:
bash复制kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
不过我实际建议你把它放到k3s的自动manifest目录里:
bash复制cp metrics-server.yaml /var/lib/rancher/k3s/server/manifests/
k3s会监控这个目录,自动应用里面的YAML文件。这种方式的几个好处是:节点重启或者k3s服务重新拉起之后,metrics-server会被自动补回来;同时在离线环境下也更方便,你把YAML文件准备好就行,不需要依赖外网。
2.2 最容易踩的坑:kubelet TLS自签名证书校验失败
我第一遍装完metrics-server,等了半天,kubectl top nodes始终没有任何输出。查日志才发现,metrics-server连kubelet时报错了:
code复制E0412 10:21:33.123456 1 scraper.go:140] "Failed to scrape node" err="Get \"https://127.0.0.1:10250/stats/summary?only_cpu_and_memory=true\": x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs"
原因是k3s的kubelet证书是自签名的,metrics-serve
