大家好,我是蓝胖子,都知道,k8s拥有自动扩缩容机制HPA,我们能够通过配置针对不同的扩缩容场景进行自动扩缩容,往往初学者在面对其中繁多配置的时候会学了又忘记,今天我将会以一种不同的视角,结合api server 请求 来探索这部分的配置,看完本篇,应该会对扩缩容这部分配置会有更深的理解。

自动扩缩容架构图

我们先来看一下自动扩缩容的原理,在k8s中HPA这个模块的逻辑会定时请求api server 获取相应的pod或者CRD或者其他资源的指标信息,这些指标信息是用户创建HPA的yaml配置文件时指定的。

api server收到请求后,根据请求的api group,api version 转发给内部的api service服务进行处理,当我们想让k8s借用prometheus的相关指标进行扩缩容时,就需要在集群里用api service的方式安装prometheus adapter,它会将发往api server的请求经过包装,转发到prometheus服务器获取对应指标信息,然后将结果经过封装返回给客户端即HPA模块。HPA模块收到指标后,在根据自身配置文件中的target值判断是否需要进行自动扩缩容。

api server 处理请求的方式

既然提到了prometheus adapter是以api service 方式安装到k8s集群中的,我再对api server的架构已经处理请求的方式再阐述下。

api server 处理请求的方式是链式的,你可以简单的理解为api server里有多个http server ,当某个请求的路径不属于某个http server处理范畴内的话,会将这个请求委托给下一个http server进行处理。同时,k8s允许用户自定义api service作为http server,prometheus adapter 就是一个自定义的api service。

api server 请求路径格式

向api server发送http请求,请求格式是按一定规则进行组装的,我主要查看了HPA模块源码,所以拿这块去举例,hpa发往api server的请求是将api version和api group 以及要请求资源的命名空间,资源名拼接到一起组成的路径。如下:

不同的HPA指标类型这个路径的拼接会有所不同(下面会详细讲到),但是整体的api风格是和这个一致的。

当HPA在向api server发送请求的时候则是根据不同的扩缩容指标类型选择了不同的api group 去发送请求。

️️ 注意,这里HPA选择的api group是k8s这部分代码已经固定好了的,所以prometheus adapter在以api service安装时指定的api group 需要和这里吻合。目前针对指标类型,HPA会从metrics.k8s.io, customer.metrics.k8s.io, external.metrics.k8s.io这3个api group种选取对应的group。

HPA 扩缩容的4种指标类型

接下来,我们来详细看下,HPA扩缩容的4种指标类型。

Pods

先看第一种pods类型,它表示的是由pod产生的指标, 其在HPA声明的配置yaml文件里写法如下,

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: sample-app
namespace: default
spec:
maxReplicas: 10
minReplicas: 2
metrics:
- pods:
metric:
name: http_requests
selector:
matchLabels:
<label-key>: <label-value>
target:
averageValue: 500m
type: AverageValue
type: Pods
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-app

可以看到spec.metrics.type 值为pods类型,HPA的pods 指标类型 是指pod这个资源对象产生的指标,其中定义了指标名为http_requests,最终发往api server的url path如下所示,

/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests?labelSelector=<label-key>=<label-value>

api server 收到这个请求后会将请求转发给prometheus adapter,那么prometheus adapter 又是如何将http_requests 与具体的prometheus中的指标对应起来的呢?

prometheus adapter在启动的时候我们会配置一个规则配置文件,在这个文件定义了这个映射关系,下面是这针这种类型的指标配置规则部分,

rules:
- seriesQuery: 'http_requests_total{}'
resources:
overrides:
kubernetes_namespace: {resource: "namespace"}
kubernetes_pod_name: {resource: "pods"}
name:
matches: "http_requests_total"
as: "http_requests"
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'

我们将hpa配置文件和发往api server的请求以及prometheus adapter的规则文件结合起来,看看prometheus adapter 规则文件里那些模板变量的含义。

