likes
comments
collection
share

k8s节点资源用量和metric-server

作者站长头像
站长
· 阅读数 19

写在前面

在资源监控层面,我们都知道prometheus是一个最佳的选择,它提供了各种维度的指标监控能力,并且支持自定义指标以及指标聚合,但是部署一个prometheus在有时候却不是一个最佳的选择,特别是在某些情况下,我们只需要获取资源的核心指标(指cpu和memory的使用量),我们有更便捷的选择。

一个非常常用的命令,kubectl top node ,即可获取节点的cpu和memory的使用量以及总量。

# kubectl top node
NAME            CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
10.56.227.185   3034m        19%    23352Mi         69%
10.56.227.186   2509m        15%    25795Mi         76%
10.56.227.187   3866m        24%    26068Mi         77%

而kubectl top 底层则是调用了metrics-server的API来获取节点的cpu和memory的使用量,那metrics-server是什么呢?

本文基于:metrics-server-0.5.2分析。

项目地址:github.com/kubernetes-…

概述

从Kubernetes v1.8 开始,资源使用情况的监控可以通过 metrics API的形式获取,例如节点的CPU和内存使用量。这些度量可以由用户直接访问(例如,通过使用kubectl top命令),或者由集群中的控制器(例如,Horizontal Pod Autoscaler)使用来进行决策,具体的组件为metric-server,用来替换之前的heapster,heapster从1.11开始逐渐被废弃。

Metrics-Server是集群核心监控数据的聚合器。通俗地说,它存储了集群中各节点的监控数据,并且提供了API以供分析和使用。Metrics-Server作为一个 Deployment对象默认部署在Kubernetes集群中。不过准确地说,它是Deployment,Service,ClusterRole,ClusterRoleBinding,APIService,RoleBinding等资源对象的综合体。

需要注意的是:

  • metrics-server提供的是实时的指标(实际是最近一次采集的数据,保存在内存中),并没有数据库来存储
  • 这些数据指标并非由metrics-server本身采集,而是由每个节点上的cadvisor采集,metrics-server只是发请求给cadvisor并将metric格式的数据转换成aggregate api
  • 由于需要通过aggregate api来提供接口,需要集群中的kube-apiserver开启该功能(开启方法可以参考官方社区的文档)

从metrics-server讲起,首先要讲apiservice的概念。

Apiservice

apiservice是kubernetes中的一类资源,和deployment,secret这些资源类似,我们使用kubectl get apiservice可以查看集群中的apiservice。

# kubectl get apiservices
NAME                                   SERVICE                      AVAILABLE   AGE
v1.                                    Local                        True        2y31d
v1.admissionregistration.k8s.io        Local                        True        58d
v1.apiextensions.k8s.io                Local                        True        58d
v1.apps                                Local                        True        2y31d
v1.authentication.k8s.io               Local                        True        2y31d
v1.authorization.k8s.io                Local                        True        2y31d
v1.autoscaling                         Local                        True        2y31d
v1.batch                               Local                        True        2y31d

当我们在集群中部署了metric-server之后,也可以使用kubectl get方法查询到对应的apiservice。

# kubectl get apiservice| grep v1beta1.metrics.k8s.io
v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        68d

原理

metrics-server一方面会调用kubelet暴露的metrics接口获取当前的资源使用情况,另一方面会启动apiserver供kubectl top等客户端调用。

Metrics-server定时从Kubelet的Summary API(类似/ap1/v1/nodes/nodename/stats/summary)采集指标信息,这些聚合过的数据将存储在内存中,且以metric-api的形式暴露出去。

Metrics-server复用了api-server的库来实现自己的功能,比如鉴权、版本等,为了实现将数据存放在内存中,去掉了默认的etcd存储,引入了内存存储(即实现Storage interface)。

因为存放在内存中,因此监控数据是没有持久化的,可以通过第三方存储来拓展。

主要是起了两个client,一个是kube-apiserverclient用来获取集群中node资源,另一个client则是调用节点上cadvisor的接口获取节点和podcpumemory监控数据,同时也创建了一个metricSink用来保存获取的监控数据。

k8s节点资源用量和metric-server

用法

话不多说,直接说一下如何使用。

我们可以先通过命令行调用的方式来体验一下效果:

# kubectl get nodes.v1beta1.metrics.k8s.io
NAME            CPU           MEMORY       WINDOW
10.56.227.185   3209942504n   23144692Ki   21s
10.56.227.186   2312842680n   26126244Ki   32s
10.56.227.187   3987327962n   27829312Ki   31s

