容器水平伸缩
云容器引擎支持在控制台界面上快速创建支持HPA的应用,实现容器资源的弹性伸缩。您也可通过定义HPA(Horizontal Pod Autoscaling)的YAML来进行配置。
注意
HPA依赖于cube-metrics-server插件搜集当前集群中的资源指标数据,开启HPA前请先安装cube-metrics-server插件。
背景信息
HorizontalPodAutoscaler(HPA)的API版本在不同 Kubernetes 版本中经历了多次演进。以下为各API版本号与Kubernetes版本的对应关系。
| HPA版本 | 引入 | 标记废弃 | 彻底删除 |
|---|---|---|---|
| v2beta2 | 1.12 | 1.23 | 1.26 |
| v2 | 1.23 | - | - |
如果您的集群版本低于Kubernetes 1.23,请使用v2beta2版本的HPA。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: nginx如果您的集群版本高于或等于1.23,请使用v2版本的HPA。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx从v1.18开始,K8s v2beta2 API允许通过HPA的behavior字段配置扩缩行为。在behavior字段中的scaleUp和scaleDown分别指定扩容和缩容行为。当您在使用HPA时,希望只进行扩容或者只进行缩容的Pod伸缩,则可以通过开启指标伸缩,单击禁止缩容或者禁止扩容来实现。
默认值:均不禁止
禁止扩容:selectPolicy的值Disabled会关闭给定方向的扩容。因此使用以下策略,将会阻止扩容。
behavior:
scaleUp:
selectPolicy: Disabled禁用缩容:selectPolicy的值Disabled会关闭给定方向的缩容。因此使用以下策略,将会阻止缩容。
behavior:
scaleDown:
selectPolicy: Disabled伸缩规则
HPA总体支持两种度量指标,一种为系统默认指标,支持CPU利用率、内存利用率这两种资源百分比指标;另一种为自定义度量指标,包含Pod度量跟Object度量两大类。
资源度量指标
以CPU为例,配置示意如下:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50自定义度量指标
使用自定义度量指标为工作负载配置HPA时,最重要的前提是:工作负载对应的Pod通过/metrics接口暴露自定义指标。若工作负载(如nginx、redis、tomcat等)本身不支持该功能,则需借助Sidecar或Exporter方式来实现指标暴露。
注意
自定义度量指标依赖于cube-metrics-adapter插件搜集自定义指标上报,如需使用自定义度量指标,请先安装cube-metrics-adapter插件。
根据自定义指标的来源及归属对象,可将其划分为Pod度量指标和Object度量指标。
Pod度量指标与Pod绑定,HPA会获取所有目标Pod的该指标值并计算算术平均数,再与设定的目标值进行比较。该指标与资源度量指标相似,但仅支持平均值。配置示意如下:
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1kObject度量用于描述同一命名空间中除Pod之外的其他Kubernetes对象(如Service或Ingress),该对象的指标为单一的绝对值,HPA会直接将其与设定的目标值进行比较,而不进行副本数均摊计算,配置示意如下:
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: v1
kind: Service
name: main-route
target:
type: Value
value: 2k通过控制台创建HPA
在策略列表页创建HPA
登录云容器引擎管理控制台。
在控制台左侧导航栏,单击集群。
在集群列表页面,单击目标集群名称。
在集群管理页左侧导航栏,选择策略,在策略列表页点击创建HPA策略。
为已有应用开启HPA
登录云容器引擎管理控制台。
在控制台左侧导航栏,单击集群。
在集群列表页面,单击目标集群名称。
在集群管理页左侧导航栏,选择工作负载 - 无状态。
在无状态列表页面选择对应工作负载的操作栏中的更多 - 弹性伸缩。
在创建对话框中,设置伸缩的配置。
通过kubectl命令创建HPA
您可通过编排模板来手动创建HPA,并将其绑定到要伸缩的Deployment对象上,通过kubectl命令实现容器自动伸缩配置。
下面针对一个Nginx应用进行举例。
1、创建并复制以下内容到nginx.yml中。Deployment的编排模板如下。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry-hangzhou7.crs-internal.ctyun.cn/artifact-hub/nginx:1.26-alpine-slim # 使用对应资源池的镜像仓库地址代替
ports:
- containerPort: 80
resources:
requests: # 必须设置,不然HPA无法运行。
cpu: 100m2、执行以下命令,创建Nginx应用。
kubectl create -f nginx.yml
3、创建HPA。通过scaleTargetRef设置当前HPA绑定的对象,在本例中绑定名叫nginx的Deployment。
apiVersion: autoscaling/v2 # 根据Kubernetes集群版本确定apiVersion,低于1.23版本时请使用autoscaling/v2beta2,高于或等于1.23版本时请使用autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx # 建议HPA名称与对应工作负载名称保持一致
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 504、创建好HPA后,再次执行 kubectl describe hpa -n default nginx -hpa 命令,可以看到Metrics (current / target)有具体的数值,说明HPA正常运行。
# kubectl describe hpa nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
CreationTimestamp: Wed, 03 Jun 2026 20:25:06 +0800
Reference: Deployment/nginx
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 0% (0) / 50%
Min replicas: 1
Max replicas: 10
Deployment pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited True TooFewReplicas the desired replica count is less than the minimum replica count
Events:配置缩容到0的HPA
在默认情况下,HPA的minReplicas 最小值为1,意味着即使工作负载完全没有流量,也至少需要保持1个 Pod在运行。
缩容到 0 是指允许 HPA 在满足特定条件时,将工作负载的副本数缩减为 0,即完全停止所有 Pod。这对于以下场景具有重要价值:
成本优化:在非生产环境或非工作时间,完全停止无流量的服务,可大幅降低云资源成本。
资源节约:开发和测试集群中,闲置的应用不再占用计算资源。
事件驱动架构:仅在消息队列或外部事件触发时才启动服务,实现“按需启动”。
HPA 缩容到 0 需要通过 HPAScaleToZero 功能门控启用,Kubernetes 在 v1.23 版本中引入该功能门控(Alpha 特性),默认不开启。直到 Kubernetes v1.36,该功能门控才改为默认开启。当前云容器引擎仅支持白名单用户为托管版集群配置门控特性,如需使用缩容到 0 功能特性,请提工单申请开放。
实现缩容到 0 的核心难点在于“从 0 扩容”。当 Pod 数为 0 时,基于 Pod 自身的指标(如 CPU、内存,或 Pod 级别的自定义指标)将无法获取。因此,HPA 的指标源必须是与 Pod 生命周期解耦的独立对象,如:Object 指标。
| 指标类型 | 数据来源 | 与 Pod 生命周期的关系 | 缩容到 0 支持 |
|---|---|---|---|
| Resource(CPU/内存) | Pod 自身 | 耦合(Pod消失则指标消失) | 不支持 |
| Pods | Pod 自身暴露的指标 | 耦合(Pod消失则指标消失) | 不支持 |
| Object | 独立对象(如Service、Ingress) | 解耦(对象独立于 Pod 存在) | 支持 |
| External | 外部系统(如消息队列、云厂商 API) | 解耦(完全独立) | 支持 |
为了使 HPA 能够设置minReplicas=0 以及从 0 扩容到 1,必须使用一个独立于 Pod 生命周期、持续存在的资源(如 Service)作为指标的“锚点”。即使后端 Pod 全部缩容到 0,该锚点对象依然存在,HPA 可以持续查询其指标值。当指标上升时,HPA 便能感知并触发扩容。
以网关-后端服务场景为例:
业务使用了 traefik 作为网关,网关后端有 backend 业务工作负载,当 backend 业务工作负载CPU使用率为 0、且 traefik 网关中最近 30s 业务流量为 0 时,通过 HPA 触发缩容到 0,traefik 网关中最近 30s 业务流量不为 0 时,通过 HPA 从 0 恢复到 1。
整体架构如下:
各组件职责如下:
1、无状态工作负载 backend,使用了alpine 镜像,启动参数为"sleep infinity",用于模拟后端业务,基于自身 CPU 使用率和 traefik 网关流量改变副本数。
2、无状态工作负载 traefik,使用了 traefik:v3 镜像,启动命令为如下:
--entrypoints.web.address=:8080 # 监听 8080 端口,提供 web 服务入口
--entrypoints.metrics.address=:9100 # 监听 9100 端口,提供 /metrics 指标暴露
--metrics.prometheus=true # 开启监控指标暴露
--metrics.prometheus.entrypoint=metrics # 监控指标访问端点
--metrics.prometheus.addentrypointslabels=true
--metrics.prometheus.addserviceslabels=truetraefik 监听 9100 端口,提供 /metrics 指标暴露,同时监听 8080 端口,提供 web 服务入口。
3、服务 traefik-svc,监听 8080 端口和 9100 端口,通过 selector 绑定无状态工作负载 traefik,同时作为 Object 指标锚点,即使 backend 业务负载 Pod 缩容到 0,该 Service 对象依然存在。
4、cube-metrics-server 插件,负责搜集容器的 CPU、内存指标。
5、cube-metrics-adapter 插件,负责自定义指标的转换,允许用户通过编辑 cube-metrics-server 的 configmap 添加自定义指标。
6、cube-prometheus插件,负责将采集到的指标数据上报到应用性能监控 APM 侧进行存储。
总结操作如下:
1、提工单申请加入白名单,支持在控制台页面为托管集群配置功能门控。
2、给 kube-apiserver、kube-controller-manager 开启功能门控。
3、安装 cube-metrics-server 、cube-metrics-adapter 和 cube-prometheus 插件。
4、创建 traefik 无状态工作负载和 Service。
5、创建 backend 无状态工作负载。
6、配置 cube-metrics-adapter 上报自定义指标。
7、创建 HPA 并触发缩容到 0。
具体操作如下:
1、提工单申请加入白名单,支持在控制台页面为托管集群配置功能门控
在工单-新建工单中发起工单,填写申请将xx租户加入到配置集群门控白名单中
2、给 kube-apiserver、kube-controller-manager 开启功能门控。
点击托管集群名称,进入集群菜单页,切换到配置中心-Kubernetes 原始配置。
对集群服务器配置,选择 HPAScaleToZero=true,点击确认配置。稍等片刻更新完毕后,再对集群控制器配置进行相同操作。
3、安装 cube-metrics-server、cube-metrics-adapter 和 cube-prometheus 插件
在插件市场中搜索 cube-metrics-adapter、cube-metrics-server 和 cube-prometheus 插件并安装,参考插件安装
稍等片刻后检查插件状态为已安装,插件相关 pod 均为 Running 状态且日志中无异常报错,在监控页面能看到监控数据,说明插件安装正常。
4、创建 traefik 无状态工作负载和 Service
在工作负载-无状态页面,切换到 default 命名空间,点击新增Yaml,填写以下 yaml 内容,创建名为 traefik 的无状态工作负载。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
appgroup: traefik
version: v1
name: traefik
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: traefik
version: v1
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: traefik
version: v1
spec:
containers:
- args:
- --metrics.prometheus=true
- --entrypoints.metrics.address=:9100
- --metrics.prometheus.entrypoint=metrics
- --entrypoints.web.address=:8080
- --metrics.prometheus.addentrypointslabels=true
- --metrics.prometheus.addserviceslabels=true
command:
- traefik
image: registry-vpc-crs-huadong1.cnsp-internal.ctyun.cn/artifact-hub/traefik:v3
imagePullPolicy: IfNotPresent
name: traefik
ports:
- containerPort: 8080
protocol: TCP
- containerPort: 9100
protocol: TCP
resources:
limits:
cpu: 200m
memory: 64Mi
requests:
cpu: 200m
memory: 64Mi
securityContext:
allowPrivilegeEscalation: false
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
runAsNonRoot: false
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30在网络-服务页面,切换到 default 命名空间,点击新增Yaml,填写以下 yaml 内容,创建名为 traefik-svc 的 Service,绑定到 traefik 无状态工作负载。(注:Service 的label workload: traefik 是为了后续创建ServiceMonitor时使用)
apiVersion: v1
kind: Service
metadata:
labels:
workload: traefik
name: traefik-svc
namespace: default
spec:
ports:
- name: "8080"
port: 8080
protocol: TCP
targetPort: 8080
- name: "9100"
port: 9100
protocol: TCP
targetPort: 9100
selector:
app: traefik
version: v1
sessionAffinity: None
type: ClusterIP检查工作负载的 pod 状态为 Running,且 Service 的 endpoint 正常指向工作负载的 Pod 地址。
通过工作负载-容器组,远程登录进入到pod中。
执行以下命令进行测试:
# wget -qO- http://127.0.0.1:8080/
wget: server returned error: HTTP/1.1 404 Not Found # 正常输出 404,说明 8080 web 端口已经在监听
# wget -qO- http://traefik-svc:9100/metrics | grep traefik_entrypoint_requests_total
# HELP traefik_entrypoint_requests_total How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.
# TYPE traefik_entrypoint_requests_total counter
traefik_entrypoint_requests_total{code="404",entrypoint="web",method="GET",protocol="http"} 1 # 正常输出指标,指标值为1,说明当前web端点共有1次请求5、创建 backend 工作负载
按步骤 4 中同样方法在 default 命名空间下创建名为 backend 的工作负载,该负载有 3 个 pod 副本。
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: backend
template:
metadata:
labels:
app.kubernetes.io/name: backend
spec:
containers:
- args:
- -c
- sleep infinity
command:
- /bin/sh
image: registry-vpc-crs-huadong1.cnsp-internal.ctyun.cn/artifact-hub/alpine:3.21
name: backend
resources:
limits:
cpu: 50m
memory: 64Mi
requests:
cpu: 50m
memory: 64Mi在有 kubectl 权限的节点上执行 kubectl top pod,可以看到三个业务 pod 的 cpu 使用率均为 0。
# kubectl get pod
NAME READY STATUS RESTARTS AGE
backend-5cff4c8976-fjv46 1/1 Running 0 14m
backend-5cff4c8976-ls9zw 1/1 Running 0 14m
backend-5cff4c8976-rj68q 1/1 Running 0 14m
traefik-67b6768b7d-2tcfp 1/1 Running 0 19m
# kubectl top pod backend-5cff4c8976-fjv46
NAME CPU(cores) MEMORY(bytes)
backend-5cff4c8976-fjv46 0m 0Mi
# kubectl top pod backend-5cff4c8976-ls9zw
NAME CPU(cores) MEMORY(bytes)
backend-5cff4c8976-ls9zw 0m 0Mi
# kubectl top pod backend-5cff4c8976-rj68q
NAME CPU(cores) MEMORY(bytes)
backend-5cff4c8976-rj68q 0m 0Mi 6、配置 cube-metrics-adapter 的 ConfigMap
在左侧菜单栏选择配置管理-配置项,切换到 kube-system 命名空间,搜索 cube-metrics-adapter,然后点击编辑。
把 config.yaml 中内容复制到文本编辑器中,并在 rules: 下增加以下配置
需要增加的配置(在实际业务场景中,需要按实际业务情况进行调整):
- seriesQuery: 'traefik_entrypoint_requests_total{entrypoint="web"}'
resources:
overrides:
namespace: {resource: "namespace"}
service: {resource: "service"}
name:
matches: "traefik_entrypoint_requests_total"
as: "requests_per_30s"
metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[30s])) by (<<.GroupBy>>) * 30更新后的变量值内容:
把更新后的变量值内容填回输入框中进行替换,点击确定,更新 ConfigMap。
到工作负载-无状态中,选择 kube-system 命名空间,搜索 cube-metrics-adapter 工作负载,点击滚动重启。
到应用性能监控 Apm 控制台中,选择左侧 Prometheus监控-接入管理,输入集群名称进行搜索,点击指标采集进入配置页面。
切换到 Service Monitor,点击新增,输入以下配置:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: service-monitor # 按需更改 ServiceMonitor 自定义资源的名称
namespace: default # 按需更改 ServiceMonitor 自定义资源的所在的命名空间
annotations:
arms.prometheus.io/discovery: 'true'
spec:
endpoints:
- interval: 15s # 按需更改指标采集间隔
port: '9100' # 指标采集端口名称,需要与 traefik-svc Service 的指标采集端口的名称保持一致
path: /metrics # 指标采集路径,需要与 traefik-svc Service 的指标采集路径保持一致
namespaceSelector:
matchNames:
- default # Service 所在命名空间,需要与 traefik-svc Service 所在命名空间保持一致
selector:
matchExpressions:
- key: workload # Service 标签 key,需要与 traefik-svc Service 的 label 的 key 保持一致
operator: In
values:
- traefik # Service 标签 value,需要与 traefik-svc Service 的 label 的 value 保持一致保存后查看 apm-prome 命名空间下 target-allocator pod 日志,能看到有类似的日志输出:
{"level":"info","ts":"2026-08-18T11:09:10Z","logger":"allocator","msg":"add target item","allocator":"consistent-hashing","target_hash":"serviceMonitor/default/service-monitor/0192.168.3.47:91004fd2cad7ccfcf73e","job_name":"serviceMonitor/default/service-monitor/0","collectors count":1}1~3 分钟后,匹配 Service 数量和匹配 Target 数量也变成 1。
在指标探索页面输入 traefik_entrypoint_requests_total 能看到有指标数据,说明指标数据成功上报。
7、创建 HPA 并触发缩容到 0。
在策略菜单中,切换到 default 命名空间。
方式一:通过 Yaml 方式创建 HPA,点击 Yaml创建,输入以下 HPA yaml。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-to-zero # hpa 资源名称
namespace: default # hpa 资源所在命名空间
spec:
behavior:
scaleDown:
policies: # 缩容配置
- periodSeconds: 60 # 缩容动作的时间窗口,60 秒内最多只允许执行一次扩缩容动作
type: Pods # 缩容操作维度,按 pod 维度进行缩容
value: 1 # 每次缩容 1 个 pod
selectPolicy: Min # 如有多条缩容策略,选择副本数最小的作为最终副本数
stabilizationWindowSeconds: 60 # 稳定窗口,观察过去的 60 秒的平均指标数据,再决定是否需要再次扩缩容
scaleUp:
policies:
- periodSeconds: 15
type: Pods
value: 2
selectPolicy: Max
stabilizationWindowSeconds: 0
maxReplicas: 5
metrics:
- resource:
name: cpu
target:
averageUtilization: "50" # CPU 平均利用率,超过 50% 时考虑扩容,低于 50% 时考虑缩容
type: Utilization
type: Resource
- object:
describedObject: # Object 指标关联的对象,需要与 HPA 在同一命名空间下
apiVersion: v1
kind: Service
name: traefik-svc
metric:
name: requests_per_30s # Object 指标,对应于cube-metrics-adapter ConfigMap 新增配置中的 as 字段
target:
averageValue: "3" # 30 秒内平均请求量,超过 3 时考虑扩容,低于 3 时考虑缩容
type: AverageValue
type: Object
minReplicas: 0
scaleTargetRef: # 弹性扩缩容作用对象
apiVersion: apps/v1
kind: Deployment
name: backend方式二:通过控制台页面创建 HPA,选择关联的工作负载为 backend,实例范围为 0 到 5,按实际需要配置扩缩容配置。
配置系统策略,新增 CPU 利用率,设置为 10%,新增自定义指标,指标名称对应于 cube-metrics-adapter ConfigMap 新增配置中的 as 字段值,指标类型选择Object,并输入 traefik-svc, 计算方式为平均值,期望值为 3,点击确定保存。
创建完 HPA 资源后,describe hpa 可以看到 pod 逐渐缩容到 0
在 hpa 页面的事件中也能看到成功触发副本数缩容到0。
如果多次在 traefik 的 pod 中访问 web 端点 http://127.0.0.1:8080/,提高最近30秒访问频率,则会成功触发 backend 扩容。