首先是hpa的配置文件中指定了metric.name是http_requests,http_requests在prometheus adapter的配置文件里是将prometheus的http_requests_total与之对应了起来,并且从规则配置文件的resources.overrides 配置中可以发现namespace和pods资源在指标http_requests_total中会有kubernetes_namespace和kubernetes_pod_name标签与之对应,这层关系其实主要是为了metricsQuery 中模板变量的替换。

metricsQuery 中 <<.Series>> 其实就是seriesQuery这部分。

<<.LabelMatchers>> 是筛选指标时的标签,在hpa里面我们指定了metric.selector,发往api server的请求里的参数labelSelector就会替代<<.LabelMatchers>>模板变量,同时发往api server请求中的namespace的值也会写到<<.LabelMatchers>>中,并且namespace的对应标签名就是resources.overrides中定义的kubernetes_namespace。

<<.GroupBy>> 变量在这里会将k8s的resource资源类型作为分组的维度,并且在这个场景下,在发往api server的请求中,k8s的资源是pods类型,而pods类型在指标中的标签名是kubernetes_pod_name。

所以最终,在prometheus 中进行查询时执行的promql语句为,

sum(rate(http_requests_total{"kubernetes_namespace":"default","<label-key>":"<label-value>"}[2m])) by (kubernetes_pod_name)

Object

在看了pods类型的hpa指标后,我们再来看看Object类型的指标是如何配置的,因为在k8s里资源类型除了pod类型,还有其他类型,所以如果由其他资源类型产生的指标,则由Object来表示。

先看下hpa的yaml配置文件是如何写的。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: sample-app
namespace: default
spec:
maxReplicas: 10
minReplicas: 2
metrics:
- object:
metric:
name: requests-per-second
describedObject:
apiVersion: extensions/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
type: Object
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-app

发往api server的请求格式如下

/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/ingress/main-route/requests-per-second

prometheus adapter配置此类规则和Pods类型类似,模板变量解析方式也是类似,唯一有点不一样的是此时的<<.GroupBy>> 模板变量会被ingress/main-route 也就是资源名加上资源示例名替代。

Resource, ContainerResource

接着看一下hpa中的Resource类型的指标配置,它表示对pod的cpu或者内存值来进行扩缩容,本质上可以用Pods 类型的配置来代替这部分配置,那为什么还有Resource类型呢?因为Resource出来的时候还没有Pods 类型。

Kubernetes 1.20 在 HorizontalPodAutoscaler (HPA) 中引入了 ContainerResource 类型指标,不论是Resource还是ContainerResource都只能对cpu和内存这两个维度进行监控,它们的区别如下,

Resource 计算pod的资源使用率是

sum{每个容器的资源使用量} / sum{每个容器的资源请求}

但是一个pod有多个容器,可能会出现单个容器资源使用率高,但是平均下来每个容器资源使用率低的情况,而ContainerResource 则能够指定以pod中的哪个容器拿来计算扩容指标,能够提供更准确的扩容机制。

ContainerResource在hpa的yaml配置文件中配置如下,其中container标签指明了容器名称。

type: ContainerResource
containerResource:
name: cpu
container: application
target:
type: Utilization
averageUtilization: 60

而Resource类型的扩容指标则是针对pod中所有容器计算指标,

type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60

它们发往api server 的请求格式如下

/apis/metrics.k8s.io/v1beta1/namespaces/default/pods

注意,这里的配置文件没有加上selector,实际上我们平时写配置文件的时候肯定是有selector的,所以发往api server的请求也会有selector的参数

prometheus adapter 在收到这个请求后,会将对应的pod的cpu和内存信息全部返回,然后k8s的hpa模块筛选其需要用到的部分,像ContainerResource就会筛选返回结果中和container标签值代表的容器名称一样的指标进行计算。