返回的三个指标分别是CPU,MEMORY和WINDOW,其中CPU和MEMORY分别表示cpu和内存的使用量,而WINDOW表示的是指标收集的时间间隔。在代码中是如此写的:

// The following fields define time interval from which metrics were
// collected from the interval [Timestamp-Window, Timestamp].
Timestamp metav1.Time     `json:"timestamp" protobuf:"bytes,2,opt,name=timestamp"`
Window    metav1.Duration `json:"window" protobuf:"bytes,3,opt,name=window"`

此外,关于CPU的单位是n(1m=1000*1000n,1core=1000m),内存的单位是Ki(1Mi=1024Ki,1Gi=1024Mi),也就是说3209942504n=3.21core。

Demo

这段代码demo展示了如何连接kubeClient和metricsClient来查询节点的cpu和内存的总量,可分配量以及使用量。

package main

import (
   "context"
   "fmt"
   "os"
   "time"

   corev1 "k8s.io/api/core/v1"
   metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
   "k8s.io/apimachinery/pkg/runtime"
   "k8s.io/client-go/tools/clientcmd"
   apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
   metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned"
   "sigs.k8s.io/controller-runtime/pkg/client"
)

func main() {
   // 1. 读取kubeconfig文件
   kubeconfig, err := os.ReadFile("kubeconfig.yaml")
   if err != nil {
      panic(err)
   }

   // 2. 根据kubeconfig文件生成kubeconfig对象
   apiconfig, err := clientcmd.Load(kubeconfig)
   if err != nil {
      panic(err)
   }
   clientConfig := clientcmd.NewDefaultClientConfig(*apiconfig, &clientcmd.ConfigOverrides{})
   cfg, err := clientConfig.ClientConfig()
   if err != nil {
      panic(err)
   }
   cfg.Timeout = 5 * time.Second

   // 3. 注册scheme,我们要查询node和apiservice两类资源
   scheme := runtime.NewScheme()
   if err = corev1.AddToScheme(scheme); err != nil {
      panic(err)
   }
   if err = apiregistrationv1.AddToScheme(scheme); err != nil {
      panic(err)
   }
   
   // 4. 生成集群的kubeclient
   kubeClient, err := client.New(cfg, client.Options{
      Scheme: scheme,
   })
   if err != nil {
      panic(err)
   }

   // 5. 查询metrics-server的apiservice是否存在,如果不存在,则说明集群没有安装metrics-server
   apiservices := &apiregistrationv1.APIService{}
   if err = kubeClient.Get(context.TODO(), client.ObjectKey{Name: "v1beta1.metrics.k8s.io"}, apiservices); err != nil {
      panic(err)
   }

   // 6. 生成metrics-server的client
   mclient, err := metricsclientset.NewForConfig(cfg)
   if err != nil {
      panic(err)
   }
   
   // 7. 查询节点的资源信息并输出,其中cpu和内存的总量以及可用量从node中获取,使用量需要从metrics-server中获取
   nodeList := &corev1.NodeList{}
   err = kubeClient.List(context.TODO(), nodeList, &client.ListOptions{})
   if err != nil {
      panic(err)
   }
   for _, node := range nodeList.Items {
      fmt.Println("----------" + node.Name + "-----------")
      metrics, err := mclient.MetricsV1beta1().NodeMetricses().Get(context.TODO(), node.Name, metav1.GetOptions{})
      if err != nil {
         panic(err)
      }
      fmt.Printf("CPU Total: %v , CPU Allocatable: %v, CPU Usage:%v\n", node.Status.Capacity.Cpu(), node.Status.Allocatable.Cpu(), metrics.Usage.Cpu())
      fmt.Printf("Memory Total: %v ,Memory Allocatable: %v, Memory usage:%v\n", node.Status.Capacity.Memory(), node.Status.Allocatable.Memory(), metrics.Usage.Memory())
      fmt.Println("______________________________________")
   }
}

运行结果:

----------10.56.227.185-----------
CPU Total: 16 , CPU Allocatable: 15800m, CPU Usage:3356816604n
Memory Total: 35008528Ki ,Memory Allocatable: 34381840Ki, Memory usage:22874236Ki
______________________________________
----------10.56.227.186-----------
CPU Total: 16 , CPU Allocatable: 15800m, CPU Usage:3473613140n
Memory Total: 35008544Ki ,Memory Allocatable: 34381856Ki, Memory usage:26397832Ki
______________________________________

参考

www.cnblogs.com/zhangmingch…

yost.top/2020/05/17/…

blog.dianduidian.com/post/kubern…