天天看点

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-07 Kubernetes云原生监控之kube-state-metrics集群资源监控

2021-09-06

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-06 Kubernetes云原生监控之cAdvisor容器资源监控

2021-09-01

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-05 Kubernetes云原生监控之节点性能监控

2021-08-30

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-04 轻松搞定Prometheus Eureka服务发现

2021-08-25

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-03 轻松搞定Prometheus文件服务发现

2021-08-23

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】-02 一张图彻底搞懂Prometheus服务发现机制

2021-08-18

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

【prometheus】- 01 云原生时代的监控系统入门

2021-08-16

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

Prometheus服务发现机制之Kubernetes

概述

分析过云原生监控接入方案,下面开始看下云原生服务发现机制。Prometheus本身就是作为云原生监控出现的,所以对云原生服务发现支持具有天然优势。

Kubernetes

服务发现协议允许使用

Kubernetes Rest API

检索出

Prometheus

需要监控的

targets

,并且跟着集群状态进行同步变更。

kubernetes_sd_configs

表示基于

Kubernetes

进行服务发现,服务发现目标类型使用

role

表示,比如:

role=service

,表示针对

Kubernetes

中的

service

资源对象,进行具体的服务发现操作。

kubernetes_sd_configs

支持的

role

包括:

node、service、pod、endpoints、ingress

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

原理

基于

Kubernetes

进行服务发现,主要针对

Kubernetes

中的

service、pod、node

等资源对象进行服务发现,

Prometheus

使用

client-go

role

中指定的资源对象进行监听。一般

Prometheus

部署在

Kubernetes

集群中的话,

Prometheus

可以直接利用指定的

Service Account

Kubernetes API

进行访问。若

Prometheus

Kubernetes

集群之外,则

kubernetes_sd_configs

还需指定监控集群的

API Server

URL

以及相关的认证信息,从而能够创建对应集群的

Client

client-go是kubernetes官方提供的go语言的客户端库,go应用使用该库可以访问kubernetes的API Server,这样我们就能通过编程来对kubernetes资源进行增删改查操作。

配置示例:

  - job_name: kubernetes-pod
    metrics_path: /metrics
    kubernetes_sd_configs:
    - role: pod
      namespaces:
        names:
        - 'test01'
      api_server: https://apiserver.simon:6443
      bearer_token_file: d:/token.k8s 
      tls_config:
        insecure_skip_verify: true
    bearer_token_file: d:/token.k8s
    tls_config:
      insecure_skip_verify: true
           

协议分析

Kubernetes

服务发现大致原理如下图:

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

1、通过

clientset

访问

API Server

,根据

role

配置获取不同的集群资源对象;

2、通过

List & Watch

机制,注册监听事件:

p.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
 AddFunc: func(o interface{}) {
  podAddCount.Inc()
  p.enqueue(o)
 },
 DeleteFunc: func(o interface{}) {
  podDeleteCount.Inc()
  p.enqueue(o)
 },
 UpdateFunc: func(_, o interface{}) {
  podUpdateCount.Inc()
  p.enqueue(o)
 },
})
           

通过

informer.AddEventHandler

函数可以为集群资源添加资源事件回调方法,支持3种资源事件回调方法:

AddFunc、DeleteFunc、UpdateFunc

,分别对应新增资源、修改资源和删除资源时事件触发。

3、资源变更注册回调方法中,将目标资源对象转成

key

放入到队列

queue

中,如下

pod

资源:

func (p *Pod) enqueue(obj interface{}) {
    //obj是pod资源对象,通过DeletionHandlingMetaNamespaceKeyFunc将其转换成key
    //比如key=test01/nginx-deployment-5ffc5bf56c-n2pl8,即namespace/pod_name格式
 key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
 if err != nil {
  return
 }
 p.queue.Add(key)
}
           

4、后台

goroutines

无限循环执行

process

逻辑,

process

逻辑中就是不停从

queue

中提取数据进行处理,比如

pod.go

对应逻辑如下:

func (p *Pod) process(ctx context.Context, ch chan<- []*targetgroup.Group) bool {
 keyObj, quit := p.queue.Get()
 if quit {
  return false
 }
 defer p.queue.Done(keyObj)
 key := keyObj.(string)

 //与 MetaNamespaceKeyFunc() 功能相反的是 SplitMetaNamespaceKey() 函数,它将传入的 Key 分解,返回对象所在的命名空间和对象名称。
 namespace, name, err := cache.SplitMetaNamespaceKey(key)
 if err != nil {
  return true
 }
    //根据key获取资源对象obj
 o, exists, err := p.store.GetByKey(key)
 if err != nil {
  return true
 }
 if !exists {
  //pod被删除时,exists=false
  // 然后发送targets为空的tg,即移除
  send(ctx, ch, &targetgroup.Group{Source: podSourceFromNamespaceAndName(namespace, name)})
  return true
 }
 pod, err := convertToPod(o)
 if err != nil {
  level.Error(p.logger).Log("msg", "converting to Pod object failed", "err", err)
  return true
 }
    //p.buildPod(pod):将资源对象信息转成target groups
 send(ctx, ch, p.buildPod(pod))
 return true
}
           

