Kubernetes 的 HPA 弹性扩缩容
HPA 介绍
扩缩容
扩缩容说明
在实际工作中,业务对资源要求是不断变化的,如:电商平台在六一八, 双十一 或者秒杀活动以及访问
低谷期, 由于资源紧张或者工作负载降低等都需要对服务实例数进行扩缩容操作。
在 Kubernetes 中可以根据当前的资源需求扩缩工作负载。 这让你的集群可以更灵活、更高效地面对资
源需求的变化。
Kubernetes 的扩缩容可以多个级别实现
- CLuster: 调整集群的数量
- Node: 调整节点的资源或者数量
- Pod : 调整 Pod 的资源或者副本数
扩缩容实现
https://kubernetes.io/zh-cn/docs/concepts/workloads/autoscaling/
手动扩缩容
Kubernetes 支持工作负载的Pod手动扩缩。
当你扩缩工作负载时,你可以增加或减少工作负载所管理的副本数量,或者就地调整副本的可用资源。
第一种手段称为水平扩缩容,第二种称为垂直扩缩容。
扩缩工作负载有手动和自动两种方式,这取决于你的使用情况
当Kubernetes集群中资源不能满足要求时,可以针对Pod级别进行手动和自动扩缩容(autoscale)
这两种策略的示例
水平扩缩:运行应用程序的多个实例
水平扩缩可以使用 kubectl 命令行工具完成。 对于垂直扩缩,你需要更新工作负载的资源定义。
- kubectl scale deployments/kubernetes-bootcamp --replicas=6
垂直扩缩:调整分配给容器的 CPU 和内存资源
#https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/resizecontainer-resources/#create-pod-with-resource-requests-and-limits
requests和limits的更改,需要删除重建Pod
apiVersion: v1 kind: Pod metadata: name: qos-demo-5 namespace: demo spec: containers: - name: qos-demo-ctr-5 image: registry.cn-beijing.aliyuncs.com/wangxiaochun/nginx:1.26.0 resources: limits: memory: "500Mi" cpu: "1000m" requests: memory: "200Mi" cpu: "700m"
kubectl apply -f create-pod-with-resource-requests-and-limits.yaml
动态扩缩容
动态(弹性)伸缩是根据用户的业务需求和策略,自动“调整”其“弹性资源”的管理服务。用户可设置定时、
周期或者监控策略,通过弹性伸缩功能,自动的完成增加或减少恰当的弹性资源,并完成实例配置修改
和保证业务平稳健康运行。
Kubernetes 被誉为新一代数据中心操作系统(DCOS),其核心工作也是管理整个集群的计算资源,并
按需合理分配给以Pod为基础的各种workload。其本质是解决资源与业务负载之间供需平衡的问题,随
着业务需求和部署规模的增大,Kubernetes 集群就要相应扩容计算资源,集群扩容的最直接的办法是
新增资源,一般单机器很难垂直扩展(Kubernetes node也不支持),所以一般都是直接增加节点。但
是随着机器的不断增加成本也不断加大,而实际上大量服务大部分时间负载很低导致机器的整体使用率
很低,一方面业务为了应对每日随机流量高峰会把副本数尽量扩得很高,另一方面业务方并不能准确评
估服务实际需要的CPU等资源,也出现大量浪费。
为了充分利用集群现有资源优化成本,当一个资源占用已经很大的业务需要扩容时,其实可以先尝试优
化业务负载自身的资源需求配置(request与实际的差距),只有当集群的资源池确实已经无法满足负载
的实际的资源需求时,再调整资源池的总量保证资源的可用性,这样可以将资源用到极致。
为了解决业务服务负载时刻存在的巨大波动和资源实际使用与预估之间差距,就有了针对业务本身的“弹
性扩缩容”解决方案
弹性伸缩包括:

Cluster-Autoscale
集群容量(node数量)自动伸缩,跟自动化部署相关的,依赖iaas的弹性伸缩,主要用于虚拟机容
器集群
Cluster AutoScaler 定期检测是否有充足的资源来调度新创建的 Pod,当资源不足时会调用 Cloud
Provider 创建新的 Node
#支持的云提供商:
#阿里云:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/alicloud/README.md
#AWS:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/aws/README.md
#Azure:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/azure/README.md
Vertical Pod Autoscaler VPA
Vertical Pod AutoScaler 容器垂直伸缩,动态调整单个Pod的最大资源限制,主要支持有状态服务
的扩缩容和升级场景,由第三方开源组件实现
工作负载Pod垂直(资源配置)自动伸缩,如自动计算或调整deployment的Pod模板
limit/request,依赖业务历史负载指标
Vertical Pod Autoscaler (VPA)使用名为 VerticalPodAutoscaler 的自定义资源定义对象进行配置
#支持的云提供商:
#阿里云:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/alicloud/README.md
#AWS:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/aws/README.md
#Azure:
https://github.com/kubernetes/autoscaler/blob/master/clusterautoscaler/cloudprovider/azure/README.md
#基于CRD实现
https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler
#需要自行安装
https://github.com/kubernetes/autoscaler/blob/master/vertical-podautoscaler/docs/installation.md
#安装方法
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/vpa-release1.0/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/vpa-release1.0/vertical-pod-autoscaler/deploy/vpa-rbac.yaml
#实现Vertical Pod Autoscaler示例:
#https://github.com/kubernetes/autoscaler/blob/master/vertical-podautoscaler/examples/hamster.yaml
Horizontal-Pod-Autoscaler HPA
Horizontal Pod Autoscaler 容器水平伸缩,动态调整Pod的数量,由Kubernetes 内置组件实现
工作负载Pod水平自动伸缩,如自动scale deployment的replicas,依赖业务实时负载指标
cronHPA
Cron Horizontal Pod Autoscaler 容器定时伸缩,主要面向的是周期性负载,预测有规律的负载周
期,并通过周期性伸缩,实现资源成本的节约,由第三方开源组件实现
直接按照cron的格式设定扩容和缩容时间及对应副本数,这种不需要动态识别业务繁忙度属于静态
HPA,适用于业务流量变化有固定时间周期规律的情况,这种比较简单可以算做HPA的一种简单特
例。
Knative Pod Autoscaler KPA
https://knative.dev/docs/serving/autoscaling/
Knative提供了简单易用的自动扩缩容KPA(Knative Pod Autoscaler)功能。您可以基于Pod并发
数(Concurrency)、每秒请求数(RPS)配置自动扩缩容的条件。此外,Knative默认会在没有业
务请求时将Pod数量缩减至0
KPA的主要限制在于它不支持基于CPU的自动扩缩容。
实现原理
Knative Serving会为每个Pod注入一个名为 queue-proxy 的QUEUE代理容器,该容器负责向
Autoscaler报告业务容器的并发指标。Autoscaler接收到这些指标之后,会根据并发请求数及相应
的算法,调整Deployment的Pod数量,从而实现自动扩缩容。
Knative Pod Autoscaler 主要基于观测到的指标(如请求每秒速率、并发请求数等)来决定是否对
Pod 进行扩缩容操作。其工作流程大致如下:
1. 指标收集:KPA 持续从各种数据源(如 Istio、Prometheus 等)收集与应用程序相关的指标
数据。
2. 指标分析:根据收集到的指标数据,KPA 会将其与预先设定的目标值进行比较。例如,若设
定目标是每个 Pod 每秒处理 100 个请求,KPA 会计算当前每个 Pod 实际处理的请求速率。
3. 扩缩容决策:如果实际指标与目标值存在偏差,KPA 会做出相应的扩缩容决策。若当前请求
速率超过目标值,KPA 会增加 Pod 数量;若请求速率低于目标值,KPA 则会减少 Pod 数量。
4. 执行操作:KPA 会与 Kubernetes 的 API Server 进行交互,通过调整 Deployment 或
ReplicaSet 来实现 Pod 数量的动态调整。
支持的指标类型
并发请求数(Concurrency):指每个 Pod 同时处理的请求数量。KPA 可以根据并发请求数
来调整 Pod 数量,确保每个 Pod 不会因处理过多并发请求而导致性能下降。
请求每秒速率(Requests per Second, RPS):表示每个 Pod 每秒处理的请求数量。通过
设置目标 RPS,KPA 可以根据实际的请求速率动态扩缩容 Pod。
其中VPA和HPA都是从业务负载角度从发的优化,VPA是解决资源配额(Pod的CPU、内存的
limit/request)评估不准的问题,HPA则要解决的是业务负载压力波动很大,需要人工根据监控报警来
不断调整副本数的问题,有了HPA后,被关联上HPA的deployment,后续副本数修改就不用人工管理,
HPA controller将会根据业务忙闲情况自动帮你动态调整。
HPA工作机制
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/
https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workloadresources/horizontal-pod-autoscaler-v1/
https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workloadresources/horizontal-pod-autoscaler-v2/
HPA 介绍

HPA全称是 Horizontal Pod Autoscaler,Pod的水平自动伸缩器。也就是对k8s的workload的副本数进
行自动水平扩缩容(scale)机制,也是k8s里使用需求最广泛的一种Autoscaler机制
水平扩缩意味着对增加的负载的响应是部署更多的 Pod。 这与 “垂直(Vertical)” 扩缩不同,对于
Kubernetes, 垂直扩缩意味着将更多资源(例如:内存或 CPU)分配给已经为工作负载运行的 Pod。
如果负载减少,并且 Pod 的数量高于配置的最小值, HorizontalPodAutoscaler 会指示工作负载资源
(Deployment、StatefulSet 或其他类似资源)缩减。
在 Kubernetes 中,HorizontalPodAutoscaler 自动更新工作负载资源 (例如Deployment或者
StatefulSet), 目的是自动扩缩工作负载以满足需求。
水平 Pod 自动扩缩不适用于无法扩缩的对象,例如:DaemonSet
资源决定了控制器的行为。 在 Kubernetes 控制平面内运行的水平 Pod 自动扩缩控制器会定期调整其目
标(例如:Deployment)的所需规模,以匹配观察到的指标, 例如,平均 CPU 利用率、平均内存利用
率或你指定的任何其他自定义指标。
既然是自动根据业务忙闲来调整业务工作负载的副本数,其实HPA的实现思路很容易想到:通过监控业
务繁忙情况,在业务忙时,就要对workload扩容副本数;等到业务闲下来时,自然又要把副本数再缩下
去。
实现水平扩缩容的关键就在于:
- 如何识别业务的忙闲程度
- 使用什么样的副本调整策略
HPA 的 API 的版本
HorizontalPodAutoscaler 被实现为 Kubernetes API 资源和控制器
HorizontalPodAutoscaler 的API 的版本:
- 目前版本 HPA 支持了 autoscaling/v1、autoscaling/v2 两个版本
- 早期版本支持 autoscaling/v1,autoscaling/v2beta1和autoscaling/v2beta2
- autoscaling/v1 这个版本只支持CPU一个指标的弹性伸缩。
- autoscaling/v2 可以支持使用更多的指标,比如CPU,内存等作为扩缩容的标准, 还增加了支持自定义指标和外部指标
范例:
kubectl api-versions |grep autoscaling
HPA 工作机制

