CCE 集群 HPA 自动扩缩容落地实践
CCE 集群 HPA 自动扩缩容落地实践
查询服务的手动扩容问题
我们有一个内部查询服务跑在 CCE 集群里,白天流量平稳,午休和晚上压测时 CPU 会突然抬高。最初 Deployment 固定 3 个副本,值班同学看到告警后手动 kubectl scale,从告警到扩容完成经常要五六分钟。等压测峰值过去,又容易忘了缩容,节点资源一直占着。
这次要解决的就是这件事。CPU 平均利用率超过阈值,服务自动加 Pod;峰值过去后自动回收,同时避免频繁抖动。
实验环境与前提
我这次使用的是 CCE 标准集群,Kubernetes 版本 1.25.3,节点池为 3 台 c6.xlarge.2,规格 4 vCPU 8 GiB。操作系统是 EulerOS 2.9,容器引擎 containerd 1.6。本地 kubectl 版本 1.25.6,集群已安装 metrics-server 插件 0.6.4。
集群使用 VPC 网络,节点子网和安全组只放通节点间通信、apiserver 到 kubelet 的 10250 端口,未对公网开放。HPA 依赖 metrics-server 提供 Pod CPU/内存指标,所以我先确认指标链路可用,再部署带 resources.requests 的工作负载。所有实验都放在 demo 命名空间,避免影响生产业务。
配置与压测步骤
确认 metrics-server 和资源指标
先创建命名空间,再检查指标接口。
kubectl create namespace demo
kubectl top nodes
kubectl get pods -n kube-system | grep metrics-server
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
kubectl create namespace demo 创建独立命名空间。接着用 kubectl top nodes 查看节点实时 CPU/内存,能返回数据,说明 metrics-server 基本可用。
kubectl get pods -n kube-system 过滤 metrics-server Pod,确认其处于 Running。再用 kubectl get --raw 直接访问聚合 API,返回 JSON 才说明 HPA 能拿到指标。如果这里报 404 或 ServiceUnavailable,先停下来修指标链路,不要继续配 HPA。
部署带 requests 的 Deployment 和 Service
我用一个 nginx 示例模拟查询服务。这里必须写 requests.cpu,后面计算 CPU 利用率要用到它。
apiVersion: apps/v1 # 使用 Deployment 的稳定 API
kind: Deployment # 声明工作负载类型
metadata:
name: web-demo # Deployment 名称,供 HPA 引用
namespace: demo # 放到独立命名空间
spec:
replicas: 2 # 初始副本数,HPA 接管后可变化
selector:
matchLabels:
app: web-demo # 选择器必须与 Pod 标签一致
template:
metadata:
labels:
app: web-demo # Pod 标签
spec:
containers:
- name: nginx # 容器名
image: nginx:1.25-alpine # 压测用镜像
ports:
- containerPort: 80 # 暴露 HTTP 端口
resources:
requests:
cpu: 100m # HPA CPU 利用率的分母,必须有
memory: 128Mi # 调度预留内存
limits:
cpu: 500m # 防止单 Pod 打满节点
memory: 256Mi # 内存上限
应用配置,然后创建 Service。
kubectl apply -f web-demo.yaml
kubectl expose deployment web-demo -n demo --name=web-demo --port=80 --target-port=80
kubectl get pods -n demo -o wide
kubectl apply 提交 Deployment,kubectl expose 创建 ClusterIP Service。其中 --port=80 是 Service 端口,--target-port=80 是容器端口,压测 Pod 通过 http://web-demo 访问。部署后用 kubectl get pods -o wide 检查,确认 Pod 已 Running,并且落在可用节点上。
创建 HPA v2
我使用 autoscaling/v2,方便后续加 behavior。
apiVersion: autoscaling/v2 # v2 支持 behavior 和更多指标
kind: HorizontalPodAutoscaler # 声明 HPA 对象
metadata:
name: web-demo-hpa # HPA 名称
namespace: demo # 与工作负载同命名空间
spec:
scaleTargetRef:
apiVersion: apps/v1 # 指向 Deployment API
kind: Deployment # 扩缩对象类型
name: web-demo # 与 Deployment 名称一致
minReplicas: 2 # 最小副本,避免缩到 0
maxReplicas: 6 # 最大副本,控制成本
metrics:
- type: Resource # 使用资源指标
resource:
name: cpu # 以 CPU 为扩缩信号
target:
type: Utilization # 按 requests 的百分比计算
averageUtilization: 50 # 平均达到 50% 触发扩容
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 缩容前观察 5 分钟,减少抖动
执行配置,持续观察 HPA。
kubectl apply -f web-demo-hpa.yaml
kubectl get hpa web-demo-hpa -n demo -w
kubectl apply 创建 HPA。通过 kubectl get hpa -w 可以持续查看 TARGETS,同时留意 MINPODS、MAXPODS 和 REPLICAS。
这里的 requests 是 100m,averageUtilization: 50 表示每个 Pod 平均 CPU 超过 50m 就倾向于扩容。缩容则留一点时间,stabilizationWindowSeconds: 300 让 HPA 先观察 5 分钟,避免压测刚停就立刻缩容。
压测并观察扩缩容
启动 3 个 busybox 副本,循环访问 Service。
kubectl create deployment loadgen -n demo --image=busybox:1.36 --replicas=3 -- /bin/sh -c "while true; do wget -q -O- http://web-demo; done"
kubectl get pods -n demo -l app=web-demo
kubectl get hpa web-demo-hpa -n demo -w
kubectl top pods -n demo
kubectl create deployment 创建压测客户端,--replicas=3 让压力更明显,while true 负责循环请求 Service。
压测跑起来后,用 kubectl get pods -l app=web-demo 查看业务 Pod 数量变化,再通过 kubectl get hpa -w 看 HPA 是否把副本从 2 提到 4、5、6。还要看一眼 kubectl top pods,确认 CPU 确实升高了。
压测结束后删除 loadgen,等待缩容窗口,观察副本回落,再清理实验资源。
kubectl delete deployment loadgen -n demo
kubectl delete -f web-demo-hpa.yaml
kubectl delete -f web-demo.yaml
kubectl delete svc web-demo -n demo
遇到的问题与解决
HPA 创建成功后,TARGETS 却显示 <unknown>/50%,一直不扩缩容。我之前只看了 Deployment,没有检查 metrics-server 的 APIService。继续排查才发现,metrics-server Pod 因插件异常没有 Ready,聚合 API 拿不到 Pod 指标。我先执行 kubectl get apiservice v1beta1.metrics.k8s.io -o yaml 和 kubectl get pods -n kube-system | grep metrics-server,然后在 CCE 控制台重装 metrics-server 插件。等 kubectl top pods -n demo 有数据后,再重建 HPA。
旧 Deployment 没写 resources.requests.cpu,也会卡住。即使 kubectl top pod 明明有 CPU 数据,HPA 仍显示 0%/50% 或 <unknown>。HPA 的 Utilization 按 requests 的百分比计算,缺了 requests 就算不出利用率。给容器补上 requests.cpu,再滚动更新即可。配置是否补上,可以用 kubectl get deploy web-demo -n demo -o jsonpath='{.spec.template.spec.containers[*].resources.requests.cpu}' 快速确认。
压测停止后,副本很快掉回去,随后少量请求又把 CPU 顶起来,出现轻微抖动。针对缩容缺少观察窗口的问题,我把 HPA v2 里的 behavior.scaleDown.stabilizationWindowSeconds 设为 300 秒,同时把 maxReplicas 控制在 6,避免异常流量把副本打满。
小结
这次改造后,查询服务在压测峰值能从 2 个 Pod 扩到 5 到 6 个,峰值过后按 5 分钟窗口缩回,值班同学不再手动 scale。
自动扩缩容也有代价。requests 必须配得比较准,配大了浪费资源,配小了 HPA 会过于敏感。metrics-server 成了关键依赖,节点容量也得留余量,否则 HPA 扩出 Pod,节点却调度不上。
这套配置适合无状态 HTTP 服务,CPU 指标相对稳定,启动也比较快。有状态服务、启动慢或突发流量极短的服务,应该配合定时扩容、节点池自动扩缩容,再采用更保守的 behavior。
先把 metrics-server 和 requests 做对,再上 HPA。上线前一定压测,并用 maxReplicas、stabilizationWindowSeconds 控制成本和抖动。
- 点赞
- 收藏
- 关注作者
评论(0)