背景

单个Prometheus Server可以轻松的处理数以百万的时间序列。但当机器规模过大时,需要对其进行分区,Prometheus也提供了集群联邦的功能,方便对其扩展。

我们采用Prometheus来监控k8s集群,节点数400,采集的samples是280w,Prometheus官方的显示每秒可抓取10w samples。当集群规模扩大到上千节点时,单个Prometheus不足以处理大量数据,需要对其进行分区。

可以根据scrape_samples_scraped{job=${JOBNAME}}来统计各个job的samples数目
可以根据count({__name__=~".*:.*"})来统计metrics总数

集群联邦

在Promehtues的源码中,federate联邦功能在web中,是一个特殊的查询接口,允许一个prometheus抓取另一个prometheus的metrics

可以通过全局的prometheus抓取其他slave prometheus从而达到分区的目的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7qOY1MRZ-1585894206562)(/img/blogImg/federate1.png)]

使用federate进行分区通过有两种方式

功能分区

每个模块为一个分区,如node-exporter为一个分区,kube-state-metrics为一个分区,再使用全局的Prometheus汇总
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zIDTaunU-1585894206563)(/img/blogImg/federate2.png)]

实现简单,但当单个job采集任务过大(如node-exporter)时,单个Prometheus slave也会成为瓶颈

水平扩展

针对功能分区的不足,将同一任务的不同实例的监控数据采集任务划分到不同的Prometheus实例。通过relabel设置,我们可以确保当前Prometheus Server只收集当前采集任务的一部分实例的监控指标。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-us7STebx-1585894206564)(/img/blogImg/federate3.png)]

下为官方提供的配置

global:
  external_labels:
    slave: 1  # This is the 2nd slave. This prevents clashes between slaves.
scrape_configs:
  - job_name: some_job
    # Add usual service discovery here, such as static_configs
    relabel_configs:
    - source_labels: [__address__]
      modulus:       4    # 4 slaves
      target_label:  __tmp_hash
      action:        hashmod
    - source_labels: [__tmp_hash]
      regex:         ^1$  # This is the 2nd slave
      action:        keep

并且通过当前数据中心的一个中心Prometheus Server将监控数据进行聚合到任务级别。

- scrape_config:
  - job_name: slaves
    honor_labels: true
    metrics_path: /federate
    params:
      match[]:
        - '{__name__=~"^slave:.*"}'   # Request all slave-level time series
    static_configs:
      - targets:
        - slave0:9090
        - slave1:9090
        - slave3:9090
        - slave4:9090

水平扩展,即通过联邦集群的特性在任务的实例级别对Prometheus采集任务进行划分,以支持规模的扩展。

我们的方案

整体架构

  • Promehtues以容器化的方式部署在k8s集群中
  • 收集node-exporter、cadvisor、kubelet、kube-state-metrics、k8s核心组件、自定义metrics
  • 通过实现opentsdb-adapter,对监控数据做持久化
  • 通过falcon-adapter,为监控数据提供报警
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mwp5Hzcp-1585894206564)(/img/blogImg/Promehtues-arch.png)]

分区方案

  • Prometheus分区包括master Prometheus 与 slave Promehtues
  • 我们将监控数据分为多个层次: cluster, namespace, deployment/daemonset, pod, node
  • 由于kubelet, node-exporter, cadvisor等是以node为单位采集的,所以安装node节点来划分不同job
  • slave Prometheus 按照node切片采集node,pod级别数据
  • kube-state-metrics暂时无法切片,可通过replicaset 设置多个,单独作为一个kube-state Prometheus,供其他slave Prometheus采集
  • 其他etcd, apiserver等自定义组件可通过master Promehtues直接采集

整体架构如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SUoPzH87-1585894206564)(/img/blogImg/federate-plan.png)]

master Prometheus配置

global:
  scrape_interval: 60s
  scrape_timeout: 30s
  evaluation_interval: 60s
  external_labels:
    cluster: {{CLUSTER}}
    production_environment: {{ENV}}

rule_files:
- cluster.yml
- namespace.yml
- deployment.yml
- daemonset.yml

scrape_configs:

- job_name: federate-slave
  honor_labels: true
  metrics_path: '/federate'
  params:
    'match[]':
      - '{__name__=~"pod:.*|node:.*"}'
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names:
      - kube-system
  relabel_configs:
  - source_labels:
    - __meta_kubernetes_pod_label_app
    action: keep
    regex: prometheus-slave.*
  - source_labels:
    - __meta_kubernetes_pod_container_port_number
    action: keep
    regex: 9090

- job_name: federate-kubestate
  honor_labels: true
  metrics_path: '/federate'
  params:
    'match[]':
      - '{__name__=~"deployment:.*|daemonset:.*"}'
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names:
      - kube-system
  relabel_configs:
  - source_labels:
    - __meta_kubernetes_pod_label_app
    action: keep
    regex: prometheus-kubestate.*
  - source_labels:
    - __meta_kubernetes_pod_container_port_number
    action: keep
    regex: 9090

slave Prometheus配置

global:
  scrape_interval: 60s
  scrape_timeout: 30s
  evaluation_interval: 60s
  external_labels:
    cluster: {{CLUSTER}}
    production_environment: {{ENV}}

rule_files:
- node.yml
- pod.yml

scrape_configs:

- job_name: federate-kubestate
  honor_labels: true
  metrics_path: '/federate'
  params:
    'match[]':
      - '{__name__=~"pod:.*|node:.*"}'
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names:
      - kube-system
  relabel_configs:
  - source_labels:
    - __meta_kubernetes_pod_label_app
    action: keep
    regex: prometheus-kubestate.*
  - source_labels:
    - __meta_kubernetes_pod_container_port_number
    action: keep
    regex: 9090
  metric_relabel_configs:
  - source_labels: [node]
    modulus:       {{MODULES}}
    target_label:  __tmp_hash
    action:        hashmod
  - source_labels: [__tmp_hash]
    regex:         {{SLAVEID}}
    action:        keep

- job_name: kubelet
  scheme: https
  kubernetes_sd_configs:
  - role: node
    namespaces:
      names: []
  tls_config:
    insecure_skip_verify: true
  relabel_configs:
  - source_labels: []
    regex: __meta_kubernetes_node_label_(.+)
    replacement: "$1"
    action: labelmap
  - source_labels: [__meta_kubernetes_node_label_kubernetes_io_hostname]
    modulus:       {{MODULES}}
    target_label:  __tmp_hash
    action:        hashmod
  - source_labels: [__tmp_hash]
    regex:         {{SLAVEID}}
    action:        keep

- job_name: ...

可能的问题

  • 如何部署,配置复杂,现在采用shell脚本加kustomize,是否有更简单的方法
  • 分区的动态扩展随着node的规模
  • kube-state-metrics是否会成为瓶颈,目前的kube-state-metrics性能测试
  • 由于分区同一个job的不同instance采集的时间有偏差,对聚合有一定影响
  • 可靠性保证,如果一个或多个slave的挂了如何处理,使用k8s来保证prometheus的可用性是否可靠