应用场景
云容器引擎提供Pod 水平自动扩缩(HPA)能力,水平自动扩缩能够根据指标自动更新工作负载资源 (例如 Deployment 或者StatefulSet)的副本数, 目的是自动扩缩工作负载以满足需求。在云容器引擎控制台支持配置基础资源(CPU、内存)和自定义指标(网络、磁盘等)作为Pod扩缩容的触发条件。
前提条件
已创建专有版集群,具体操作请参见 用户指南 > 集群管理 > 新建集群 章节。若已有集群,无需重复操作。
通过基础指标(CPU、内存)进行Pod的水平自动伸缩
步骤一 安装cube-metrics-server 插件
云容器引擎在插件市场提供了cube-metrics-server插件,cube-metrics-server是基于Kubernetes官方提供metrics-server二次开发的插件,支持通过CPU、内存进行HPA的能力;
登陆云容器引擎控制台,进入需要操作的集群,在左侧菜单选择 插件 > 插件市场,选择cube-metrics-server进行安装
步骤二 配置HPA策略
登陆云容器引擎控制台,进入需要操作的集群,在左侧菜单选择 工作负载 并选择进入对应的工作负载页面,以下以无状态工作负载为例,点击需要伸缩的工作负载右侧的更多按钮,选择弹性伸缩,开启指标伸缩按钮
点击启用策略,指标名称可选CPU和内存,计值方式为百分比;填写伸缩的指标阈值及副本数的伸缩范围,点击确定创建HPA策略
通过预置的高阶指标(网络、磁盘等)进行 Pod的水平自动伸缩
步骤一 安装cube-prometheus和cube-metrics-adapter插件
通过预置的高阶指标(如网络、磁盘等)依赖监控cube-prometheus和cube-metrics-adapter插件
登陆云容器引擎控制台,进入需要操作的集群,在左侧菜单选择 插件 > 插件市场,选择cube-metrics-adapter插件进行安装
需要注意的是如果集群的监控插件为ccse-monitor,需要修改values中metricsProvider.mode参数为ccse-monitor
步骤二 配置HPA策略
登陆云容器引擎控制台,进入需要操作的集群,在左侧菜单选择 工作负载 并选择进入对应的工作负载页面,以下以无状态工作负载为例,点击需要伸缩的工作负载右侧的更多按钮,选择弹性伸缩,点击 + 号新增自定义指标策略
点击新增Pod规则,在指标名称中输入预置的指标名并设置伸缩的预置及副本数伸缩范围,点击确定创建HPA策略。云容器引擎提供的预置指标如下列表格所示
云容器引擎提供的预置指标
cpu预置指标
| 指标名称 | 指标对象 | 指标含义 | 指标单位 | 计算公式 |
| k8s_pod_cpu_core_used | Pod | CPU使用量 | 核 | sum(rate(container_cpu_usage_seconds_total{image=~".+",pod=~"$Pod",namespace="$namespace"}[5m])) by (pod) |
| k8s_pod_rate_cpu_core_used_node | Pod | CPU利用率(占节点) | % | (label_replace(sum(rate(container_cpu_usage_seconds_total{name =~ ".+",pod=~"$Pod",namespace="$namespace"}[5m])) by (pod,instance,namespace), "node", "$1", "instance", "(.*)")) / on(node) group_left sum(kube_node_status_allocatable{resource="cpu"}) by (node) * 100 |
| k8s_pod_rate_cpu_core_used_request | Pod | CPU利用率(占request) | % | sum(rate(container_cpu_usage_seconds_total{image=~".+",pod=~"$Pod",namespace="$namespace"}[5m])) by (pod) / (sum (kube_pod_container_resource_requests{resource="cpu",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
| k8s_pod_rate_cpu_core_used_limit | Pod | CPU利用率(占limit) | % | sum(rate(container_cpu_usage_seconds_total{image=~".+",pod=~"$Pod",namespace="$namespace"}[5m])) by (pod) / (sum (kube_pod_container_resource_limits{resource="cpu",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
内存预置指标
| 指标名称 | 指标对象 | 指标含义 | 指标单位 | 计算公式 |
| k8s_pod_mem_usage_bytes | Pod | 内存使用量 | Byte | sum (container_memory_usage_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) |
| k8s_pod_mem_no_cache_bytes | Pod | 内存使用量(不含Cache) | Byte | sum (container_memory_working_set_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) |
| k8s_pod_rate_mem_usage_node | Pod | 内存利用率(占节点) | % | (label_replace(sum(container_memory_usage_bytes{name =~ ".+",pod=~"$Pod",namespace="$namespace") by (pod,instance,namespace), "node", "$1", "instance", "(.*)")) / on(node) group_left sum(kube_node_status_allocatable{resource="memory"}) by (node) * 100 |
| k8s_pod_rate_mem_no_cache_node | Pod | 内存利用率(占节点,不含Cache) | % | (label_replace(sum(container_memory_working_set_bytes{name =~ ".+",pod=~"$Pod",namespace="$namespace"}) by (pod,instance,namespace), "node", "$1", "instance", "(.*)")) / on(node) group_left sum(kube_node_status_allocatable{resource="memory"}) by (node) * 100 |
k8s_pod_rate_mem_usage_request
| Pod | 内存利用率(占request)
| % | sum (container_memory_usage_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) / (sum (kube_pod_container_resource_requests{resource="memory",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
| k8s_pod_rate_mem_no_cache_request | Pod | 内存利用率(占request,不含Cache) | % | sum (container_memory_working_set_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) / (sum (kube_pod_container_resource_requests{resource="memory",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
| k8s_pod_rate_mem_usage_limit | Pod | 内存利用率(占limit) | % | sum (container_memory_usage_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) / (sum (kube_pod_container_resource_limits{resource="memory",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
| k8s_pod_rate_mem_no_cache_limit | Pod | 内存利用率(占limit,不含Cache) | % | sum (container_memory_working_set_bytes{image=~".+",pod=~"$Pod",namespace="$namespace"}) by (pod) / (sum (kube_pod_container_resource_limits{resource="memory",pod=~"$Pod",namespace="$namespace"}) by (pod))*100 |
网络预置指标
| 指标名称 | 指标对象 | 指标含义 | 指标单位 | 计算公式 |
| k8s_pod_network_receive_bytes_bw | Pod | 网络入带宽 | Byte/s | sum(irate(container_network_receive_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_network_transmit_bytes_bw | Pod | 网络出带宽 | Byte/s | sum(irate(container_network_transmit_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_network_receive_bytes | Pod | 网络入流量 | Byte/s | sum(rate(container_network_receive_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_network_transmit_bytes | Pod | 网络出流量 | Byte/s | sum(rate(container_network_transmit_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_network_receive_packets | Pod | 网络入包量 | 个/s | sum(irate(container_network_receive_packets_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_network_transmit_packets | Pod | 网络出包量 | 个/s | sum(irate(container_network_transmit_packets_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
硬盘预置指标
| 指标名称 | 指标对象 | 指标含义 | 指标单位 | 计算公式 |
| k8s_pod_fs_read_times | Pod | 硬盘读IOPS | 次/s | sum (irate(container_fs_reads_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_fs_write_times | Pod | 硬盘写IOPS | 次/s | sum (irate(container_fs_writes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
| k8s_pod_fs_read_bytes | Pod | 硬盘读流量 | Byte/s | sum (rate(container_fs_reads_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m]))by (pod) |
| k8s_pod_fs_write_bytes | Pod | 硬盘写流量 | Byte/s | sum (rate(container_fs_writes_bytes_total{image=~".+", namespace=~"$namespace", pod=~"$pod"}[5m])) by (pod) |
GPU预置指标
| 指标名称 | 指标对象 | 指标含义 | 指标单位 | 计算公式 |
|---|---|---|---|---|
| pod_gpu_utilization | Pod | 计算Pod中GPU核心利用率的平均值 | % | avg(DCGM_FI_DEV_GPU_UTIL{job_namespace=~"$namespace"}) by (pod) |
| pod_gpu_memory_utilization | Pod | 计算Pod中GPU显存的利用率 | % | round( sum(DCGM_FI_DEV_FB_USED{job_namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod) / sum(DCGM_FI_DEV_FB_TOTAL{job_namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod) * 100 ) |
| pod_gpu_memory_node_utilization | Pod | 计算Pod使用的GPU显存占整个节点总显存的百分比 | % | round( sum(DCGM_FI_DEV_FB_USED{job_namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, Hostname, job_namespace) / on(Hostname) group_left sum(DCGM_FI_DEV_FB_TOTAL) by (Hostname) * 100 ) |
| pod_gpu_memory | Pod | 计算Pod当前使用的GPU显存量 | % | sum(DCGM_FI_DEV_FB_USED{job_namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod) |
| pod_gpu_usage | Pod | 计算GPU利用率的总和 | % | sum(DCGM_FI_DEV_GPU_UTIL{job_namespace=~"$namespace"}) by (pod) / 100 |
| pod_gpu_usage_node_utilization | Pod | 计算Pod消耗的GPU核心利用率总和,占节点可分配GPU数量的平均比例 | % | round( label_replace( sum(DCGM_FI_DEV_GPU_UTIL{job_namespace=~"$namespace"}) by (pod, job_namespace, Hostname), "node", "$1", "Hostname", "(.*)" ) / on(node) group_left sum(kube_node_status_allocatable{resource="nvidia_com_gpu"}) by (node) ) |
基于自定义指标的HPA水平伸缩配置
使用自定义度量指标为工作负载配置HPA时,最重要的前提是:工作负载对应的Pod通过/metrics接口暴露自定义指标。若工作负载(如nginx、redis、tomcat等)本身不支持该功能,则需借助Sidecar或Exporter方式实现指标暴露。
注意
自定义度量指标依赖于cube-metrics-adapter插件搜集自定义指标并上报至应用性能监控(APM)侧。如需使用自定义度量指标,请先安装cube-metrics-adapter与cube-prometheus插件。
根据自定义指标的来源及归属对象,可将其划分为Pod度量指标和Object度量指标。
Pod度量指标与Pod绑定,HPA会获取所有目标Pod的该指标值并计算算术平均数,再与设定的目标值进行比较。该指标与资源度量指标相似,但仅支持平均值。
Object度量用于描述同一命名空间中除Pod之外的其他Kubernetes对象(如Service或Ingress),该对象的指标为单一的绝对值,HPA会直接将其与设定的目标值进行比较,而不进行副本数均摊计算。
Pod度量指标和Object度量指标示例如下:
使用自定义指标进行HPA的操作步骤
步骤一 安装依赖插件
自定义指标的采集与存储依赖于cube-metrics-adapter和cube-prometheus插件,需提前安装。
步骤二 确保应用对外暴露/metrics接口
以traefik应用为例,通过"–metrics.prometheus=true"启动参数启用指标暴露后,访问pod ip的8080端口的/metrics路径,即可获取标准的指标数据。
步骤三 配置采集任务
以部署在default命名空间下创建的traefik无状态工作负载和traefik-svc服务为例,若需采集Pod度量指标和Object(Service)度量指标,则需分别为traefik的Pod和Service配置自定义采集规则。以pod度量指标为例说明如下:
登录应用性能监控(APM)控制台,点击左侧菜单栏的Prometheus监控。
在Prometheus监控菜单下,点击接入管理。
在已接入环境页签,查看容器环境列表,点击目标容器环境操作列的指标采集按钮,进入指标采集页面。
切换到Pod Monitor页签,点击新增。
输入YAML示例如下,请根据工作负载所在命名空间、工作负载标识标签、采集路径及端口的实际情况进行修改。填写完毕后可点击检查进行语法检查,检查无误后点击创建。
apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: pod-monitor1 namespace: default #建议修改为工作负载对应的命名空间 annotations: arms.prometheus.io/discovery: 'true' spec: selector: matchLabels: app: traefik # 修改为唯一能标识该工作负载的Pod标签 namespaceSelector: any: true podMetricsEndpoints: - interval: 30s targetPort: 8080 # 修改为Pod对外暴露metrics指标的端口 path: /metrics # 修改为Pod对外暴露metrics指标的url路径1~3分钟后点击刷新按钮,若查看匹配的Target数量不为0,即表示配置成功。更多信息可参考应用性能监控帮助文档。
切换到Service Monitor页签,可以对Service进行配置。更多信息可参考应用性能监控帮助文档。
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: service-monitor1
namespace: default #建议修改为工作负载对应的命名空间
annotations:
arms.prometheus.io/discovery: 'true'
spec:
endpoints:
- interval: 15s
port: '8080' # 修改为Service对外暴露metrics指标的端口
path: /metrics # 修改为Service对外暴露metrics指标的url
namespaceSelector:
any: true
selector:
matchLabels:
app: traefik # 修改为唯一能标识该工作负载的Pod标签步骤四 配置自定义采集规则
以traefik为例,traefik会暴露traefik_entrypoint_requests_total指标,该指标为Counter(计数器)类型,用于在Pod维度计算单Pod的QPS。针对计算Pod在2分钟内QPS平均增长率的场景,编写对应的自定义采集规则。
- seriesQuery: 'traefik_entrypoint_requests_total'
metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)
name:
as: traefik_requests_total
resources:
overrides:
namespace: { resource: "namespace" }
pod: { resource: "pod" }把该规则添加到cube-metrics-adapter的configmap中,操作步骤如下:
登录云容器引擎控制台,选择指定集群后进入集群详情页。
点击左侧菜单栏的“配置管理”-“配置项”,切换到kube-system命名空间,搜索“cube-metrics-adapter”,点击编辑。
在config.yaml中rules下新增上述自定义采集规则配置,建议先将原有内容复制到文本编辑器中,添加采集配置后再粘贴回配置值。
修改完cube-metrics-adapter自定义采集规则后,需要重启cube-metrics-adapter pod使之生效。点击左侧菜单栏的“工作负载”-“容器组”,切换到kube-system命名空间,搜索“cube-metrics-adapter”,点击“销毁重建”。
步骤五 使用自定义指标创建HPA
以default命名空间下的traefik为例,操作步骤如下:
点击左侧菜单栏的“工作负载”>“无状态”,切换至default命名空间。
搜索应用名称“traefik”,在操作栏点击“更多”>“弹性伸缩”。
点击启用策略,根据实际业务需求配置实例范围,同时可在伸缩配置中自定义扩缩容行为。填写自定义指标,该指标名称对应于cube-metrics-adapter ConfigMap配置文件中
name.as的值;根据指标类型选择Pod类型或Service类型;根据实际业务需求设置计算方式为平均值或阈值,以及对应的阈值范围。点击确定,提交创建HPA。
步骤六 验证HPA生效
点击左侧菜单栏的“策略”,选择“HPA策略”页签,切换至default命名空间,搜索应用名称“traefik”。在列表中可见HPA的最新状态为“正常”,点击操作栏中的“事件”,事件列表中无异常记录。
登录至具有kubectl命令执行权限的集群节点,执行
kubectl describe hpa -n default traefik命令,可见Metrics的当前(Current)采集项有数据(数值为0是因为无流量访问),而非Unknown,即表明HPA配置成功。使用traefik Service的ClusterIP对应用进行访问压测。
随着压测的进行,查看HPA事件与工作负载页面,均可见副本数扩容至3。
停止压测后,副本数逐渐缩容直至稳定。