抽丝剥茧--从零开始建设k8s监控之水平拆分(五)

前言

书接上文,经过之前的不懈努力,我们已经有了较为完善的监控系统与告警系统,而prometheus的工作模式就像一个单点,拉取数据回来之后存储在自己的磁盘上

当监控数据越来越多,那prometheus单点的压力就会变大,那本文就来讨论一下如何降低单点prometheus的压力

环境准备

组件 版本
操作系统 Ubuntu 22.04.4 LTS
docker 24.0.7
kube-state-metrics v2.13.0
thanos 0.36.1

水平拆分

水平拆分的目的就是为了拆成多个prometheus,让单个prometheus负载降低,不要这么容易挂掉,并且拆成多个之后,就算挂掉一个,其余的也可以正常工作。比如一个prometheus专门负责节点监控数据采集、一个prometheus专门负责k8s监控数据采集等

1. 根据采集的目标进行拆分

每个业务都有一个prometheus对其进行采集,并且不同prometheus之间解耦

这时候业务部门提出需求,k8s的监控还是太多了,一个prometheus依然不堪重负,那怎么办呢?

2. kube-state-metrics拆分

由于k8s是通过kube-state-metrics这个exporter进行采集,所以我们需要对其进行拆分

2.1 根据namespace进行拆分

这个拆分是显而易见的,不同的namespace采集进入不同的prometheus即可,配置也很简单,只需要修改kube-state-metrics的启动参数即可

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-state-metrics
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kube-state-metrics
  template:
    metadata:
      labels:
        app: kube-state-metrics
    spec:
      serviceAccountName: kube-state-metrics
      containers:
      - args:
        - --metric-labels-allowlist=pods=[*]
        - --metric-annotations-allowlist=pods=[*]
        - --namespaces=default # 新增
        name: kube-state-metrics
        image: registry.cn-beijing.aliyuncs.com/wilsonchai/kube-state-metrics:v2.13.0
        ports:
        - containerPort: 8080

--namespaces=default 告诉kube-state-metrics只采集namespace为default的数据

创建多个prometheus以及kube-state-metrics,然后指定采集不同的namespace

这种方法配置简单,但是分配多个kube-state-metrics的采集策略就比较复杂,一旦业务复杂,namespace多起来之后,也会造成频繁修改配置,还有没有更简单的方法呢?

2.2 kube-state-metrics根据shard拆分

kube-state-metrics的高版本(具体是哪个版本待查,笔者的版本是v2.13.0),支持了自动分片的采集策略,就是让多个kube-state-metrics自己去分片,省去人为配置的烦恼

关于水平分片的例子,可以参考 kube-state-metrics

复制代码
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: v2.13.0
  name: kube-state-metrics
  namespace: kube-system
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - apps
  resourceNames:
  - kube-state-metrics
  resources:
  - statefulsets
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: v2.13.0
  name: kube-state-metrics
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kube-state-metrics
subjects:
- kind: ServiceAccount
  name: kube-state-metrics
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: v2.13.0
  name: kube-state-metrics
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: kube-state-metrics
  serviceName: kube-state-metrics
  template:
    metadata:
      labels:
        app.kubernetes.io/name: kube-state-metrics
        app.kubernetes.io/version: v2.13.0
    spec:
      containers:
      - args:
        - --pod=$(POD_NAME)
        - --pod-namespace=$(POD_NAMESPACE)
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: registry.cn-beijing.aliyuncs.com/wilsonchai/kube-state-metrics:v2.13.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          timeoutSeconds: 5
        name: kube-state-metrics
        ports:
        - containerPort: 8080
          name: http-metrics
        - containerPort: 8081
          name: telemetry
        readinessProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 5
          timeoutSeconds: 5
        securityContext:
          runAsUser: 65534
      nodeSelector:
        kubernetes.io/os: linux
      serviceAccountName: kube-state-metrics

启动起来之后检查一下metrics的指标数量

复制代码
▶ curl -s 10.244.0.107:8080/metrics | wc -l
949
▶ curl -s 10.244.0.108:8080/metrics | wc -l
909

看起来已经打散到2个节点去了,如果我再增加一个节点,那指标数量又分散了

复制代码
▶ curl -s 10.244.0.107:8080/metrics | wc -l
702
▶ curl -s 10.244.0.108:8080/metrics | wc -l
733
▶ curl -s 10.244.0.109:8080/metrics | wc -l
663

这时候只需要把不同的prometheus配置采集不同kube-state-metrics即可,架构也变成了这个样子

当然kube-state-metrics也是有手动分片模式的,就是通过参数--shard来实现了,只不过有自动分片的话,没有极致特殊的需求,我们还是用自动分片来处理更加合适

多prometheus数据汇聚

当我们拆分了监控数据,用不同的prometheus来采集的时候,又带来了新的问题

  • 由于prometheus使用本地磁盘存储数据,所以通过prometheus的web界面查看监控数据时,也只能查看到本prometheus的监控数据,不能跨prometheus查询监控数据

  • 使用grafana添加数据源的时候,就出现了多prometheus数据源的情况,造成管理复杂

  • 有一个公共的storage组件,prometheus通过remote_write的方式,把数据汇聚在这个组件,就可以解决数据分散的问题,并且数据存储的方式就很灵活了,可以存储在本地,然后通过传统的raid做数据备份,也可以直接通过云 平台的对象存储保存历史数据

  • 最后再来一个统一的web界面进行查询,同时这个web界面兼容了prometheus的promQL,并且兼容了prometheus的api,可以直接作为数据源添加至grafana中

  • 有这种功能的组件就很多了,比如thanos、cortext、influxDB等等,都可以完成这个工作

小结

  • 下一小节,通过thanos来详细讨论一下怎么做数据汇聚

联系我

  • 联系我,做深入的交流

至此,本文结束

在下才疏学浅,有撒汤漏水的,请各位不吝赐教...