在安装完k8s相关的部署后,随着业务的发展,比如说电商系统遇到大促,这个时候k8s里面的pod的cpu使用率就会大幅上升,可能会导致cpu使用率达到100%,从而导致系统反应缓慢,甚至不可用,如果使用人工去观察cpu的使用情况,这个不仅费时费力,而且效果也不太好,这个时候k8s提供了一种Horizontal Pod Autoscaler(HPA)的自动扩缩容的方法,在cpu使用量达到预定的百分比时就会自动进行扩容pod,HPA 的工作流程是一个闭环的反馈系统,依赖于以下组件协同工作:
-
指标采集 :Metrics Server 从集群中每个节点的 Kubelet 采集基础的 CPU、内存资源指标。
-
指标查询:HPA 控制器通过 Kubernetes API 定期查询 Metrics Server,获取目标 Pod 的平均资源利用率。
-
计算与决策 :控制器将当前指标与你在 HPA 中设定的目标值进行比较,通过特定公式计算出所需的副本数。
-
执行伸缩 :控制器更新目标工作负载(如 Deployment)的
replicas字段,从而触发 Pod 的创建或销毁。
整个链路可以概括为:Metrics Server -> Kubernetes Metrics API -> HPA Controller -> 调整 Deployment replicas。
同样的我们也是在dockers desktop上面进行HPA的扩缩容验证,
HPA 依赖 Metrics Server 获取 Pod 的 CPU/内存指标。Docker Desktop 默认不包含 Metrics Server,需要手动安装。
1. 安装 Metrics Server
XML
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
2. 修复自签名证书问题(关键步骤)
Docker Desktop 的 Kubelet 证书是自签名的,必须让 Metrics Server 跳过 TLS 验证,否则 HPA 会一直显示 <unknown>。
XML
kubectl patch deployment metrics-server -n kube-system --type='json' -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
3. 验证 Metrics Server 是否正常工作
等待约 1 分钟后执行:
XML
kubectl top nodes
kubectl top pods
如果能正常显示 CPU/内存数据,说明 Metrics Server 已就绪。如果显示 error,请检查 Metrics Server Pod 的日志:kubectl logs -n kube-system deployment/metrics-server。
HPA 必须基于 Pod 的 resources.requests 来计算利用率,因此 Deployment 中必须明确设置 CPU 请求值:
1.设置backend-deployment-hpa.yaml
XML
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-service-pha # Deployment 名称,集群内唯一
labels:
# 【资源标签】用于标识这个 Deployment 对象本身,方便分类、查询和运维管理。
# 注意:这里的标签不会自动传递给 Pod,也不影响 Deployment 管理哪些 Pod。
app: backend-service-pha # 表示这个 Deployment 属于 backend-service-pha 应用
version: v1 # 表示这个 Deployment 管理的是 v1 版本
spec:
selector:
matchLabels:
# 【Pod 选择器】定义该 Deployment 管理哪些 Pod。
# 必须与下面 template.metadata.labels 中的标签完全匹配,否则 Deployment 无法管理 Pod。
# 这里同时匹配 app 和 version,确保不同版本的 Deployment 不会互相干扰。
app: backend-service-pha # 匹配属于该应用的 Pod
version: v1 # 只匹配 v1 版本的 Pod
replicas: 1 # 期望的 Pod 副本数;HPA 可动态调整此值
template:
metadata:
labels:
# 【Pod 标签】Pod 的标签,必须匹配上面的 selector.matchLabels。
# 同时,Service 也通过 app 标签来发现并转发流量。
# version 标签用于 Istio 区分不同版本,后续灰度发布时会在 VirtualService 中引用。
app: backend-service-pha # 表示这个 Pod 属于 backend-service-pha 应用
version: v1 # 表示这个 Pod 是 v1 版本
spec:
containers:
- name: backend-service-pha # 容器名称,在 Pod 内唯一;通常与 Deployment 名称保持一致
image: client-agent-backend:1.3.5 # 容器镜像地址和标签;建议使用明确版本号,避免使用 latest
ports:
- containerPort: 8090 # 容器内部监听的端口;必须与应用程序实际监听的端口一致
resources: # 资源限制配置,HPA 依赖 requests 计算 CPU 利用率
requests: # 最低资源保证;调度器据此选择节点
cpu: 200m # CPU 请求量:200 毫核(0.2 核)
memory: 256Mi # 内存请求量:256 MiB
limits: # 最大资源上限;容器超过限制可能被限流或终止
cpu: 500m # CPU 上限:500 毫核(0.5 核)
memory: 512Mi # 内存上限:512 MiB
---
apiVersion: v1
kind: Service
metadata:
name: backend-service-pha
spec:
ports:
- port: 8090 # Service 对外暴露的端口;集群内其他服务通过该端口访问
selector:
# 【Service 选择器】将流量转发给带有指定标签的 Pod。
# 这里只选择 app 标签,不包含 version,这样 Service 会将流量负载均衡到所有版本的 Pod
# (例如 v1 和未来的 v2),配合 Istio VirtualService 即可实现权重路由。
app: backend-service-pha # 只匹配属于该应用的 Pod,不区分版本
2.配置HPA信息
XML
# HPA 的 API 版本,autoscaling/v2 支持多指标和更精细的扩缩容行为配置
apiVersion: autoscaling/v2
# 资源类型:HorizontalPodAutoscaler(水平 Pod 自动扩缩容)
kind: HorizontalPodAutoscaler
metadata:
# HPA 对象的名称,集群内唯一
name: backend-service-pha
spec:
# 指定要伸缩的目标资源
scaleTargetRef:
apiVersion: apps/v1 # 目标资源的 API 版本,Deployment 属于 apps/v1
kind: Deployment # 目标资源类型,这里是对 Deployment 进行伸缩
name: backend-service-pha # 目标 Deployment 的名称,必须与集群中实际名称一致
# 副本数下限:即使负载很低,也至少保持 1 个 Pod 运行
minReplicas: 1
# 副本数上限:即使负载很高,最多也只能扩展到 5 个 Pod
maxReplicas: 5
# 指标列表:HPA 根据这些指标来决定是否扩容或缩容
metrics:
# 指标类型为 Resource,表示使用 Kubernetes 内置的资源指标(如 CPU、内存)
- type: Resource
resource:
# 指标名称:cpu,表示基于 CPU 使用率进行伸缩
name: cpu
target:
# 目标类型为 Utilization,表示按"利用率百分比"来计算
# 利用率 = Pod 实际 CPU 使用量 / Pod 的 CPU requests
type: Utilization
# 目标平均利用率:50%
# 当所有 Pod 的平均 CPU 利用率超过 50% 时,HPA 会尝试扩容
# 当低于 50% 时,HPA 会尝试缩容(受缩容冷却时间影响)
averageUtilization: 50
有了这些配置后,我们就可以启动了
XML
kubectl apply -f .\backend-deployment-hpa.yaml
kubectl apply -f .\backend-deployment-horizontal.yaml
启动完成后我们可以观察pod的数量,执行下面的命令,我自己的代码里提供了这个接口:
XML
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --image-pull-policy=IfNotPresent --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://backend-service-pha:8090/actuator/health; done"
通过这个查看cpu的使用情况
XML
kubectl get hpa backend-service-pha --watch
会看到随着cpu的使用量增加,pod的数量也会跟这增加,当关闭了接口查询,cpu的使用率就会下降,pod的数量也会跟着减少。
还需要注意的是执行以下命令在spec.template.spec.containers0.args列表末尾添加一行- --kubelet-insecure-tls
XML
kubectl edit deployment metrics-server -n kube-system
有时候我们会拉取Metrics Server 失败, 解决方法:手动拉取镜像到本地,然后重启 Pod。
✅ 解决步骤
1. 查看 metrics-server 使用的镜像
XML
kubectl get deployment metrics-server -n kube-system -o jsonpath="{.spec.template.spec.containers[0].image}"
输出类似:registry.k8s.io/metrics-server/metrics-server:v0.7.x
2. 手动拉取镜像到本地 Docker
XML
docker pull registry.k8s.io/metrics-server/metrics-server:v0.7.7
请将版本号替换为上一步实际查看到的版本。
如果 registry.k8s.io 拉取慢或失败,可以改用国内镜像:
XML
# 从国内镜像源拉取
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.7.7
# 重新打标签为原镜像名
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.7.7 registry.k8s.io/metrics-server/metrics-server:v0.7.7
3. 修改 Deployment 的镜像拉取策略为 IfNotPresent
XML
kubectl patch deployment metrics-server -n kube-system --type='strategic' -p='{"spec":{"template":{"spec":{"containers":[{"name":"metrics-server","imagePullPolicy":"IfNotPresent"}]}}}}'
如果上面这条报错,可以直接 kubectl edit deployment metrics-server -n kube-system,找到 imagePullPolicy 改为 IfNotPresent,保存退出。
4. 重启 Pod 使用本地镜像
XML
kubectl rollout restart deployment/metrics-server -n kube-system
5. 验证
XML
kubectl get pods -n kube-system -l k8s-app=metrics-server
kubectl top nodes
如果 kubectl top nodes 能返回 CPU/内存数据,说明 Metrics Server 正常工作。