环境:
kubernetes 1.11+/openshift3.11
自定义metric HPA原理:
首选需要注册一个apiservice(custom metrics API)。
当HPA请求metrics时,kube-aggregator (apiservice的controller)会将请求转发到adapter,adapter作为kubernentes集群的pod,实现了Kubernetes resource metrics API 和custom metrics API,它会根据配置的rules从Prometheus抓取并处理metrics,在处理(如重命名metrics等)完后将metric通过custom metrics API返回给HPA。最后HPA通过获取的metrics的value对Deployment/ReplicaSet进行扩缩容。
adapter作为extension-apiserver(即自己实现的pod) ,充当了代理kube-apiserver请求Prometheus的功能。
如下是k8s-prometheus-adapter apiservice的定义,kube-aggregator 通过下面的service 将请求转发给adapter。v1beta1.custom.metrics.k8s.io 是写在k8s-prometheus-adapter代码中的,因此不能任意改变。
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1beta1.custom.metrics.k8s.io
spec:
service:
name: custom-metrics-apiserver
namespace: custom-metrics
group: custom.metrics.k8s.io
version: v1beta1
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 100
部署:
Adapter config
部署adapter前需要配置adapter的rule,用于预处理metrics,默认配置为manifests/custom-metrics-config-map.yaml 。adapter的配置主要分为4个:
-
Discovery:指定需要处理的Prometheus的metrics。通过seriesQuery挑选需要处理的metrics集合,可以通过seriesFilters精确过滤metrics。
seriesQuery可以根据标签进行查找(如下),也可以直接指定metric name查找
seriesQuery: '{__name__=~"^container_.*_total",container_name!="POD",namespace!="",pod_name!=""}'
seriesFilters:
- isNot: "^container_.*_seconds_total"
seriesFilters:
is: <regex>,匹配包含该正则表达式的metrics.
isNot: <regex>,匹配不包含该正则表达式的metrics.
-
Association:设置metric与kubernetes resources的映射关系,kubernetes resorces可以通过kubectl api-resources 命令查看。overrides会将Prometheus metric label与一个kubernetes resource(下例为deployment)关联。需要注意的是该label必须是一个真实的kubernetes resource,如metric的pod_name可以映射为kubernetes的pod resource,但不能将container_image映射为kubernetes的pod resource,映射错误会导致无法通过custom metrics API获取正确的值。这也表示metric中必须存在一个真实的resource 名称,将其映射为kubernetes resource。
resources:
overrides:
microservice: {group: "apps",resource: "deployment"}
-
Naming:用于将prometheus metrics名称转化为custom metrics API所使用的metrics名称,但不会改变其本身的metric名称,即通过curl http://$(kubectl get service sample-app -o jsonpath='{ .spec.clusterIP }')/metrics 获得的仍然是老的metric名称。如果不需要可以不执行这一步。
# match turn any name <name>_total to <name>_per_second
# e.g. http_requests_total becomes http_requests_per_second
name:
matches: "^(.*)_total$"
as: "${1}_per_second"
如本例中HPA后续可以通过/apis/{APIService-name}/v1beta1/namespaces/{namespaces-name}/pods/*/http_requests_per_second 获取metrics
-
Querying:处理调用custom metrics API获取到的metrics的value,该值最终提供给HPA进行扩缩容
# convert cumulative cAdvisor metrics into rates calculated over 2 minutes
metricsQuery: "sum(rate(<<.Series>>{<<.LabelMatchers>>,container_name!="POD"}[2m])) by (<<.GroupBy>>)"
metricsQuery 字段使用Go template将URL请求转变为Prometheus的请求,它会提取custom metrics API请求中的字段,并将其划分为metric name,group-resource,以及group-resource中的一个或多个objects,对应如下字段:
-
Series : metric名称
-
LabelMatchers : 以逗号分割的objects,当前表示特定group-resource加上命名空间的label(如果该group-resource 是namespaced的)
-
GroupBy :以逗号分割的label的集合,当前表示LabelMatchers中的group-resource label
假设metrics http_requests_per_second 如下
http_requests_per_second{pod="pod1",service="nginx1",namespace="somens"}
http_requests_per_second{pod="pod2",service="nginx2",namespace="somens"}
当调用kubectl get --raw "/apis/{APIService-name}/v1beta1/namespaces/somens/pods/*/http_request_per_second" 时,metricsQuery 字段的模板的实际内容如下:
Series: "http_requests_total"
LabelMatchers: "pod=~"pod1|pod2",namespace="somens"
GroupBy:pod
adapter使用字段rules 和externalRules 分别表示custom metrics和external metrics,如本例中
apiVersion: v1
kind: ConfigMap
metadata:
name: adapter-config
namespace: openshift-monitoring
data:
config.yaml: |
externalRules:
- seriesQuery: '{namespace!="",pod!=""}'
seriesFilters: []
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[22m])) by (<<.GroupBy>>)
rules:
- seriesQuery: '{namespace!="",pod!=""}'
seriesFilters: []
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)
HPA的配置
HPA通常会根据type从aggregated APIs (metrics.k8s.io ,custom.metrics.k8s.io ,external.metrics.k8s.io )的资源路径上拉取metrics
HPA支持的metrics类型有4种(下述为v2beta2的格式):
-
resource:目前仅支持cpu 和memory 。target可以指定数值(targetAverageValue )和比例(targetAverageUtilization )进行扩缩容
HPA从metrics.k8s.io 获取resource metrics
-
pods:custom metrics,这类metrics描述了pod类型,target仅支持按指定数值(targetAverageValue )进行扩缩容。targetAverageValue 用于计算所有相关pods上的metrics的平均值
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
HPA从custom.metrics.k8s.io 获取custom metrics
-
object:custom metrics,这类metrics描述了相同命名空间下的(非pod)类型。target支持通过value 和AverageValue 进行扩缩容,前者直接将metric与target比较进行扩缩容,后者通过metric/相关的pod数目 与target比较进行扩缩容
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: extensions/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
-
external:kubernetes 1.10+。这类metrics与kubernetes集群无关(pods和object需要与kubernetes中的某一类型关联)。与object类似,target支持通过value 和AverageValue 进行扩缩容。由于external会尝试匹配所有kubernetes资源的metrics,因此实际中不建议使用该类型。
HPA从external.metrics.k8s.io 获取external metrics
- type: External
external:
metric:
name: queue_messages_ready
selector: "queue=worker_tasks"
target:
type: AverageValue
averageValue: 30
-
1.6版本支持多metrics的扩缩容,当其中一个metrics达到扩容标准时就会创建pod副本(当前副本<maxReplicas)
注:target的value的一个单位可以划分为1000份,每一份以m 为单位,如500m表示1/2 个单位。参见Quantity
kubernetes HPA的算法如下:
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
当使用targetAverageValue 或targetAverageUtilization 时,currentMetricValue会取HPA指定的所有pods的metric的平均值
Kubernetes metrics的获取
假设注册的APIService为custom.metrics.k8s.io/v1beta1,在注册好APIService后HorizontalPodAutoscaler controller会从以/apis/custom.metrics.k8s.io/v1beta1 为根API的路径上抓取metrics。metrics的API path可以分为namespaced 和non-namespaced 类型的。通过如下方式校验HPA是否可以获取到metrics:
namespaced
- 获取指定namespace下指定object类型和名称的metrics
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/{object-type}/{object-name}/{metric-name...}"
如获取monitor 命名空间下名为grafana 的pod的start_time_seconds metric
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitor/pods/grafana/start_time_seconds"
- 获取指定namespace下所有特定object类型的metrics
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/pods/*/{metric-name...}"
如获取monitor 命名空间下名为所有pod的start_time_seconds metric
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitor/pods/*/start_time_seconds"
- 使用labelSelector可以选择带有特定label的object
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/{object-type}/{object-name}/{metric-name...}?labelSelector={label-name}"
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/pods/*/{metric-name...}?labelSelector={label-name}"
non-namespaced
non-namespaced和namespaced的类似,主要有node,namespace,PersistentVolume等。non-namespaced访问有些与custom metrics API描述不一致。
- 访问object为namespace的方式如下如下
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/metrics/{metric-name...}"
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/*/metrics/{metric-name...}"
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/nodes/{node-name}/{metric-name...}"
DEBUG:
-
使用如下方式查看注册的APIService发现的所有rules
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
如果获取失败,可以看下使用oc get apiservice v1beta1.custom.metrics.k8s.io -oyaml 查看status 和message 的相关信息
如果获取到的resource为空,则需要校验deploy中的Prometheus url是否正确,是否有权限等
-
通过如下方式查看完整的请求过程(--v=8)
kubectl get --raw “/apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace-name}/pods/*/{metric-name...}" --v=8
-
如果上述过程正确,但获取到的items为空
- 首先保证k8s-prometheus-adapter的参数
--metrics-relist-interval 设置值大于Prometheus的参数scrape_interval
- 确保k8s-prometheus-adapter
rules 的seriesQuery 规则可以抓取到Prometheus的数据
- 确保k8s-prometheus-adapter
rules 的metricsQuery 规则可以抓取到计算出数据,此处需要注意的是,如果使用到了计算某段时间的数据,如果时间设置过短,可能导致没有数据生成
TIPS:
-
官方提供了End-to-end walkthrough,但需要采集的metrics中包含pod 和namespace label,否则在官方默认配置下无法采集到metrics。
-
Configuration Walkthroughs一步步讲解了如何配置adapter config
-
在goland里面使用如下参数可以远程调试adapter:
--secure-port=6443 --tls-cert-file=D:adapterserving.crt --tls-private-key-file=D:adapterserving.key --logtostderr=true --prometheus-url=${prometheus-url} --metrics-relist-interval=70s --v=10 --config=D:adapterconfig.yaml --lister-kubeconfig=D:adapterk8s-config.yaml --authorization-kubeconfig=D:adapterk8s-config.yaml --authentication-kubeconfig=D:adapterk8s-config.yaml
参考:
Kubernetes pod autoscaler using custom metrics
Kubernetes API Aggregation Setup — Nuts & Bolts
Configure the Aggregation Layer
Aggregation
Setup an Extension API Server
OpenShift下的JVM监控 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|