一、前言
metrics-server、custom-metrics-server以aggregator方式集成到apiserver中,集成方式见下图:
图1 出自:blog.jetstack.io/blog/resour…
二、metrics-server
1、metrics-server获取指标的方式
图2 Resource Metrics Pipeline
图中从右到左的架构组件包括以下内容:
- cAdvisor: 用于收集、聚合和公开 Kubelet 中包含的容器指标的守护程序。
- kubelet: 用于管理容器资源的节点代理。 可以使用
/metrics/resource和/statskubelet API 端点访问资源指标。 - Summary API: kubelet 提供的 API,用于发现和检索可通过
/stats端点获得的每个节点的汇总统计信息。 - metrics-server: 集群插件组件,用于收集和聚合从每个 kubelet 中提取的资源指标。 API 服务器提供 Metrics API 以供 HPA、VPA 和
kubectl top命令使用。Metrics Server 是 Metrics API 的参考实现。 - Metrics API: Kubernetes API 支持访问用于工作负载自动缩放的 CPU 和内存。 要在你的集群中进行这项工作,你需要一个提供 Metrics API 的 API 扩展服务器。
说明: cAdvisor 支持从 cgroups 读取指标,它适用于 Linux 上的典型容器运行时。 如果你使用基于其他资源隔离机制的容器运行时,例如虚拟化,那么该容器运行时必须支持 CRI 容器指标 以便 kubelet 可以使用指标。
2、可扩展性限制
我们希望从集群中运行的每个 pod 和节点收集最多 10 个指标。从 Kubernetes 1.6 开始,我们支持 5000 个节点的集群,每个节点 30 个 pod。假设我们想要以 1 分钟的粒度收集指标,这意味着:
10 x 5000 x 30 / 60 = 25000 metrics per second by average
Kubernetes apiserver 将所有 Kubernetes 资源保存在其键值存储etcd中。它无法处理这样的负载。另一方面,指标往往会经常变化,是暂时的,如果它们丢失了,我们可以在下一次内务处理操作中收集它们。 然后我们将它们存储在内存中。 这意味着我们不能重用主要的apiserver,而是引入一个新的 - metrics server。
3、Metrics API
特性状态: Kubernetes 1.8 [beta]
metrics-server 实现了 Metrics API。此 API 允许你访问集群中节点和 Pod 的 CPU 和内存使用情况。 它的主要作用是将资源使用指标提供给 K8s 自动缩放器组件。
下面是一个 minikube 节点的 Metrics API 请求示例,通过 jq 管道处理以便于阅读:
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes/minikube" | jq '.'
这是使用 curl 来执行的相同 API 调用:
curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/nodes/minikube
响应示例:
{
"kind": "NodeMetrics",
"apiVersion": "metrics.k8s.io/v1beta1",
"metadata": {
"name": "minikube",
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/minikube",
"creationTimestamp": "2022-01-27T18:48:43Z"
},
"timestamp": "2022-01-27T18:48:33Z",
"window": "30s",
"usage": {
"cpu": "487558164n",
"memory": "732212Ki"
}
}
下面是一个 kube-system 命名空间中的 kube-scheduler-minikube Pod 的 Metrics API 请求示例, 通过 jq 管道处理以便于阅读:
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube" | jq '.'
这是使用 curl 来完成的相同 API 调用:
curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube
响应示例:
{
"kind": "PodMetrics",
"apiVersion": "metrics.k8s.io/v1beta1",
"metadata": {
"name": "kube-scheduler-minikube",
"namespace": "kube-system",
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-scheduler-minikube",
"creationTimestamp": "2022-01-27T19:25:00Z"
},
"timestamp": "2022-01-27T19:24:31Z",
"window": "30s",
"containers": [
{
"name": "kube-scheduler",
"usage": {
"cpu": "9559630n",
"memory": "22244Ki"
}
}
]
}
4、节点指标获取
kubectl get --raw "/api/v1/nodes/minikube/proxy/metrics/resource
说明: 从metrics-server0.6.x 开始,metricsserver查询
metrics/resourcekubelet 端点, 不查询/stats/summary。
5、metrics-server从节点获取指标最长周期
GetMetrics-->collectNode-->Scrape-->NewScraper-->Config-->runCommand-->options.ServerConfig()-->o.KubeletClient.KubeletRequestTimeout
获取指标周期:maxDelayMs(4s) + KubeletRequestTimeout(10s) = 14s
...
delayMs := delayPerSourceMs * len(nodes)
if delayMs > maxDelayMs {
delayMs = maxDelayMs
}
...
for _, node := range nodes {
go func(node *corev1.Node) {
// Prevents network congestion.
sleepDuration := time.Duration(rand.Intn(delayMs)) * time.Millisecond
time.Sleep(sleepDuration)
// make the timeout a bit shorter to account for staggering, so we still preserve
// the overall timeout
ctx, cancelTimeout := context.WithTimeout(baseCtx, c.scrapeTimeout)
defer cancelTimeout()
klog.V(2).InfoS("Scraping node", "node", klog.KObj(node))
m, err := c.collectNode(ctx, node)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
klog.ErrorS(err, "Failed to scrape node, timeout to access kubelet", "node", klog.KObj(node), "timeout", c.scrapeTimeout)
} else {
klog.ErrorS(err, "Failed to scrape node", "node", klog.KObj(node))
}
}
responseChannel <- m
}(node)
...
func NewKubeletClientOptions() *KubeletClientOptions {
o := &KubeletClientOptions{
KubeletPort: 10250,
KubeletPreferredAddressTypes: make([]string, len(utils.DefaultAddressTypePriority)),
KubeletRequestTimeout: 10 * time.Second,
}
for i, addrType := range utils.DefaultAddressTypePriority {
o.KubeletPreferredAddressTypes[i] = string(addrType)
}
return o
}
...
文章引用: kubernetes官方文档kubernetes.io/zh-cn/docs/…