prometheus adapter针对此类型的指标规则配置如下, 其中的containerLabel 表明了指标中容器名称是用哪个标签表示的,此时的<<.GroupBy>>模板变量 会由pod资源名称和容器名标签两个维度替代。

以下是prometheus adapter官方给出的配置模版,自己配置的时候需要改掉实际查询的指标名已经标签名等。

"resourceRules":
"cpu":
"containerLabel": "container"
"containerQuery": |
sum by (<<.GroupBy>>) (
irate (
container_cpu_usage_seconds_total{<<.LabelMatchers>>,container!="",pod!=""}[4m]
)
)
"nodeQuery": |
sum by (<<.GroupBy>>) (
irate(
node_cpu_usage_seconds_total{<<.LabelMatchers>>}[4m]
)
)
"resources":
"overrides":
"namespace":
"resource": "namespace"
"node":
"resource": "node"
"pod":
"resource": "pod"
"memory":
"containerLabel": "container"
"containerQuery": |
sum by (<<.GroupBy>>) (
container_memory_working_set_bytes{<<.LabelMatchers>>,container!="",pod!=""}
)
"nodeQuery": |
sum by (<<.GroupBy>>) (
node_memory_working_set_bytes{<<.LabelMatchers>>}
)
"resources":
"overrides":
"node":
"resource": "node"
"namespace":
"resource": "namespace"
"pod":
"resource": "pod"
"window": "5m"

External

最后,我们来看下external 类型的扩容指标如何配置,上面讲到的hpa 扩缩容指标类型都是在k8s集群里产生的指标,它们都限定在了一个namespace里面,除此以外,hpa模块还允许配置第三方的指标类型,比如集群外部的消息队列产生的指标,这类型的指标被称作External类型。 在hpa里配置案例如下,

type: External
external:
metric:
name: queue_messages_cnt
selector:
matchLabels:
app: "lanpangzi"
# External指标类型下只支持Value和AverageValue类型的目标值
target:
type: AverageValue
averageValue: 30

发往api server的请求格式如下

/apis/external.metrics.k8s.io/v1beta1/namespaces/default/queue_messages_cnt

由于外部指标和namespace无关,所以在配置prometheus adapter的规则配置文件的时候,指定下指标是namespace无关的。

externalRules:
- seriesQuery: 'queue_messages_cnt'
resources:
namespaced: false
name:
matches: 'queue_messages_cnt'
as: 'queue_messages_cnt'
metricsQuery: avg(<<.Series>>{<<.LabelMatchers>>})

总结

探索HPA配置的含义过程中,其实可以发现k8s在针对HPA扩容依据的拓展方式上,就是规定了3组api group(metrics.k8s.io,external.metrics.k8s.io,custom.metrics.k8s.io),并且用基本一致的http请求,让第三方(prometheus adapter)在声明为api service 的时候指定为对应的api group,然后解析请求路径和参数来进而对prometheus查询 即完成了对HPA扩容指标的查询。

关于prometheus adapter更多的配置案例建议直接看prometheus adapter的doc目录下的示例。

