CCE 集群 HPA 自动扩缩容落地实践

举报
yd_256731678 发表于 2026/10/27 19:18:59 2026/10/27
【摘要】 我们有一个内部查询服务跑在 CCE 集群里,白天流量平稳,午休和晚上压测时 CPU 会突然抬高。最初 Deployment 固定 3 个副本,值班同学看到告警后手动 kubectl scale,从告警到扩容完成经常要五六

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 控制成本和抖动。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。