HPA 工作流程
- Kubernetes HPA 控制器kube-controller-manager通过 API Server(聚合 API)持续采集所有 Pod 副本的指标数据。
- HPA 基于用户定义的扩缩容规则进行计算,得到目标 Pod 副本数量。
- 当目标 Pod 副本数量与当前副本数量不同时,HPA 控制器就向 Pod 的副本控制器 (Deployment、RC 或 ReplicaSet)发起 scale 操作,调整 Pod 的副本数量,完成扩缩容操作
Kubernetes 将水平 Pod 自动扩缩实现为一个间歇运行的控制回路(它不是一个连续的过程)。间隔由
kube-controller-manager 的 --horizontal-pod-autoscaler-sync-period 参数设置(默认间隔为 15
秒)。
在每个时间段内,控制器管理器都会根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利
用率。 控制器管理器找到由 scaleTargetRef 定义的目标资源,然后根据目标资源的 .spec.selector 标签
选择 Pod, 并从资源指标 API(针对每个 Pod 的资源指标)或自定义指标获取指标 API(适用于所有其
他指标)。
对于按 Pod 统计的资源指标(如 CPU),控制器从资源指标 API 中获取每一个
HorizontalPodAutoscaler 指定的 Pod 的度量值,如果设置了目标使用率, 控制器获取每个 Pod 中的
容器资源使用情况, 并计算资源使用率。如果设置了 target 值,将直接使用原始数据(不再计算百分
比)。 接下来,控制器根据平均的资源使用率或原始值计算出扩缩的比例,进而计算出目标副本数。
需要注意的是,如果 Pod 某些容器不支持资源采集,那么控制器将不会使用该 Pod 的 CPU 使用率。
如果 Pod 使用自定义指标,控制器机制与资源指标类似,区别在于自定义指标只使用原始值,而不是使
用率。
如果 Pod 使用对象指标和外部指标(每个指标描述一个对象信息)。 这个指标将直接根据目标设定值相
比较,并生成一个上面提到的扩缩比例。 在 autoscaling/v2 版本 API 中,这个指标也可以根据 Pod 数
量平分后再计算。
HorizontalPodAutoscaler 控制器访问支持扩缩的相应工作负载资源(例如:Deployment 和
StatefulSet)。 这些资源每个都有一个名为 scale 的子资源,该接口允许你动态设置副本的数量并检查
它们的每个当前状态。
要实现HPA, 必须安装指标系统,比如:metric-server或其它类似服务, 以及在Pod中定义Requests参数
HPA 扩缩容算法
https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-podautoscale/#algorithm-details
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-podautoscale/#algorithm-details

Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例。
期望副本数desiredReplicas=向上取整ceil[当前副本数currentReplicas*(当前指标
currentMetricValue/期望指标desiredMetricValue)]
#ceil 函数表示向上取整 #currentReplicas:当前 Pod 副本数 #currentMetricValue:即取当前所有Pod的平均指标值,HPA 在进行扩缩容决策时,并不是看某一个 Pod 的指标值,而是对所有可用 Pod 的指标做聚合计算,默认使用的是平均值(average) #desiredMetricValue:期望的目标指标值,HPA资源中定义
例如
1)如果当前指标值为 200m ,而期望值为 100m , 因为 200.0 / 100.0 == 2.0 ,因此副本数将加倍
2)如果当前指标值为 50m ,而期望值为 100m ,则副本数将减半, 因为 50.0 / 100.0 == 0.5 。
如果比率足够接近 1.0(在全局可配置的容差范围内,默认为 0.1), 则控制平面会跳过扩缩操作。
说明:
如果 HorizontalPodAutoscaler 指定的是 targetAverageValue 或 targetAverageUtilization , 那
么将会把指定 Pod 度量值的平均值做为 currentMetricValue 。 然而,在检查容忍度和决定最终扩缩
值前,仍然会把那些无法获取指标的 Pod 统计进去
当使用CPU指标进行HPA时,任何还未就绪(例如还在初始化)状态的 Pod 或 最近的指标度量值采集于
就绪状态前的 Pod,该 Pod 也会被搁置,即不统计在内
HPA扩缩容计算过程
#第一步:计算每个 Pod 的 CPU 利用率 每个Pod CPU 利用率 = 当前Pod的实际 CPU 使用量 / CPU request #第二步:对所有 Pod 的利用率求平均值 每个 Pod 平均 CPU 利用率 = (Pod1 利用率 + Pod2 利用率 + ... + PodN 利用率) / N #第三步:用“平均值”参与比例控制公式 期望副本数desiredReplicas = 向上取整【当前副本数currentReplicas × (当前指标=即平均CPU利用 率 / targetCPU利用率 )】
示例1: 单 Pod 利用率
#场景
当前 Pod 副本数:4
每个 Pod 配置:cpu.requests = 200m
每个 Pod 的实际使用:300m
HPA 目标:targetCPUUtilization = 80%
#计算过程
单 Pod CPU的 利用率 = 300 / 200 = 150%
当前平均利用率 = 150%
期望副本数desiredReplicas=ceil(4*150%/80%)=7.5 向上取整 8
示例2:HPA扩缩容计算
#场景
当前 Pod 副本数: 4
每个 Pod 配置:cpu.requests = 200m
#Pod Pod实际CPU
Pod1 300m
Pod2 100m
Pod3 100m
Pod4 100m
HPA 目标:targetCPUUtilization = 80%
#第一步:计算每个 Pod 的 CPU 利用率
#各 Pod 的实际使用情况
Pod 实际CPU CPU使用利用率
Pod1 300m 300/200=150%
Pod2 100m 100/200=50%
Pod3 100m 100/200=50%
Pod4 100m 100/200=50%
#第二步:对所有 Pod 的利用率求平均值
#HPA 的平均值计算
平均利用率 = (150% + 50% + 50% + 50%) / 4 = 75%
#第三步:用“平均值”参与比例控制公式
期望副本数desiredReplicas = ceil[currentReplicas × ( 平均CPU利用率 / targetCPU利用率
)]
期望副本数desiredReplicas = 向上取整【4 × ( 75% / 80% )】=ceil[3.75]=4
#最后结论:无需扩容
controller-manager的HPA 相关配置
--horizontal-pod-autoscaler-sync-period #HPA控制器同步pod副本数的时间间隔,默认值为15s --horizontal-pod-autoscaler-downscale-stabilization: #表示缩容冷却时间。即自从上次缩容执行结束后,多久可以再次执行缩容,默认5分钟,此值可以防止抖动 --horizontal-pod-autoscaler-tolerance #HPA控制器能够容忍的当前值和期望值的数据差异的浮点数,默认值为0.1,即期望的指标与当前的阈值的差异超过0.1以上,即要大于1.1则会触发扩容,或小于0.9则会触发缩容 --horizontal-pod-autoscaler-initial-readiness-delay #设置Pod准备就绪时间,在此时间内的Pod处于未就绪状态并不会采集数据,默认为30秒 --horizontal-pod-autoscaler-cpu-initialization-period #用于设置Pod的初始化时间,在此时间内的Pod的CPU资源度量值将不会被采纳,默认为5分钟
kubectl exec -n kube-system kube-controller-manager-master1.wang.org -- kube-controller-manager --help |grep horizontal-podautoscaler-sync-period
#可以修改如下配置文件
vim /etc/kubernetes/manifests/kube-controller-manager.yaml
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: component: kube-controller-manager tier: control-plane name: kube-controller-manager namespace: kube-system spec: containers: - command: - kube-controller-manager - --allocate-node-cidrs=true - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf - --bind-address=127.0.0.1 - --client-ca-file=/etc/kubernetes/pki/ca.crt - --cluster-cidr=10.244.0.0/16 - --cluster-name=kubernetes - --horizontal-pod-autoscaler-sync-period=30s
HPA 资源管理
需要指标系统实现指标的采集,比如: Metrics Server 或者 Prometheus-Adapter
需部署 Metrics Server 或者Prometheus-Adapter(需要结合Prometheus实现指标采集)其它的以提
供资源监控数据。若未安装,HPA 将无法获取 CPU 指标
Pod 配置资源请求 requests
Deployment 的 Pod 模板需定义resources.requests.cpu
否则 HPA 无法计算 CPU 使用率百分比,提示如下
kubectl describe hpa
kubectl get hpa
当前CPU 利用率的计算公式为:
CPU 利用率 = (实际使用的 CPU 量 / Pod 配置 requests.cpu) * 100%`
#比如: Pod 的 requests.cpu 设置为 100m,实际使用 80m,则 CPU 利用率为 80%
HPA 配置和实现流程
1. 创建Deployment等资源,要求配置Pod的requests
2. 创建HPA资源,设定目标CPU使用率限额,以及最大、最小Pod副本数
3. Metrics Server 或者 Prometheus-Adapter 收集PodSelector中每个Pod最近一分钟内的CPU使用
率,并计算所有Pod的平均值
4. 读取HPA中设定的 CPU使用期望指标desiredMetricValue,计算所有Pod平均值之和/期望指标
desiredMetricValue并向上取整,求出目标调整的实例个数
5. 调整的副本实例数不能超过HPA中设定的最大、最小实例数,如果没有超过最大实例数则扩容;如
果超过最大值则扩容至最大实例个数
6. 不断循环第3步后面的步骤
HPA 创建说明
HPA 创建两种方式
命令式
资源清单方式
命令行创建对象
#TYPE 支持 deployment, replica set, statefulset, or replication controller
#详细解释
1)CPU 使用率计算:CPU 使用率 = (Pod 实际使用的 CPU 量 / 容器配置的 resources.requests.cpu ) * 100%
2)触发自动伸缩:如果所有Pod 的平均 CPU 使用率超过了 --cpu-percent 指定的百分比,HPA 就会增加 Pod 的数量;反之,若低于这个百分比,HPA 会减少 Pod 的数量。
#示例:
kubectl autoscale deployment myapp --cpu 20 --min=2 --max=5 # cpu 20m
kubectl autoscale deployment myapp --cpu 20% --min=2 --max=5 # cpu 20%
#说明
假设在Deployment的 myapp 中,每个 Pod 的 requests.cpu 设置为 0.5(也就是 500m CPU,1 个
CPU 核心等于 1000m)
若某个Pod实际使用的 CPU 量达到了 0.1(即 100m),此时该 Pod 的 CPU 使用率为 (0.1 / 0.5) *
100% = 20%。
当所有Pod的平均CPU使用率与设定的目标值(如 --cpu 指定的值20%)进行比较,超过20%时,HPA 就会开
始进行自动伸缩操作。
#注意:
kubectl autoscale deployment hpa-demo --cpu 20 --min=2 --max=5 --dry-run=client -o yaml
#k8s-v1.33以前版本默认生成为的HPA-v1版本,但在线编辑时 kubectl edit hpa hpa-test 为HPAv2版
PA-v2版本
HPA-v2版本支持各种指标,包括CPU,内存,自定义指标等
#autoscaling/v2 配置说明 #apiVersion: autoscaling/v2beta2 旧版 apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: php-apache namespace: default spec: # HPA的伸缩对象描述,HPA会动态修改该对象的pod数量 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: php-apache # HPA的最小pod数量和最大pod数量 minReplicas: 1 maxReplicas: 10 # 监控的指标数组,支持多种类型的指标共存 behavior: scaleDown: stabilizationWindowSeconds: 30 #缩小稳定窗口为 30 秒,默认值为300s scaleUp stabilizationWindowSeconds: 30 #扩容稳定窗口为 30 秒,默认值为0s metrics: # Object类型的指标 - type: Object object: metric: # 指标名称 name: requests-per-second # 监控指标的对象描述,指标数据来源于该对象 describedObject: apiVersion: networking.k8s.io/v1beta1 kind: Ingress name: main-route # Value类型的目标值,Object类型的指标只支持Value和AverageValue类型的目标值 target: type: Value value: 10k # Resource类型的指标 - type: Resource resource: name: cpu # Utilization类型的目标值,Resource类型的指标只支持Utilization和AverageValue类型 的目标值 target: type: Utilization averageUtilization: 50 #平均利用率 < (所有Pod的实际资源使用总量/所有Pod的资源 resources.requests.cpu的总量×100%)时会扩容,否则缩容 # Pods类型的指标 - type: Pods pods: metric: name: packets-per-second # AverageValue类型的目标值,Pods指标类型下只支持AverageValue类型的目标值 target: type: AverageValue averageValue: 1k # External类型的指标 - type: External external: metric: name: queue_messages_ready # 该字段与第三方的指标标签相关联,(此处官方文档有问题,正确的写法如下) selector: matchLabels: env: "stage" app: "myapp" # External指标类型下只支持Value和AverageValue类型的目标值 target: type: AverageValue averageValue: 30
#HPA-v2版本示例 apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: my-app-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-app-deployment minReplicas: 1 maxReplicas: 10 behavior: scaleDown: stabilizationWindowSeconds: 30 #缩小稳定窗口为 30 秒,默认值为300s,HPA-v1 不支持 此字段 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 60
Kubernetes 的指标系统
Kubernetes API Aggregation
HPA和VPA 控制器的实现都依赖指标数据,需要从一系列的 API 中检索到相应的指标的度量值。
除了Kubernetes API Server 内置的指标外,如果需要自定义指标,还需要扩展Kubernetes的 API
Kubernetes 扩展支持更多API 的方式
- CRD
- APIServer源代码二次开发
- API Aggregation: API聚合额外的API Server,
Kubernetes API Aggregation

在 Kubernetes 1.7 版本引入了API Aggregation Layer,集成在API Server 中, 允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和
操作,用于将扩展 API 的访问请求转发到用户服务的功能。
当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通
过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。
Kubernetes 集群管理员需要确保下述条件,以保证 HPA 控制器能够访问这些 API:
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-podautoscale/#support-for-metrics-apis
启用了 API 聚合层
基于APIService资源的相应的 API 已注册:
对于Kubernetes 内置的资源指标,将使用 metrics.k8s.io API, 一般由 metrics-server将节点和Pod使用CPU和内存两种指标数据暴露出来给HPA和VPA使用。 它可以作为集群插件启动。
https://APISERVER:PORT/apis/metrics.k8s.io/v1beta1/namespaces/default/pods/mypod
对于自定义指标,将使用 custom.metrics.k8s.io API。 它由其他度量指标方案厂商的适配器(Adapter) API 服务器暴露出来给HPA和VPA使用。 检查你的指标管道以查看是否有可
用的 Kubernetes 指标适配器。
https://APISERVER:PORT/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/mypod
对于外部指标,将使用 external.metrics.k8s.io API。 也可能由上面的自定义指标适配器提供。
HorizontalPodAutoscaler 将其配置为从聚合 API (metrics.k8s.io、custom.metrics.k8s.io 或 external.metrics.k8s.io)获取指标。
Kubernetes 的指标系统
为HPA,dashboard,kubectl top 等提供相应的指标相关组件
核心指标流水线
负责支撑Metrics API、生成并提供只包括节点和Pod的CPU和内存的两种核心指标数据的相关组件
自定义指标流水线
负责支撑 Custom Metrics API、生成并提供各种自定义的指标数据的相关组件
核心指标流水线
核心指标流水线
核心指标流水线 Core Metrics Pipeline 负责支撑Metrics API、生成并提供CPU和内存的两种核心指标
数据的相关组件
核心指标流水线主要组件构成:
Kubelet:
作为每个节点上的代理,通过Kubelet内置的cAdvisor组件基于读取容器的控制组cgroups实现负责收集运行在该节点上的 Pod 和容器的资源使用情况,包括 CPU、内存、网络和磁盘 I/O 等指标。
Metrics Server:
是一个轻量级的应用,负责从各个节点的 Kubelet 收集指标数据,并对这些数据进行聚合和存储。
Metrics Server 本身并不持久化存储数据,数据仅在内存中保留较短时间
只收集心资源指标:CPU、内存(及部分存储、网络)
API Server:
作为 Kubernetes 集群的核心控制组件,Metrics Server 会将收集到的指标数据通过自定义的 API端点暴露给 API Server,使得其他组件可以通过 API Server 查询这些指标。
核心指标流水线流程
HPA/kubectl top --> API Serve (metrics.k8s.io/v1beta1) --> Metrics Server --> Kubelet (cAdvisor)

1.指标收集:Kubelet 在每个节点上定期收集 Pod 和容器的资源使用指标,并将这些数据存储在本地。
2. 数据传输:Metrics Server 会定期从各个节点的 Kubelet 拉取指标数据,进行聚合处理。
3. 指标暴露:Metrics Server 将聚合后的指标数据通过 /apis/metrics.k8s.io 这个 API 端点暴露给 Kubernetes API Server。
4. 指标查询:其他 Kubernetes 组件(如 HPA、VPA 等)可以通过 API Server 查询所需的指标数据,以进行自动化决策。
Kubernetes 指标服务器 Metrics Server
Metrics Server 介绍
https://kubernetes-sigs.github.io/metrics-server/
https://github.com/kubernetes-sigs/metrics-server
核心指标流线流程
监控容器资源 --> Kubelet (cAdvisor) --> Kubelet Summary API --> Metrics Server --> metrics.k8s.io API --> HPA / kubectl top / 其他客户端
Kubernetes 有一些依赖于指标数据的组件,例如HPA和VPA等,Kubernetes使用Metrics API暴露系统指标给这些组件
kubernetes提供的metrics接口,HPA controller通过这个统一metrics接口可以查询到任意一个HPA对
象关联的deployment业务的繁忙指标metrics数据,不同的业务的繁忙指标均可以自定义,只需要在对
应的HPA里定义关联deployment对应的metrics即可。
标准的metrics查询接口有了,还需要实现metrics API的服务端,并提供各种metrics数据,k8s的所有
核心组件之间都是通过apiserver进行通信,所以作为k8s API的扩展,metrics APIserver自然选择了基
于API Aggregation聚合层,这样HPA controller的metrics查询请求就自动通过apiserver的聚合层转发
到后端真实的metrics API的服务端(比如:Metrics server 或者 Prometheus adapter)
Kubernetes自身并未提供Metrics API,其功能要借助于名为Metrics Server辅助APIServer提供,并经由Aggregation Layer聚合至主API Server
metrics.k8s.io API 仅提供CPU和内存相关的指标数据,通常由名为 Metrics Server 的插件提供,需要单独启动。
metrics-server
- Metrics Server 是一个受 Heapster 启发并实现的由 Kubernetes SIG 社区维护的项目
- Metrics Server 是 Kubernetes 提供的监控工具,主要用来收集 Node 和 Pod 的 CPU、内存使用情况。其本质就是通过 kube-aggregator 实现的一个 API server。
- Metrics Server 通过将各node端Kubelet提供的metrics接口收集CPU和内存指标,默认每15秒收集一次,并经由Metrics API暴露
- Metrics-Server 将采集到的数据汇总到本地,因为Metrics-Server是没有持久模块的,数据全在内存中所以也没有保留历史数据,只提供当前最新采集的数据查询
- Metrics Server 仅用于HPA和VPA等组件自动扩展目的。例如,不能使用它来将指标转发到监控解决方案,也不要将其用作监控解决方案指标的来源
Metrics Server 提供:
- 适用于大多数集群的单个部署(请参阅要求)
- 快速自动扩展,每 15 秒收集一次指标。
- 资源效率,为集群中的每个节点使用 1 个 mili 内核的 CPU 和 2 MB 的内存。
- 可扩展支持多达 5000 个节点的集群。
Metrics Server 用于:
- 基于 CPU/内存的水平自动扩展(了解有关水平自动扩展的更多信息)
- 自动调整/建议容器所需的资源(了解有关 Vertical Autoscaling 的更多信息)
当您需要时,请不要使用 Metrics Server:
- 非 Kubernetes 集群
- 资源使用指标的准确来源
- 基于 CPU/内存以外的其他资源的水平自动扩展
Metrics Server 部署
https://github.com/kubernetes-sigs/metrics-server
Metrics Server 部署要求
- kube-apiserver必须启用聚合层aggregation layer
- 各节点必须启用(ebhook认证和鉴权机制
- kubelet证书需要由Kubernetes CA签名,或者要使用 --kubelet-insecure-tls 选项禁用证书验证
- Container Runtime需要支持container metrics RPC,或者内置了cAdvisor
- 控制平面节点需要经由10250/TCP端口访问Metrics Server
- Metrics Server需要访问所有的节点以采集指标,默认为kubelet监听的10250端口
范例: 部署metrics-server
#默认无法访问/apis/metrics.k8s.io/v1beta1
kubectl get --raw /apis/metrics.k8s.io/v1beta1
#先安装Metric-server
#官方链接:https://github.com/kubernetes-sigs/metrics-server
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
#默认文件需要修改才能工作,因为默认配置需要内部证书验证和镜像地址k8s.gcr.io所以修改
vim components.yaml
....... containers: - args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls #1)添加本行和下面共两行,不加此行导致Pod无法ready,提 示:Warning Unhealthy 5s (x19 over 2m45s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 500
#2)修改镜像地址,默认registry.k8s.io无法下载
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.8.1 #image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.7.2 #image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.7.1 #image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.3 #image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.1 #image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1
#应用
kubectl apply -f components.yaml
#可以访问API对应的URL路径
kubectl get --raw /apis/metrics.k8s.io/v1beta1
kubectl top nodes
kubectl get pod -A |grep metrics-server
核心指标流水线HPA案例
注意: 提前部署metrics-server, 参看2.2.2小节
https://github.com/kubernetes-sigs/metrics-server
范例:基于CPU实现 HPA-v2
#准备清单文件
[root@master1 hpa]# cat hpav2-cpu-demo.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hpav2-demo-deployment spec: replicas: 3 selector: matchLabels: app: hpav2-demo template: metadata: labels: app: hpav2-demo spec: containers: - name: hpav2-demo-deployment #image: registry.cn-beijing.aliyuncs.com/wangxiaochun/nginx:1.20.0 image: registry.cn-beijing.aliyuncs.com/wangxiaochun/pod-test:v0.1 ports: - containerPort: 80 resources: requests: cpu: "200m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" --- apiVersion: v1 kind: Service metadata: name: hpav2-demo-svc labels: app: nginx spec: ports: - port: 80 name: http selector: app: hpav2-demo --- apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: hpav2-cpu-demo spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpav2-demo-deployment minReplicas: 1 #最小副本数,缩容时不会低于此值 maxReplicas: 10 # 最大副本数,扩容时不会超过此值 metrics: # 定义扩缩指标 - type: Resource resource: name: cpu # 监控CPU资源 target: type: Utilization # 指标目标值设置,使用利用率百分比类型 averageUtilization: 50 # 目标CPU利用率设置为50%,HPA会调整副本数使CPU平均利用率接近此值 #- type: Resource #resource: #name: memory # 监控内存资源 #target: #type: Utilization #averageUtilization: 30 #目标内存利用率设置为30% behavior: scaleDown: stabilizationWindowSeconds: 10 #默认值为300s,缩容等待时间,缩容稳定窗口时间设置为10秒在这段时间内,HPA会观察指标是否稳定在目标值以下
#应用清单
kubectl apply -f hpav2-cpu-demo.yaml
kubectl get hpa
[root@master1 hpa]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: <unknown>/50% 1 10 0 9s
没有人访问 3个副本缩容到1个
[root@master1 hpa]# kubectl get pod NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-c56cbc686-4f26s 0/1 Error 0 62s hpav2-demo-deployment-c56cbc686-cvb2k 0/1 Error 0 62s hpav2-demo-deployment-c56cbc686-szbcc 1/1 Running 0 62s [root@master1 hpa]# [root@master1 hpa]# [root@master1 hpa]# kubectl get pod NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-c56cbc686-szbcc 1/1 Running 0 64s
[root@master1 hpa]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hpav2-demo-svc ClusterIP 10.109.97.175 <none> 80/TCP 3h20m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h
#压力测试访问SVC
#安装压力测试工具
dnf install -y httpd-tools
while true;do ab -c 1000 -n 2000 http://10.109.97.175/;done
root@master1 ~]# kubectl get pod -w NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-c56cbc686-szbcc 1/1 Running 1 (18m ago) 3h32m hpav2-demo-deployment-c56cbc686-6xsqc 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 ContainerCreating 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 ContainerCreating 0 1s hpav2-demo-deployment-c56cbc686-6xsqc 1/1 Running 0 1s
[root@master1 hpa]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 0%/50% 1 10 1 3h32m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 64%/50% 1 10 1 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 0%/50% 1 10 2 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 53%/50% 1 10 2 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 50%/50% 1 10 2 3h33m
[root@master1 ~]# kubectl get pod -w NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-c56cbc686-szbcc 1/1 Running 1 (18m ago) 3h32m hpav2-demo-deployment-c56cbc686-6xsqc 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 ContainerCreating 0 0s hpav2-demo-deployment-c56cbc686-6xsqc 0/1 ContainerCreating 0 1s hpav2-demo-deployment-c56cbc686-6xsqc 1/1 Running 0 1s hpav2-demo-deployment-c56cbc686-fff6p 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-fff6p 0/1 Pending 0 0s hpav2-demo-deployment-c56cbc686-fff6p 0/1 ContainerCreating 0 0s hpav2-demo-deployment-c56cbc686-fff6p 0/1 ContainerCreating 0 1s hpav2-demo-deployment-c56cbc686-fff6p 1/1 Running 0 1s hpav2-demo-deployment-c56cbc686-6xsqc 1/1 Running 0 69s
[root@master1 hpa]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 0%/50% 1 10 1 3h32m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 64%/50% 1 10 1 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 0%/50% 1 10 2 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 53%/50% 1 10 2 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 50%/50% 1 10 2 3h33m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 62%/50% 1 10 2 3h34m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 63%/50% 1 10 3 3h34m hpav2-cpu-demo Deployment/hpav2-demo-deployment cpu: 38%/50% 1 10 3 3h34m
#清理环境
kubectl delete -f hpav2-cpu-demo.yaml
范例:基于内存实现 HPA-v2
[root@master1 hpa]# cat hpav2-memory-demo.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hpav2-demo-deployment spec: replicas: 3 selector: matchLabels: app: hpav2-demo template: metadata: labels: app: hpav2-demo spec: containers: - name: hpav2-demo-deployment #image: registry.cn-beijing.aliyuncs.com/wangxiaochun/nginx:1.20.0 #image: registry.cn-beijing.aliyuncs.com/wangxiaochun/pod-test:v0.1 image: registry.cn-beijing.aliyuncs.com/wangxiaochun/hpa-example ports: - containerPort: 80 resources: requests: cpu: "200m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" --- apiVersion: v1 kind: Service metadata: name: hpav2-demo-svc labels: app: nginx spec: ports: - port: 80 name: http selector: app: hpav2-demo --- apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: hpav2-memory-demo spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpav2-demo-deployment minReplicas: 1 # 最小副本数,无论负载多低都不会低于此副本数量 maxReplicas: 10 # 最大副本数,无论负载多高都不会超过此副本数量 metrics: - type: Resource resource: name: memory # 监控内存资源使用率 target: type: Utilization # 使用利用率百分比类型 averageUtilization: 20 #目标内存利用率设置为20%,HPA会调整副本数使内存平均利用率接近此值 behavior: scaleDown: # 缩容稳定窗口时间设置为10秒 # 在这段时间内,HPA会观察指标是否持续低于目标值 # 默认值为300秒(5分钟),这里缩短为10秒,使缩容响应更迅速 stabilizationWindowSeconds: 10
kubectl apply -f hpav2-memory-demo.yaml
root@master1 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-84c5f4fd4f-2vms6 1/1 Running 0 12s hpav2-demo-deployment-84c5f4fd4f-gf2l9 1/1 Running 0 12s hpav2-demo-deployment-84c5f4fd4f-xxkff 1/1 Running 0 12s
[root@master1 hpa]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 3%/20% 1 10 1 58s
[root@master1 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hpav2-demo-svc ClusterIP 10.98.205.132 <none> 80/TCP 29s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h
while true;do ab -c 1000 -n 2000 http://10.98.205.132/;sleep 1;done
[root@master1 ~]# kubectl get pod -w NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-84c5f4fd4f-gf2l9 1/1 Running 0 2m43s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-c5nmc 1/1 Running 0 3s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-vkpmk 1/1 Running 0 3s
[root@master1 hpa]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 3%/20% 1 10 1 2m46s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 13%/20% 1 10 1 3m1s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 32%/20% 1 10 1 3m16s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 25%/20% 1 10 2 3m31s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 21%/20% 1 10 3 3m47s
[root@master1 ~]# kubectl get pod -w NAME READY STATUS RESTARTS AGE hpav2-demo-deployment-84c5f4fd4f-gf2l9 1/1 Running 0 2m43s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-c5nmc 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-c5nmc 1/1 Running 0 3s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-vkpmk 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-vkpmk 1/1 Running 0 3s hpav2-demo-deployment-84c5f4fd4f-8g2c9 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-8g2c9 0/1 Pending 0 0s hpav2-demo-deployment-84c5f4fd4f-8g2c9 0/1 ContainerCreating 0 1s hpav2-demo-deployment-84c5f4fd4f-8g2c9 1/1 Running 0 8s
[root@master1 hpa]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 3%/20% 1 10 1 2m46s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 13%/20% 1 10 1 3m1s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 32%/20% 1 10 1 3m16s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 25%/20% 1 10 2 3m31s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 21%/20% 1 10 3 3m47s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 22%/20% 1 10 3 4m2s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 24%/20% 1 10 3 4m17s hpav2-memory-demo Deployment/hpav2-demo-deployment memory: 26%/20% 1 10 4 4m32s
#清理环境
kubectl delete -f hpav2-memory-demo.yaml
自定义指标流水线
HPA和Metrics 架构

自定义指标流水线
最早的kubernetes的metrics数据是由metrics-server提供的,只支持Pod使用CPU和内存的指标
除了常见的CPU、内存资源指标以外,用户还需要了解kubernetes中更多的指标数据,比如
Kubernetes 指标、容器指标、节点资源指标以及应用程序指标等等。
后来为了适应更灵活的需求,metrics API开始扩展支持用户自定义metrics指标(custom metrics),
自定义数据则需要用户自行开发custom metrics server,社区有提供专门的custom adpater框架
custom-metrics-apiserver ,该框架定义了Custom和External的MetricsProvider接口,需要自行实现
对应的接口
Kubernetes 如果需要暴露其它指标的API,由Custom Metrics API和External Metrics API 实现


负责支撑 Custom Metrics API、生成并提供各种自定义的指标数据的相关组件,称为自定义指标流水线
自定义指标流水线可以取代核心指标流水线,实现它的基于CPU和内存指标功能,并提供更多自定义的指标
自定义指标流水线需要准备如下组件
prometheus-server
必要组件
采集各种丰富的指标数据:资源、应用性能、业务指标、节点硬件等
默认只能采集Kubernetes 的Node,Pod,endpoint,SVC,Ingress
prometheus-adapter
必要组件
提供custom.metrics.k8s.io和external.metrics.k8s.io 相关API,注册到API聚合层
负责将Prometheus的指标数据转换为Kubernetes的指标格式
kube-state-metrics
可选组件
基于 kubernetes_sd 只能采集Node,Pod,Service,endpoint,Ingress五种资源
使用 kube-state-metrics 可以支持更多类型的Kubernetes 资源,比如:deployment, statefulset,daemonset,pvc等
相当于K8s-exporter功能
Pormetheus 可以做为一个监控系统使用,所需要组件如下
- prometheus-server
- alertmanager
- grafana
- blackbox-exporter
- push-gateway
- node-exporter
- kube-state-metrics
- 其它的exporter
Prometheus 能够直接把 Kubernetes API Server 作为服务发现系统使用进而动态发现和监控集群中的所有可被监控的对象。
这里需要特别说明的是, Pod 资源需要添加下列注解信息才能被 Prometheus 系统自动发现并抓取其内建的指标数据。
prometheus. io/scrape: 用于标识是否需要被采集指标数据, 布尔型值 true 或 false
prometheus. io/path: 抓取指标数据时使用的URL路径, 默认为/ metrics
prometheus. io/port: 抓取指标数据时使用的套接字端口, 如 8080
自定义指标流线流程
Node/Pod/Ingress/Service/Endpoint/Deployment/PV等 ---> Node_exporter / Kube - state-metrics/ Instrumentation/各种Exporters/Pushgateway ---> Prometheus Server ---> Prometheus Adapater (PromQL) ---> API Server (custom.metrics.k8s.io/v1beta1,external.metrics.k8s.io/v1beta1) ---> HPA ---> HPA 扩缩容
Prometheus Adapter
Prometheus Adapter 说明
自定义指标API允许请求任意的指标,其指标API的实现要指定相应的后端的指标监控系统。
最常见的监控工具有Prometheus、Datadog以及Sysdig等。而不同的工具所使用的格式也有所区别。
在使用Kubernetes API聚合来暴露endpoint之前,我们需要将指标转换为合适的格式。
此时需要使用的adapter,它在监控工具和Kubernetes API之间架起了一座桥梁。
例如,Prometheus有专门的Prometheus adapter或者Datadog有Datadog Cluster Agent
它们位于指标监控系统和API之间,并从一种格式转换到另一个种格式
prometheus-adapter

Prometheus 是提供丰富的指标的监控系统。我们可以通过 PromQL 的方式进行查询获取指标数据,
但是由于本身 prometheus 属于第三方的解决方案,原生的k8s系统并不能对 Prometheus 的自定义指标
进行解析,就需要借助于 k8s-prometheus-adapter 项目将这些来自于Prometheus的指标数据查询接口
转换为标准的 Kubernetes 自定义指标。

Prometheus Adapter
https://github.com/kubernetes-sigs/prometheus-adapter
- Custom Metrics API和External Metrics API 要由专用的第三方的API Server提供,例如著名的Prometheus Adapter项目
- Prometheus Adapter 注册至API Server ,使其支持更多的扩展的API 群组:custom.metrics.k8s.io 和external.metrics.k8s.io
- Prometheus Adapter 同时也支持核心流水线API群组metrics.k8s.io,从而可以替换已运行Kubernetes集群上的Metrics Server并收集相应的指标。
- Prometheus Adapter 相当于增强版本的Metrics Server,可以支持包括CPU和内存两种核心指标 以及更多自定义指标
- 适用于 Kubernetes 1.6+ 中的autoscaling/v2 水平 Pod 自动缩放程序。


Prometheus Adapter 部署
方法1: YAML文件部署
https://github.com/kubernetes-sigs/prometheus-adapter/tree/master/deploy
https://github.com/kubernetes-sigs/prometheusadapter/tree/master/deploy/manifests
1. 创建名为custom-metrics的名称空间。
kubectl create namespace custom-metrics
2. 创建一个名为cm-adapter-serving-certs的secret对象,它需要具备serving.crt和serving.key两个键。这些是适配器 adapter用于处理 HTTPS 流量的服务证书,更多的信息,请参考auth concepts
documentation。
可通过如下命令,运行目录中预置的gencerts.sh脚本进行创建此secret 资源
#该脚本依赖于golang的cfssl模块,下面的命令也能在r完成该模块的安装。
wget https://ghfast.top/https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl_1.6.5_linux_amd64
mv cfssl_1.6.5_linux_amd64 cfssl
chmod +x cfssl
mv cfssl /usr/local/bin/
cd prometheus-adpater/
bash gencerts.sh
[root@master1 prometheus-adpater]# ls -l manifests/ total 48 -rw-r--r-- 1 root root 4077 Aug 6 19:32 cm-adapter-serving-certs.yaml -rw-r--r-- 1 root root 312 Aug 6 19:30 custom-metrics-apiserver-auth-delegator-cluster-role-binding.yaml -rw-r--r-- 1 root root 333 Aug 6 19:30 custom-metrics-apiserver-auth-reader-role-binding.yaml -rw-r--r-- 1 root root 1585 Aug 6 19:30 custom-metrics-apiserver-deployment.yaml -rw-r--r-- 1 root root 315 Aug 6 19:30 custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml -rw-r--r-- 1 root root 107 Aug 6 19:30 custom-metrics-apiserver-service-account.yaml -rw-r--r-- 1 root root 196 Aug 6 19:30 custom-metrics-apiserver-service.yaml -rw-r--r-- 1 root root 964 Aug 6 19:30 custom-metrics-apiservice.yaml -rw-r--r-- 1 root root 217 Aug 6 19:30 custom-metrics-cluster-role.yaml -rw-r--r-- 1 root root 3817 Aug 6 19:30 custom-metrics-config-map.yaml -rw-r--r-- 1 root root 219 Aug 6 19:30 custom-metrics-resource-reader-cluster-role.yaml -rw-r--r-- 1 root root 313 Aug 6 19:30 hpa-custom-metrics-cluster-role-binding.yaml
该脚本会在manifests目录下创建一个cm-adapter-serving-certs.yaml的文件,它提供了相关secret对象的配置。另外
3. 运行如下命令,在custom-metrics名称空间中部署prometheus-adapter。
#新加APIService
cat manifests/custom-metrics-apiservice.yaml
kubectl apply -f manifests/
kubectl get all -n custom-metrics
[root@master1 prometheus-adpater]# kubectl get all -n custom-metrics NAME READY STATUS RESTARTS AGE pod/custom-metrics-apiserver-9786d7d4b-2jh9h 1/1 Running 0 47s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/custom-metrics-apiserver ClusterIP 10.102.244.181 <none> 443/TCP 47s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/custom-metrics-apiserver 1/1 1 1 48s NAME DESIRED CURRENT READY AGE replicaset.apps/custom-metrics-apiserver-9786d7d4b 1 1 1 48s
4. 测试访问
#此方式没有安装metrics.k8s.io的API
kubectl get --raw /apis/metrics.k8s.io/v1beta1
#安装生成custom.metrics.k8s.io和external.metrics.k8s.io
kubectl get --raw /apis/external.metrics.k8s.io/v1beta1
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
HPA --> k8s 指标 --》 prometheus adapter(转换) --> prometheus --》 k8s-api-sd k8s指标 (五种资源:node,pod,endpoint,svc,ingress) /kube-state-metrics(相关于k8s_exporter) 采集指标 xxx_exporter
1 prometheus 采集指标
2 prometheus adapter
3 kube-state-metrics 可选

Prometheus Adapter 规则配置说明
https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/config.md
https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/configwalkthrough.md
https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/sampleconfig.yaml
Prometheus Adapter通过一组“发现(discovery)”规则(rules)来确定要公开哪些指标,以及如何公开这些指标。
每条规则都是独立执行的(因此要确保规则彼此互斥),它通常包含需要由Adpater在API 公开指标时所
需采取的多个步骤。
每条规则大致可以分为四个部分:
- 发现:指定Adpater如何找到此规则的所有 Prometheus 指标
- 关联:指定Adpater应如何确定特定指标与哪些 Kubernetes 资源相关联
- 命名:指定Adpater应如何在自定义指标 API 中公开指标
- 查询:指定如何将对一个或多个 Kubernetes 对象上的特定指标的请求转换为对 Prometheus 的查询
每条规则关键配置项
配置项 属于
Prometheus
属于
Kubernetes 说明
seriesQuery ✅ ❌ 选择 Prometheus 中“已有的时间序列”
metricsQuery ✅ ❌ PromQL,决定如何计算指标值
name ❌ ✅ Kubernetes 中暴露的指标名称
resources ❌ ✅ 将 Prometheus label 映射为 K8s 资源
下面是一个示例:
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}' resources: overrides: namespace: {resource: "namespace"} #左边的 namespace 是 Prometheus 的 label 名,右边的 "namespace" 是 Kubernetes 的资源类型 pod: {resource: "pod"} name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: rate(<<.Series>>{<<.LabelMatchers>>}[1m])
#上面的配置解析
1)seriesQuery(系列查询):在 Prometheus 中查找匹配的指标系列
在 Prometheus 中查找名为 http_requests_total的指标
要求必须包含以下标签且不为空:
namespace!="": 必须有 Kubernetes 命名空间标签
pod!="": 必须有 Kubernetes Pod 名称标签
这确保了只选择与 Kubernetes 资源关联的 HTTP 请求指标
2)resources(资源映射):将 Prometheus 标签映射到 Kubernetes API 资源:
namespace标签 → Kubernetes namespace资源
pod 标签 → Kubernetes pod资源
这样 HPA 就能知道指标关联到哪个命名空间和哪个 Pod
3)name(指标名称转换)
matches: "^(.*)_total": 使用正则表达式匹配指标名
(.*)捕获组:匹配 http_requests部分
_total:匹配后缀
as: "${1}_per_second": 重命名指标
${1}:引用第一个捕获组,即 http_requests
最终名称:http_requests_per_second
4)metricsQuery(指标查询)
<<.Series>>: 替换为原始指标名 http_requests_total
<<.LabelMatchers>>: 自动包含查询时的标签匹配条件
rate(...[1m]): 计算 1 分钟内的请求速率(QPS)
完整查询示例:rate(http_requests_total{namespace="default",pod="app-pod"}[1m])
待Prometheus和Prometheus Adapter的相关Pod均就绪后,获取针对现存系统环境由规则生成的自定义指标信息。
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
部署示例应用metrcis app,它附带有“http_requests_total”指标
kubectl apply -f https://raw.githubusercontent.com/iKubernetes/k8s-prom/master/prometheus-adpater/example-metrics/metrics-example-app.yaml
待Metrics App的Pod就绪后,等待Prometheus Server的几个指标抓取周期,即可尝试获取由规则生成自定义指标http_requests_per_second。
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second | jq
案例:自定义指标流水线
前提准备
- ingress-nginx
- metallb
- storage Class: sc-nfs
部署 Prometheus
基于 YAML 清单文件方式部署 Prometheus
范例: 基于清单方式部署 Prometheus
#准备:提前安装ingress-nginx
kubectl apply -f namespace.yaml
kubectl apply -f . -n prom
kubectl get all -n prom
[root@master1 prometheus]# kubectl get all -n prom NAME READY STATUS RESTARTS AGE pod/prometheus-server-56695d78b8-2cl9b 1/1 Running 0 2m10s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/prometheus NodePort 10.100.121.161 <none> 9090:30090/TCP 2m10s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/prometheus-server 1/1 1 1 2m10s NAME DESIRED CURRENT READY AGE replicaset.apps/prometheus-server-56695d78b8 1 1 1 2m10s [root@master1 prometheus]#
kubectl get ingress -n prom
#浏览器访问,注意:名称解析prometheus.ming.org至192.168.3.10
http://prometheus.ming.org
kube-state-metrics (可选)
如果只是实现HPA-v2的自动扩容,此kube-state-metrics组件可无需安装
如果需要通过Prometheus实现监控Kubernetes的deplyment,statefulset等资源,才需要安装此组件
kube-state-metrics 说明

prometheus 本身就是一个监控系统,分为 server 端和 agent 端
server 端从被监控主机获取数据,而 agent 端需要部署一个 exporter ,主要用于数据采集和暴露节点的数据
基于Kubernetes_sd 只能支持如下五种资源
- Node --> node role
- Pods --> pod role
- Endpoint --> endpoint role
- Service --> service role
- Ingress --> ingress role
对于Kubernetes 的还有更多的其它的资源,比如: Deployment,PV等 想要获取其指标数据,就需要部署相关的 exporter 。
kube-state-metrics
https://github.com/kubernetes/kube-state-metrics
kube-state-metrics (KSM) 相当于 kubernetes-exporter
kube-state-metrics 是一个监听 Kubernetes API Server 的简单服务,可以生成有关对象状态的指标。
kube-state-metrics 专注于从 Kubernetes 的对象状态(例如,基于deployments, replica sets等)。它将 Kubernetes 状态的完整快照保存在内存中,并且 根据它不断生成新的指标
Prometheus 默认只支持对Node,Pod,Endpoint,Serivce,Ingress 这五个资源进行采集指标,而不支持常见的其它资源,如:Deployment,statefulset等,kube-state-metrics可以支持更多的资源的
指标,比如:Deployment,statefulset,DaemonSet,PVC等,做为Prometheus 指标采集的补充
kube-state-metrics 从Kubernetes API Server 查询所有可被监控对象的State字段获取相关指标数据,再将这些资源的指标转换为Prometheus的标准格式,由Prometheus进行指标采集
Kubernetes 资源对象指标 --> kube-state-metrics --> Prometheus
kube-state-metrics 的指标
https://github.com/kubernetes/kube-state-metrics/tree/main/docs
官方默认 collectors 覆盖的资源类型
Workloads(工作负载类)
资源 说明
Pod Pod 状态、重启、调度
Deployment 副本数、期望/实际
ReplicaSet Deployment 底层
StatefulSet 有状态应用
DaemonSet 每节点运行情况
Job 一次性任务
CronJob 定时任务
Node & Cluster 级资源
Node Node 状态、标签
Namespace 命名空间状态
LimitRange 资源限制
ResourceQuota 资源配额
Service & 网络相关
Service ClusterIP / 类型
EndpointSlice Service 后端
Endpoints 老版本对象
配置与控制类资源
资源 说明
ConfigMap 配置对象
Secret 密钥(只暴露 metadata,不暴露内容)
HorizontalPodAutoscaler (HPA) 自动伸缩状态
PodDisruptionBudget (PDB) 中断预算
PriorityClass Pod 优先级
Storage 相关
资源 说明
PersistentVolume (PV) 卷状态
PersistentVolumeClaim (PVC) 卷声明
StorageClass 存储类型
RBAC(权限对象)
资源 说明
ServiceAccount 服务账号
Role / ClusterRole 权限定义
RoleBinding / ClusterRoleBinding 权限绑定
默认 不会 监控的资源(非常关键)
资源 原因
❌ Ingress 新版本默认关闭
❌ NetworkPolicy 需显式开启
❌ CRD kube-state-metrics 不自动采
❌ CiliumNetworkPolicy 属于 CRD
❌ 自定义资源 必须额外组件
❌ Pod 日志 / 事件 不属于 state
kube-state-metrics 不采 Event、不采 Log、不采 Metrics
kube-state-metrics 部署
https://github.com/kubernetes/kube-state-metrics#kubernetes-deployment
https://github.com/kubernetes/kube-state-metrics/tree/main/examples/standard
资源使用推荐
kube-state-metrics 的资源使用量随集群的 Kubernetes 对象(Pods/Nodes/Deployments/Secrets
等)大小而变化。 在某种程度上,集群中的 Kubernetes 对象与集群的节点号成正比。
作为一般规则,您应该分配:
- 250MiB 内存
- 0.1 个核心
YAML 清单文件方式部署 kube-state-metrics
范例:YAML 清单文件方式部署 kube-state-metrics
kubectl create ns prom
[root@master1 kube-state-metrics]# cat kube-state-metrics-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: kube-state-metrics namespace: prom spec: replicas: 1 selector: matchLabels: app: kube-state-metrics template: metadata: labels: app: kube-state-metrics spec: serviceAccountName: kube-state-metrics containers: - name: kube-state-metrics #image: gcr.io/google_containers/kube-state-metrics-amd64:v1.3.1 #image: gcmirrors/kube-state-metrics-amd64:v1.7.1 image: registry.cn-beijing.aliyuncs.com/wangxiaochun/kube-state-metrics-amd64:v1.7.1 ports: - containerPort: 8080 [root@master1 kube-state-metrics]#
[root@master1 kube-state-metrics]# cat kube-state-metrics-rbac.yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: kube-state-metrics namespace: prom --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-state-metrics rules: # ===== Core API ===== - apiGroups: [""] resources: - nodes - pods - services - endpoints - namespaces - persistentvolumes - persistentvolumeclaims - resourcequotas - replicationcontrollers - limitranges verbs: ["list", "watch"] # ===== extensions(老版本 K8s)===== - apiGroups: ["extensions"] resources: - deployments - replicasets - daemonsets verbs: ["list", "watch"] # ===== apps(新版本 K8s,重点)===== - apiGroups: ["apps"] resources: - deployments - replicasets - daemonsets - statefulsets verbs: ["list", "watch"] # ===== batch ===== - apiGroups: ["batch"] resources: - jobs - cronjobs verbs: ["list", "watch"] # ===== autoscaling ===== - apiGroups: ["autoscaling"] resources: - horizontalpodautoscalers verbs: ["list", "watch"] # ===== policy(可选,但推荐)===== - apiGroups: ["policy"] resources: - poddisruptionbudgets verbs: ["list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-state-metrics roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kube-state-metrics subjects: - kind: ServiceAccount name: kube-state-metrics namespace: prom
[root@master1 kube-state-metrics]# cat kube-state-metrics-svc.yaml apiVersion: v1 kind: Service metadata: annotations: prometheus.io/scrape: 'true' prometheus.io/port: '8080' name: kube-state-metrics namespace: prom labels: app: kube-state-metrics spec: ports: - name: kube-state-metrics port: 8080 protocol: TCP selector: app: kube-state-metrics
cd kube-state-metrics/
kubectl apply -f .
#确认安装
kubectl get pod,svc -n prom
[root@master1 kube-state-metrics]# kubectl get pod,svc -n prom NAME READY STATUS RESTARTS AGE pod/kube-state-metrics-75b47b4c8d-9brml 1/1 Running 0 67s pod/prometheus-server-56695d78b8-2cl9b 1/1 Running 0 16m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kube-state-metrics ClusterIP 10.111.105.221 <none> 8080/TCP 67s service/prometheus NodePort 10.100.121.161 <none> 9090:30090/TCP 16m
#访问kube-state-metrics对应的SVC
curl 10.111.105.221:8080/metrics
curl -s 10.111.105.221:8080/metrics|grep kube_deployment_create|head
[root@master1 kube-state-metrics]# curl -s 10.111.105.221:8080/metrics|grep kube_deployment_create|head # HELP kube_deployment_created Unix creation timestamp # TYPE kube_deployment_created gauge kube_deployment_created{namespace="custom-metrics",deployment="custom-metrics-apiserver"} 1.786016495e+09 kube_deployment_created{namespace="ingress-nginx",deployment="ingress-nginx-controller"} 1.786081288e+09 kube_deployment_created{namespace="kube-system",deployment="coredns"} 1.785740043e+09 kube_deployment_created{namespace="kube-system",deployment="metrics-server"} 1.785927156e+09 kube_deployment_created{namespace="metallb-system",deployment="controller"} 1.786080763e+09 kube_deployment_created{namespace="prom",deployment="kube-state-metrics"} 1.786082759e+09 kube_deployment_created{namespace="prom",deployment="prometheus-server"} 1.786081838e+09
#通过Prometheus查看相关指标
kube_service_info
kube_persistentvolume_info
kube_deployment_created
kube_statefulset_created
kube_node_status_condition
部署测试 APP
首先部署Metrics APP示例于指定的名称空间,例如default。
准备测试的Deployment和Service
[root@master1 hpa]# cat metrics-example-app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: metrics-app spec: replicas: 2 selector: matchLabels: app: metrics-app controller: metrics-app template: metadata: labels: app: metrics-app controller: metrics-app annotations: prometheus.io/scrape: "true" prometheus.io/port: "80" prometheus.io/path: "/metrics" spec: containers: - name: metrics-app image: registry.cn-beijing.aliyuncs.com/wangxiaochun/metrics-app:v0.1 ports: - name: web containerPort: 80 resources: requests: memory: "256Mi" cpu: "500m" limits: memory: "256Mi" cpu: "500m" --- apiVersion: v1 kind: Service metadata: name: metrics-app spec: type: LoadBalancer ports: - name: web port: 80 targetPort: 80 selector: app: metrics-app controller: metrics-app
kubectl apply -f metrics-example-app.yaml
kubectl get pod,svc -o wide -o wide
[root@master1 hpa]# kubectl get pod,svc -o wide -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/metrics-app-7bdcd57958-fpkqt 1/1 Running 0 4m8s 10.244.1.30 node1.org <none> <none> pod/metrics-app-7bdcd57958-twjs4 1/1 Running 0 4m8s 10.244.1.31 node1.org <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d23h <none> service/metrics-app LoadBalancer 10.96.114.5 192.168.3.11 80:31466/TCP 4m8s app=metrics-app,controller=metrics-app
#测试访问
curl 10.96.114.5
#查看指标
curl 10.96.114.5/metrics
[root@master1 hpa]# curl 10.96.114.5/metrics # HELP http_requests_total The amount of requests in total # TYPE http_requests_total counter http_requests_total 1 # HELP http_requests_per_second The amount of requests per second the latest ten seconds # TYPE http_requests_per_second gauge http_requests_per_second 0.1
#测试发起大量访问
while true;do curl 10.96.114.5;sleep 0.$[RANDOM%10];done
部署 HPAv2
部署HPA的定义于同一名称空间
root@master1 hpa]# cat metrics-app-hpa.yaml kind: HorizontalPodAutoscaler apiVersion: autoscaling/v2 metadata: name: metrics-app-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: metrics-app minReplicas: 2 maxReplicas: 10 metrics: - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: "3" behavior: scaleDown: stabilizationWindowSeconds: 10
#应用清单文件
kubectl apply -f metrics-app-hpa.yaml
kubectl get hpa
[root@master1 example-metrics]# kubectl get pod -n custom-metrics -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES custom-metrics-apiserver-9786d7d4b-q8wlw 1/1 Running 4 (8m1s ago) 6h3m 10.244.1.49 node1.org <none> <none>
[root@node1 config]# docker ps -a |grep custom-metrics 05580398041e 276d59929ae0 "/adapter --secure-p…" 8 minutes ago Up 8 minutes k8s_custom-metrics-apiserver_custom-metrics-apiserver-9786d7d4b-q8wlw_custom-metrics_6cfa60b6-7c93-4353-9764-75a9a40ca986_4 f145f9a1125a registry.aliyuncs.com/google_containers/pause:3.10.1 "/pause" 8 minutes ago Up 8 minutes k8s_POD_custom-metrics-apiserver-9786d7d4b-q8wlw_custom-metrics_6cfa60b6-7c93-4353-9764-75a9a40ca986_16 c5625d1188ee 276d59929ae0 "/adapter --secure-p…" 3 hours ago Exited (255) 8 minutes ago k8s_custom-metrics-apiserver_custom-metrics-apiserver-9786d7d4b-q8wlw_custom-metrics_6cfa60b6-7c93-4353-9764-75a9a40ca986_3 1aa1407b9105 registry.aliyuncs.com/google_containers/pause:3.10.1 "/pause" 3 hours ago Exited (255) 8 minutes ago k8s_POD_custom-metrics-apiserver-9786d7d4b-q8wlw_custom-metrics_6cfa60b6-7c93-4353-9764-75a9a40ca986_13 [root@node1 config]#
docker inspect 05580398041e|grep adapter
root@node1 config]# docker inspect 05580398041e|grep adapter "Path": "/adapter", "--config=/etc/adapter/config.yaml" "/var/lib/kubelet/pods/6cfa60b6-7c93-4353-9764-75a9a40ca986/volumes/kubernetes.io~configmap/config:/etc/adapter/:ro", "Destination": "/etc/adapter", "--config=/etc/adapter/config.yaml" "/adapter"
[root@node1 config]# cat /var/lib/kubelet/pods/6cfa60b6-7c93-4353-9764-75a9a40ca986/volumes/kubernetes.io~configmap/config/config.yaml rules: - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' seriesFilters: [] resources: overrides: namespace: resource: namespace pod: resource: pod name: matches: ^container_(.*)_seconds_total$ as: "" metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>) - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' seriesFilters: - isNot: ^container_.*_seconds_total$ resources: overrides: namespace: resource: namespace pod: resource: pod name: matches: ^container_(.*)_total$ as: "" metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>) - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' seriesFilters: - isNot: ^container_.*_total$ resources: overrides: namespace: resource: namespace pod: resource: pod name: matches: ^container_(.*)$ as: "" metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>) - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' seriesFilters: - isNot: .*_total$ resources: template: <<.Resource>> name: matches: "" as: "" metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' seriesFilters: - isNot: .*_seconds_total resources: template: <<.Resource>> name: matches: ^(.*)_total$ as: "" metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>) - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' seriesFilters: [] resources: template: <<.Resource>> name: matches: ^(.*)_seconds_total$ as: "" metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>) resourceRules: cpu: containerQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>) nodeQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[1m])) by (<<.GroupBy>>) resources: overrides: instance: resource: node namespace: resource: namespace pod: resource: pod containerLabel: container memory: containerQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>) nodeQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>) resources: overrides: instance: resource: node namespace: resource: namespace pod: resource: pod containerLabel: container window: 1m externalRules: - seriesQuery: '{__name__=~"^.*_queue_(length|size)$",namespace!=""}' resources: overrides: namespace: resource: namespace name: matches: ^.*_queue_(length|size)$ as: "$0" metricsQuery: max(<<.Series>>{<<.LabelMatchers>>}) - seriesQuery: '{__name__=~"^.*_queue$",namespace!=""}' resources: overrides: namespace: resource: namespace name: matches: ^.*_queue$ as: "$0" metricsQuery: max(<<.Series>>{<<.LabelMatchers>>}) [root@node1 config]# [root@node1 config]#
自定义指标流水线规则
prometheus Adapter需要基于定义的规则来生成自定义指标。
例如:要将示例应用Metrics APP上的指标http_requests_total转为Prometheus上可用的指标 http_requests_per_second,需要类似如下规则的支撑。
#示例1
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"} name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: rate(<<.Series>>{<<.LabelMatchers>>}[1m])
#示例2:将原有的promthues指标直接转换为k8s的同名的指标
seriesQuery: 'http_requests_per_second{namespace!="",pod!=""}' name: matches: "^(.*)" as: "${1}" metricsQuery: avg(<<.Series>>{<<.LabelMatchers>>})
#示例3:将原有的promthues指标直接转换为k8s的同名的指标 - seriesQuery: 'http_requests_per_second' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"}
#示例4:全部指标自动暴露,不推荐,全部暴露,指标太多,性能差,不安全 rules: - seriesQuery: '{__name__=~".+"}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"}
ConfigMap配置文件“custom-metrics-config-map.yaml”在默认配置的基础上添加了如上配置,若部署
prometheus-adapter无其它配置变化,则直接运行如下命令即可完成添加自定义的规则。
#把 Prometheus 中的 http_requests_total 指标,转换成一个 Kubernetes 自定义指标http_requests_per_second,并按 namespace / pod 维度暴露给 HPA 使用
#Prometheus 指标: http_requests_total(Counter)--> rate(...[1m]) 计算 QPS --> 重命名为: http_requests_per_second -->按 namespace / pod 维度暴露 --> 供 HPA 自动扩缩容使用
[root@master1 example-metrics]# cat custom-metrics-config-map-demo1.yaml apiVersion: v1 kind: ConfigMap metadata: name: adapter-config namespace: custom-metrics data: config.yaml: | rules: #- {} #添加自定义指标的信息 - seriesQuery: 'http_requests_total{namespace!="",pod!=""}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"} name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: rate(<<.Series>>{<<.LabelMatchers>>}[1m])
#上面的内容格式解析 apiVersion: v1 # Kubernetes API 版本,ConfigMap 属于 core/v1 kind: ConfigMap # 资源类型:ConfigMap,用于给 prometheus-adapter 提供配置 metadata: name: adapter-config # ConfigMap 名称,prometheus-adapter 会引用它 namespace: custom-metrics # ConfigMap 所在命名空间(必须和 adapter 在同一 namespace) data: config.yaml: | # ConfigMap 中的一个文件,内容是 adapter 的规则配置 rules: # 规则列表,每一条 rule 定义一个自定义指标 #- {} # 官方示例的占位写法,这里被注释掉,没有实际作用 # ================== 自定义指标规则开始 ================== # 将 Prometheus 中的 http_requests_total 转换成 Kubernetes 可识别的自定义指标 - seriesQuery: 'http_requests_total{namespace!="",pod!=""}' # seriesQuery:定义从 Prometheus 中“选择哪些时间序列” # http_requests_total -> 原始Prometheus中的 Counter 指标 # namespace!="" && pod!="" -> 只选择 Pod 级别的指标,排除无关数据 resources: # resources:定义 Prometheus label 与 Kubernetes 资源的映射关系 overrides: namespace: {resource: "namespace"} # 将 Prometheus 的 namespace 标签映射为 Kubernetes 的 Namespace 资源 # 左边的 namespace 是 Prometheus 的 label 名,右边的 "namespace" 是 Kubernetes 的资源类型 pod: {resource: "pod"} # 将 Prometheus 的 pod 标签映射为 Kubernetes 的 Pod 资源 # HPA 通过这个映射知道“这个指标属于哪个 Pod” name: # name:定义指标名称的转换规则 matches: "^(.*)_total" # 正则匹配 Prometheus 原始指标名 # 例如:http_requests_total # 捕获:http_requests as: "${1}_per_second" # 将捕获的名称重新命名 # http_requests -> http_requests_per_second # 这是最终暴露给 Kubernetes / HPA 使用的指标名 metricsQuery: rate(<<.Series>>{<<.LabelMatchers>>}[1m]) # metricsQuery:真正向 Prometheus 发送的 PromQL 查询 # # <<.Series>> -> seriesQuery 中匹配到的指标名 # <<.LabelMatchers>> -> 自动注入的 label 过滤条件 # # 实际生成的查询类似: # rate(http_requests_total{namespace="default", pod="nginx-xxx" }[1m] ) # 含义:计算 http_requests_total 在 1 分钟内的增长速率 # 得到“每秒请求数(QPS)”
#应用清单文件
kubectl apply -f custom-metrics-config-map-demo1.yaml
[root@node1 config]# cat /var/lib/kubelet/pods/6cfa60b6-7c93-4353-9764-75a9a40ca986/volumes/kubernetes.io~configmap/config/config.yaml rules: #- {} #添加自定义指标的信息 - seriesQuery: 'http_requests_total{namespace!="",pod!=""}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"} name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: rate(<<.Series>>{<<.LabelMatchers>>}[1m])
#注意:不支持热加载,必须重新创建prometheus-adapter的Pod才能生效
kubectl rollout restart deployment -n custom-metrics custom-metrics-apiserver
kubectl get hpa
[root@master1 example-metrics]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-app-hpa Deployment/metrics-app 100m/3 2 10 2 3h14m
#测试访问
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second"
测试访问
[root@master1 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d4h metrics-app LoadBalancer 10.96.114.5 192.168.3.11 80:31466/TCP 5h21m
[root@master1 ~]# kubectl get pod -w NAME READY STATUS RESTARTS AGE metrics-app-7bdcd57958-fpkqt 1/1 Running 3 (13m ago) 5h21m metrics-app-7bdcd57958-twjs4 1/1 Running 3 (13m ago) 5h21m
加速访问APP对应的SVC
while true;do curl 10.96.114.5;sleep 0.0$[RANDOM%10];done
while true;do curl 10.96.114.5;done
#可看到
curl 10.96.114.5/metrics
[root@master1 ~]# curl 10.96.114.5/metrics # HELP http_requests_total The amount of requests in total # TYPE http_requests_total counter http_requests_total 64 # HELP http_requests_per_second The amount of requests per second the latest ten seconds # TYPE http_requests_per_second gauge http_requests_per_second 0.2
[root@master1 example-metrics]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-app-hpa Deployment/metrics-app 77m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 121m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 2288m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 4688m/3 2 10 2 3h20m
#查看到达到8177m即8.177超过3的阈值
[root@master1 example-metrics]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-app-hpa Deployment/metrics-app 77m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 121m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 2288m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 4688m/3 2 10 2 3h20m metrics-app-hpa Deployment/metrics-app 8320m/3 2 10 4 3h20m metrics-app-hpa Deployment/metrics-app 8177m/3 2 10 6 3h20m
#过一会儿可以看到Pod扩容
[root@master1 ~]# kubectl get pod -w -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-app-7bdcd57958-bjjrt 0/1 ContainerCreating 0 2m49s <none> node2.org <none> <none> metrics-app-7bdcd57958-fpkqt 1/1 Running 3 (21m ago) 5h28m 10.244.1.54 node1.org <none> <none> metrics-app-7bdcd57958-lj78q 0/1 ContainerCreating 0 3m4s <none> node2.org <none> <none> metrics-app-7bdcd57958-twjs4 1/1 Running 3 (21m ago) 5h28m 10.244.1.52 node1.org <none> <none> metrics-app-7bdcd57958-vqg8n 0/1 ContainerCreating 0 2m49s <none> node3.org <none> <none> metrics-app-7bdcd57958-xm4z8 0/1 ContainerCreating 0 3m4s <none> node2.org <none> <none> metrics-app-7bdcd57958-bjjrt 1/1 Running 0 3m5s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-xm4z8 1/1 Running 0 3m21s 10.244.2.17 node2.org <none> <none> metrics-app-7bdcd57958-lj78q 1/1 Running 0 3m22s 10.244.2.18 node2.org <none> <none> metrics-app-7bdcd57958-vqg8n 1/1 Running 0 3m9s 10.244.3.11 node3.org <none> <none>
#加快访问后,可以看到最多达到10个Pod
[root@master1 example-metrics]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-app-hpa Deployment/metrics-app 77m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 121m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 2288m/3 2 10 2 3h19m metrics-app-hpa Deployment/metrics-app 4688m/3 2 10 2 3h20m metrics-app-hpa Deployment/metrics-app 8320m/3 2 10 4 3h20m metrics-app-hpa Deployment/metrics-app 8177m/3 2 10 6 3h20m metrics-app-hpa Deployment/metrics-app 8166m/3 2 10 6 3h20m metrics-app-hpa Deployment/metrics-app 7733m/3 2 10 6 3h21m metrics-app-hpa Deployment/metrics-app 7977m/3 2 10 6 3h21m metrics-app-hpa Deployment/metrics-app 8121m/3 2 10 6 3h21m metrics-app-hpa Deployment/metrics-app 7844m/3 2 10 6 3h22m metrics-app-hpa Deployment/metrics-app 7533m/3 2 10 6 3h22m metrics-app-hpa Deployment/metrics-app 7488m/3 2 10 6 3h22m metrics-app-hpa Deployment/metrics-app 7310m/3 2 10 6 3h22m metrics-app-hpa Deployment/metrics-app 7533m/3 2 10 6 3h23m metrics-app-hpa Deployment/metrics-app 7466m/3 2 10 6 3h23m metrics-app-hpa Deployment/metrics-app 6912m/3 2 10 6 3h23m metrics-app-hpa Deployment/metrics-app 3526m/3 2 10 6 3h24m metrics-app-hpa Deployment/metrics-app 1715m/3 2 10 6 3h24m metrics-app-hpa Deployment/metrics-app 1950m/3 2 10 4 3h24m metrics-app-hpa Deployment/metrics-app 3055m/3 2 10 3 3h24m metrics-app-hpa Deployment/metrics-app 3814m/3 2 10 3 3h25m metrics-app-hpa Deployment/metrics-app 4012m/3 2 10 4 3h25m metrics-app-hpa Deployment/metrics-app 3186m/3 2 10 4 3h25m metrics-app-hpa Deployment/metrics-app 3386m/3 2 10 4 3h25m metrics-app-hpa Deployment/metrics-app 3598m/3 2 10 5 3h26m metrics-app-hpa Deployment/metrics-app 2975m/3 2 10 5 3h26m metrics-app-hpa Deployment/metrics-app 2384m/3 2 10 5 3h26m metrics-app-hpa Deployment/metrics-app 5849m/3 2 10 4 3h26m metrics-app-hpa Deployment/metrics-app 8483m/3 2 10 8 3h27m metrics-app-hpa Deployment/metrics-app 6932m/3 2 10 10 3h27m
[root@master1 ~]# kubectl get pod -w -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-app-7bdcd57958-4ljf5 0/1 Pending 0 45s <none> <none> <none> <none> metrics-app-7bdcd57958-bjjrt 1/1 Running 0 7m30s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-djzb2 1/1 Running 0 2m48s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-gbc7d 1/1 Running 0 62s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-gv7bx 1/1 Running 0 62s 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-mzhsk 1/1 Running 0 62s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-nd7s9 1/1 Running 0 63s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-rqqhs 0/1 Pending 0 45s <none> <none> <none> <none> metrics-app-7bdcd57958-twjs4 1/1 Running 3 (25m ago) 5h33m 10.244.1.52 node1.org <none> <none> metrics-app-7bdcd57958-vqg8n 1/1 Running 0 7m30s 10.244.3.11 node3.org <none> <none>
#停止访问,等一会儿,可以看到Pod数据减少
[root@master1 example-metrics]# kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-app-hpa Deployment/metrics-app 6932m/3 2 10 10 3h27m metrics-app-hpa Deployment/metrics-app 4659m/3 2 10 10 3h27m metrics-app-hpa Deployment/metrics-app 4345m/3 2 10 10 3h27m metrics-app-hpa Deployment/metrics-app 5079m/3 2 10 10 3h28m metrics-app-hpa Deployment/metrics-app 4760m/3 2 10 10 3h28m metrics-app-hpa Deployment/metrics-app 3219m/3 2 10 10 3h28m metrics-app-hpa Deployment/metrics-app 1599m/3 2 10 10 3h28m metrics-app-hpa Deployment/metrics-app 181m/3 2 10 5 3h29m metrics-app-hpa Deployment/metrics-app 66m/3 2 10 2 3h29m
[root@master1 ~]# kubectl get pod -w -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-app-7bdcd57958-4ljf5 0/1 Pending 0 90s <none> <none> <none> <none> metrics-app-7bdcd57958-bjjrt 1/1 Running 0 8m15s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-djzb2 1/1 Running 0 3m33s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-gbc7d 1/1 Running 0 107s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-gv7bx 1/1 Running 0 107s 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-mzhsk 1/1 Running 0 107s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-nd7s9 1/1 Running 0 108s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-rqqhs 0/1 Pending 0 90s <none> <none> <none> <none> metrics-app-7bdcd57958-twjs4 1/1 Running 3 (26m ago) 5h34m 10.244.1.52 node1.org <none> <none> metrics-app-7bdcd57958-vqg8n 1/1 Running 0 8m15s 10.244.3.11 node3.org <none> <none> metrics-app-7bdcd57958-nd7s9 1/1 Terminating 0 2m1s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-gbc7d 1/1 Terminating 0 2m 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-nd7s9 1/1 Terminating 0 2m1s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-gv7bx 1/1 Terminating 0 2m 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-4ljf5 0/1 Terminating 0 103s <none> <none> <none> <none> metrics-app-7bdcd57958-rqqhs 0/1 Terminating 0 103s <none> <none> <none> <none> metrics-app-7bdcd57958-gv7bx 1/1 Terminating 0 2m 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-gbc7d 1/1 Terminating 0 2m 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-rqqhs 0/1 Terminating 0 103s <none> <none> <none> <none> metrics-app-7bdcd57958-4ljf5 0/1 Terminating 0 103s <none> <none> <none> <none> metrics-app-7bdcd57958-djzb2 1/1 Terminating 0 4m1s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-bjjrt 1/1 Terminating 0 8m43s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-mzhsk 1/1 Terminating 0 2m15s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-djzb2 1/1 Terminating 0 4m1s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-mzhsk 1/1 Terminating 0 2m15s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-bjjrt 1/1 Terminating 0 8m43s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-gbc7d 0/1 Error 0 2m30s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-nd7s9 0/1 Error 0 2m31s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-gv7bx 0/1 Error 0 2m30s 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-gbc7d 0/1 Error 0 2m30s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-gbc7d 0/1 Error 0 2m31s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-gbc7d 0/1 Error 0 2m31s 10.244.2.20 node2.org <none> <none> metrics-app-7bdcd57958-nd7s9 0/1 Error 0 2m32s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-nd7s9 0/1 Error 0 2m32s 10.244.3.13 node3.org <none> <none> metrics-app-7bdcd57958-gv7bx 0/1 Error 0 2m31s 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-gv7bx 0/1 Error 0 2m31s 10.244.3.14 node3.org <none> <none> metrics-app-7bdcd57958-djzb2 0/1 Error 0 4m31s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-mzhsk 0/1 Error 0 2m45s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-bjjrt 0/1 Error 0 9m13s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-djzb2 0/1 Error 0 4m32s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-djzb2 0/1 Error 0 4m32s 10.244.2.19 node2.org <none> <none> metrics-app-7bdcd57958-mzhsk 0/1 Error 0 2m46s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-mzhsk 0/1 Error 0 2m46s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-mzhsk 0/1 Error 0 2m46s 10.244.1.58 node1.org <none> <none> metrics-app-7bdcd57958-bjjrt 0/1 Error 0 9m15s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-bjjrt 0/1 Error 0 9m15s 10.244.2.16 node2.org <none> <none> metrics-app-7bdcd57958-bjjrt 0/1 Error 0 9m15s 10.244.2.16 node2.org <none> <none>
浙公网安备 33010602011771号