k8s 自动扩缩容HPA原理及adapter配置详解👑的更多相关文章

  1. 三十三、HPA实现自动扩缩容

    通过HPA实现业务应用的动态扩缩容 HPA控制器介绍 当系统资源过高的时候,我们可以使用如下命令来实现 Pod 的扩缩容功能 $ kubectl -n luffy scale deployment m ...

  2. 通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容

    上一篇我们讲到了dapr提供的bindings,通过绑定可以让我们的程序轻装上阵,在极端情况下几乎不需要集成任何sdk,仅需要通过httpclient+text.json即可完成对外部组件的调用,这样 ...

  3. Knative 基本功能深入剖析:Knative Serving 自动扩缩容 Autoscaler

    Knative Serving 默认情况下,提供了开箱即用的快速.基于请求的自动扩缩容功能 - Knative Pod Autoscaler(KPA).下面带你体验如何在 Knative 中玩转 Au ...

  4. Nginx 反向代理工作原理简介与配置详解

    Nginx反向代理工作原理简介与配置详解   by:授客  QQ:1033553122   测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...

  5. (转)使用LVS实现负载均衡原理及安装配置详解

    使用LVS实现负载均衡原理及安装配置详解 原文:https://www.cnblogs.com/liwei0526vip/p/6370103.html

  6. k8s手动扩缩容

    1. 查询deploy副本数,ready数表示副本数 kubectl get deploy 2.通过命令直接扩容或者缩容,--replicas=1表示把my-dep缩容到副本数1,--replicas ...

  7. 使用LVS实现负载均衡原理及安装配置详解

    负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学 ...

  8. minikube metrics-server HPA 自动扩缩容错误

    minikube metrics-server pod 错误 启动 minikube addons enable metrics-server 之后查看 metrics-server pod 会有如下 ...

  9. Marathon自动扩缩容(marathon-lb-autoscale)

    我们在服务里面创建如下的应用(以下是创建完复制过来的json): { "id": "/nginxtest", "cmd": null, &q ...

  10. 使用 LVS 实现负载均衡原理及安装配置详解

    负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学 ...

随机推荐

  1. CANoe工具的安装

    CANoe是德国Vector公司为汽车总线的开发而设计的一款总线开发环境,全称叫CAN open environment,用于分析和模拟CAN(Controller Area Network)和LIN ...

  2. 常用的Java Enum JdbcType

    常用的Java Enum JdbcType ARRAY BIGINT BINARY BIT BLOB BOOLEAN CHAR CLOB CURSOR DATE DECIMAL DOUBLE FLOA ...

  3. @Repeatable元注解的使用

    @Repeatable注解表明标记的注解可以多次应用于相同的声明或类型,此注解由Java SE 8版本引入.以下示例如何使用此注解: 第一步,先声明一个重复注解类: package org.sprin ...

  4. Grafana系列-GaC-1-Grafana即代码的几种实现方式

    系列文章 Grafana 系列文章 Terraform 系列文章 概述 GaC(Grafana as Code, Grafana 即代码) 很明显是扩展自 IaC(Infrastructure as ...

  5. 自然语言处理 Paddle NLP - 情感分析技术及应用SKEP-实践

    Part A. 情感分析任务 众所周知,人类自然语言中包含了丰富的情感色彩:表达人的情绪(如悲伤.快乐).表达人的心情(如倦怠.忧郁).表达人的喜好(如喜欢.讨厌).表达人的个性特征和表达人的立场等等 ...

  6. 【.Net/C#之ChatGPT开发系列】四、ChatGPT多KEY动态轮询,自动删除无效KEY

    ChatGPT是一种基于Token数量计费的语言模型,它可以生成高质量的文本.然而,每个新账号只有一个有限的初始配额,用完后就需要付费才能继续使用.为此,我们可能存在使用多KEY的情况,并在每个KEY ...

  7. VSCode隐藏一些非必要的文件

    VSCode自动编译生成 .exe文件 很烦 所以要隐藏掉 文件,首选项,搜索 files.exclude 在后面添加 **/*.exe 即可

  8. ASP.NET MVC4 学习笔记-1

    初学ASP.NET MVC,通过博客来记录自己的学习笔记! 创建一个新的 ASP.NET MVC 项目 在新建项目中选择 ASP.NET MVC4 Web Application,项目类型为空,视图引 ...

  9. Seeion相关

    存储会话数据有两种方式: Cookie 1) 存储在浏览器端,通过服务器发送cookie数据 2) 使用cookie存储会话数据,相对不安全(可以cookie查到一些用户安全) 3) 从存储数据类型来 ...

  10. 跟运维学 Linux - 02

    文件操作和用户 复制移动和删除 在Windows中我们可以通过快捷键 ctrl + c 复制,ctrl + v 粘贴,在 linux 中需要使用命令. 复制移动 cp 就是 copy 的意思.请看示例 ...