大致逻辑:

a、根据从

queue

中提取的

key

,使用

p.store.GetByKey(key)

获取对应的资源对象,比如

pod、service

等对象;

b、如果对象不存在,则表示资源对象被删除,则创建一个

targets

集合为空的

target groups

,这样

Scrape Manager

就会移除

targets

c、使用

buildXXX(obj)

将资源对象解析成

target groups

,如

buildNode()、buildPod()

等;

d、最后使用

send()

方法将解析的

target groups

通过通道

channel

传递出去,最终传递给

Scrape Manager

,这样

target groups

targets

将被

Prometheus

抓取监控数据。

pod

资源的

target groups

结构如下示例,每个pod对象都会被解析成

target groups

,其中包含

targets

集合、

labels

标签集合:

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

Discovery创建

1、假如我们定义如下抓取作业:

- job_name: kubernetes-nodes-cadvisor
    metrics_path: /metrics
    scheme: https
    kubernetes_sd_configs:
    - role: node
      api_server: https://apiserver.simon:6443
      bearer_token_file: d:/token.k8s 
      tls_config:
        insecure_skip_verify: true
    bearer_token_file: d:/token.k8s
    tls_config:
      insecure_skip_verify: true
    relabel_configs:
    # 将标签(.*)作为新标签名,原有值不变
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.*)
    # 修改NodeIP:10250为APIServerIP:6443
    - action: replace
      regex: (.*)
      source_labels: ["__address__"]
      target_label: __address__
      replacement: 192.168.52.151:6443
    - action: replace
      source_labels: [__meta_kubernetes_node_name]
      target_label: __metrics_path__
      regex: (.*)
      replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor  
           

会被解析成

kubernetes.SDConfig

如下:

【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

kubernetes.SDConfig

定义如下:

type SDConfig struct {
 APIServer          config.URL              `yaml:"api_server,omitempty"`
 Role               Role                    `yaml:"role"`
 HTTPClientConfig   config.HTTPClientConfig `yaml:",inline"`
 NamespaceDiscovery NamespaceDiscovery      `yaml:"namespaces,omitempty"`
 Selectors          []SelectorConfig        `yaml:"selectors,omitempty"`
}
           

2、

Discovery

创建

//创建Clientset,可看成操作Kubernetes API的客户端
c, err := kubernetes.NewForConfig(kcfg)
 if err != nil {
  return nil, err
 }
return &Discovery{
  client:             c,
  logger:             l,
  role:               conf.Role,
  namespaceDiscovery: &conf.NamespaceDiscovery,
  discoverers:        make([]discovery.Discoverer, 0),
  selectors:          mapSelector(conf.Selectors),
}, nil
           

3、

Discovery

创建完成,最后会调用

Discovery.Run()

启动服务发现:

func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
 d.Lock()
 namespaces := d.getNamespaces()

 switch d.role {
 case RoleEndpointSlice:
  role=endpointslice逻辑
 case RoleEndpoint:
  role=endpoints逻辑
 case RolePod:
  role=pod逻辑
 case RoleService:
  role=service逻辑
 case RoleIngress:
  role=ingress逻辑
 case RoleNode:
  role=node逻辑
 default:
  level.Error(d.logger).Log("msg", "unknown Kubernetes discovery kind", "role", d.role)
 }

 var wg sync.WaitGroup
 for _, dd := range d.discoverers {
  wg.Add(1)
  go func(d discovery.Discoverer) {
   defer wg.Done()
   d.Run(ctx, ch)
  }(dd)
 }

 d.Unlock()

 wg.Wait()
 <-ctx.Done()
}
           

4、注册集群资源对象监听事件回调逻辑:

for _, namespace := range namespaces {
 p := d.client.CoreV1().Pods(namespace)
 plw := &cache.ListWatch{
  ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
   options.FieldSelector = d.selectors.pod.field
   options.LabelSelector = d.selectors.pod.label
   return p.List(ctx, options)
  },
  WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
   options.FieldSelector = d.selectors.pod.field
   options.LabelSelector = d.selectors.pod.label
   return p.Watch(ctx, options)
  },
 }
 pod := NewPod(
  log.With(d.logger, "role", "pod"),
  cache.NewSharedInformer(plw, &apiv1.Pod{}, resyncPeriod),
 )
 d.discoverers = append(d.discoverers, pod)
 go pod.informer.Run(ctx.Done())
}
           
【prometheus】-08 图解云原生服务发现机制Prometheus服务发现机制之Kubernetes

继续阅读