使用prometheus+grafana监控k8s集群

Prometheus官网地址:https://prometheus.io/

GitHub地址:https://github.com/prometheus/prometheus

一、prometheus的安装

        Prometheus是最初由SoundCloud开发的监控和警报工具,于2016年加入了 Cloud Native Computing Foundation,这是继Kubernetes之后的第CNC的二个托管项目。

1、prometheus的特征

(1)具有由metric名称和键/值对标识的时间序列数据的多维数据模型

(2)有⼀个灵活的查询语⾔

(3)不依赖分布式存储,只和本地磁盘有关

(4)通过HTTP的服务拉取时间序列数据

(5)⽀持推送的⽅式来添加时间序列数据

(6)⽀持通过服务发现或静态配置发现⽬标

(7)多种图形和仪表板⽀持

2、prometheus的组件

        Prometheus生态系统包含许多组件,部分组件是可选组件,主要的组件如下:

(1)Prometheus Server:⽤于抓取指标、存储时间序列数据

(2)exporter:暴露指标让任务来抓

(3)pushgateway:push的⽅式将指标数据推送到该⽹关

(4)alertmanager:处理报警的报警组件

(5)adhoc:⽤于数据查询的组件

3、prometheus的安装

        Prometheus的二进制安装非常简单,只需要在prometheus的官方网站下载对应版本的二进制包,可通过prometheus的程序制定配置文件即可启动。此处我的prometheus运行在k8s集群中,所以我通过deployment控制器去运行prometheus运行。

(1)创建prometheus配置文件

          默认的prometheus的配置为如下:

~]# cat prometheus-2.21.0.linux-386/prometheus.yml | grep -Ev "^#|^[[:space:]]{1,}#|^$"
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
alerting:
  alertmanagers:
  - static_configs:
    - targets:
rule_files:
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
    - targets: ['localhost:9090']

Prometheus的主要几个配置参数说明如下:

      1)scrape_interval:表示    prometheus   抓取指标数据的频率,默认是15s

      2)evaluation_interval:⽤来控制评估规则的频率,prometheus使⽤规则产⽣新的时间序列数据或者产⽣警报

      3)rule_files   模块制定了规则所在的位置,prometheus可以根据这个配置加载规则,⽤于⽣成新的时间 序列数据或者报警信息

      4)scrape_configs:⽤于控制prometheus监控哪些资源。由于  prometheus通过HTTP的⽅式来暴露的它本身的监控数据,prometheus也能够监控本身的健康情况。在默认的配置⾥有⼀个单独的job叫 做prometheus,它采集prometheus   服务本身的时间序列数据。这个job包含了⼀个单独的、静态配 置的⽬标:监听localhost上的9090端⼝。prometheus      默认会通过⽬标的/metrics路径采集metrics。

        为了方便在k8s中prometheus使用配置文件,我们需要将配置文件通过ConfigMap的形式进行管理

# 定义所有的资源之前先创建一个名称空间
~]# kubectl create namespace prometheus
# 定义prometheus的configmap资源
]# cat prometheus-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: prometheus
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    scrape_configs:
    - job_name: 'prometheus'
      static_configs:
      - targets: ['localhost:9090']
# 创建资源
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config created

(2)为prometheus中的数据库创建存储资源

        为了防止prometheus所在的pod故障导致数据丢失,我们需要为prometheus的TSDB创建一个pvc。这里使用之前创建的基于nfs的存储类实现动态的pv供给。

# 定义pvc资源
]# cat prometheus-pvc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: prometheus
  namespace: prometheus
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
# 创建资源
]# kubectl apply -f prometheus-pvc.yaml 
persistentvolumeclaim/prometheus created

(3)通过rbac为prometheus授权

        由于prometheus需要访问Kubernetes集群中的相关信息,所以我们需要为prometheusc创建一个ServiceAccount,并授予相关的权限。

# 定义sa资源
]# cat prometheus-sa.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata: 
  name: prometheus
  namespace: prometheus
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  - services
  - endpoints
  - pods
  - nodes/proxy
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - configmaps
  - nodes/metrics
  verbs:
  - get
- nonResourceURLs:
  - /metrics
  verbs:
  - get
---
kind: ClusterRoleBinding 
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: prometheus
  namespace: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: Prometheus
# 创建sa资源
]# kubectl apply -f prometheus-sa.yaml 
serviceaccount/prometheus created
clusterrole.rbac.authorization.k8s.io/prometheus created
clusterrolebinding.rbac.authorization.k8s.io/prometheus created

(4)为prometheus创建deployment控制器

        相关的配置文件及依赖的存储资源定义好之后就可以为prometheus创建deployment控制器。

# 定义deployment控制器资源
]# cat prometheus-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: prometheus
  labels:
    app: prometheus
spec:
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      serviceAccountName: prometheus
      containers:
      - image: prom/prometheus:v2.21.0
        name: prometheus
        command:
        - "/bin/prometheus"
        args:
        - "--config.file=/etc/prometheus/prometheus.yml"
        - "--storage.tsdb.path=/prometheus"
        - "--storage.tsdb.retention=24h"
        #控制对adminHTTPAPI的访问,其中包括删除时间序列等功能
        - "--web.enable-admin-api" 
        #⽀持热更新,直接执⾏localhost:9090/-/reload⽴即⽣效	
        - "--web.enable-lifecycle"
        ports:
        - containerPort: 9090
          protocol: TCP
          name: http
        volumeMounts:
        - mountPath: "/prometheus"
          subPath: prometheus
          name: data
        - mountPath: "/etc/prometheus"
          name: config-volume
        resources:
          requests:
            cpu: 200m
            memory: 512Mi
          limits:
            cpu: 200m
            memory: 512Mi
      # 由于prometheusdocker中是以nobody身份运行,所以要定义该项
      securityContext:
        runAsUser: 0  
      volumes: 
      - name: data
        persistentVolumeClaim:
          claimName: prometheus
      - configMap:
          name: prometheus-config
        name: config-volume
# 创建并查看运行状态
]# kubectl apply -f prometheus-deployment.yaml 
deployment.apps/prometheus created
]# kubectl get pods -n prometheus
NAME                         READY   STATUS    RESTARTS   AGE
prometheus-97bf69799-64n7w   1/1     Running   0          9s

(5)定义service资源通过集群外部访问

         Prometheus的pod控制器创建成功后,为了便于在k8s集群外部访问prometheus,我们需要为k8s集群创建nodeport类型的service资源。

# 定义service资源
]# cat prometheus-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: prometheus
  labels:
    app: prometheus
spec:
  selector:
    app: prometheus
  type: NodePort
  ports:
  - name: web
    port: 9090
targetPort: 9090
# 创建并查看service资源
]# kubectl apply -f prometheus-svc.yaml 
service/prometheus created
]# kubectl get svc -n prometheus
NAME         TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
prometheus   NodePort   10.111.61.27   <none>        9090:31736/TCP   16s

         至此,prometheus监控已经在k8s集群中安装完毕,可以通过node节点ip加映射至node节点的端口号去访问设置prometheus监控。

二、prometheus的使用

       Prometheus的监控数据指标是通过⼀个公开的(HTTP(S))数据接⼝获取到的,不需要单独安装监控的agent,只需要暴露⼀个metrics接⼝,Prometheus就会定期去拉取数据; 对于⼀些普通的HTTP服务,我们完全可以直接给这个服务添加⼀个/metrics接⼝暴露给 Prometheus;⽽且获取到的指标数据格式是⾮常易懂的,不需要太⾼的学习成本。现在很多服务从⼀开始就内置了⼀个/metrics  接⼝,⽐如Kubernetes的各个组件;有⼀些服务即使没有原⽣集成该接⼝,也完全可以使⽤⼀些exporter来获取到指标数据⽐如mysqld_exporter、node_exporter,类似于传统监控服务中的agent。

1、kubernetes集群节点的监控

(1)集群节点需要监控的内容

       1)kubernetes集群node几点的监控,包括cpu,内存,负载、磁盘等

       2)内部系统组件的状态:⽐如kube-scheduler、kube-controller-manager、kubedns/coredns等组件的详细运⾏状态

3)编排级的资源:⽐如Deployment的状态、资源请求、调度和API 延迟等数据指标

(2)kubernetes集群的监控方案

       1)Heapster:Heapster是⼀个集群范围的监控和数据聚合⼯具,以  Pod 的形式运⾏在集群中,目前Heapster已经被metrics-server所代替。

       2)cAdvisor:cAdvisor是 Google 开源的容器资源监控和性能分析⼯具,它是专⻔为容器⽽⽣,本身也⽀持 Docker 容器,在 Kubernetes 中,我们不需要单独去安装,cAdvisor 作为 kubelet 内置的⼀部分程序可以直接使⽤。

      3)Kube-state-metrics:kube-state-metrics通过监听API    Server⽣成有关资源对象的状态指标,⽐如Deployment、Node、Pod,需要注意的是kube-state-metrics只是简单提供⼀个metrics数据,并不会存储这些指标数据,所以我们可以使⽤Prometheus      来抓取这些数据然后存储。

      4)metrics-server:metrics-server也是⼀个集群范围内的资源数据聚合⼯具,是Heapster的替代品,同样metrics-server也只是显示数据,并不提供数据存储服务。

        在上述监控方案中,kube-state-metrics主要关注的是业务相关的⼀些元数据,⽐如Deployment、Pod、副本状态等,而metrics-server主要关注的是资源度量API的实现,⽐如CPU、⽂件描述符、内存、请求延时等指标

(3)使用Prometheus监控集群节点

       使用Prometheus监控node节点,可以通过node_exporter服务来获取监控数据, node_exporter就是抓取⽤于采集服务器节点的各种运⾏指标,⽬前       node_exporter⽀持⼏乎所有常⻅的监控点。

       node_exporter服务监控各节点可通过DaemonSet 控制器来部署,这样可以保证每个节点都可以运行一个该服务,即使节点扩容,也可保证在新节点上运行该服务。

# node_exporter服务的DaemonSet控制器资源清单
]# cat prome-node-exporter.yaml 
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: prometheus
  labels:
    name: node-exporter
spec:
  selector:
    matchLabels:
      name: node-exporter
  template:
    metadata:
      labels:
        name: node-exporter
    spec:
      # 使用宿主机pid、ipc、network命名空间
      hostPID: true
      hostIPC: true
      hostNetwork: true
      containers:
      - name: node-exporter
        image: prom/node-exporter:v1.0.1
        ports:
        - containerPort: 9100
        resources:
          requests:
            cpu: 0.15
        securityContext:
          privileged: true
        args:
        - --path.procfs
        - /host/proc
        - --path.sysfs
        - /host/sys
        - --collector.filesystem.ignored-mount-points
        - '"^/(sys|proc|dev|host|etc)($|/)"'
        volumeMounts:
        - name: dev
          mountPath: /host/dev
        - name: proc
          mountPath: /host/proc
        - name: sys
          mountPath: /host/sys
        - name: rootfs
          mountPath: /rootfs
      tolerations:
      - key: "node-role.kubernetes.io/master"
        operator: "Exists"
        effect: "NoSchedule"
      volumes:
        - name: proc
          hostPath:
            path: /proc
        - name: dev
          hostPath:
            path: /dev
        - name: sys
          hostPath:
            path: /sys
        - name: rootfs
          hostPath:
            path: /
# 创建并查看资源你运行情况
]# kubectl apply -f prome-node-exporter.yaml
]# kubectl get pods -n prometheus
NAME                         READY   STATUS    RESTARTS   AGE
node-exporter-dxbfn          1/1     Running   0          4m54s
node-exporter-fncvm          1/1     Running   0          4m54s
node-exporter-s6jbf          1/1     Running   0          4m51s

        通过DaemonSet控制器管理的node-exporter服务是共享了宿主机的网络名称空间,所以该pod运行起来后,各node节点会监听9100端口,所以我们可通过9100端口去获取监控数据。

# 查看各节点node-export监听端口
]# netstat -lntp | grep node_exporter
tcp6       0      0 :::9100                 :::*                    LISTEN      41458/node_exporter 
# 查看监控数据
]# curl localhost:9100/metrics | more
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 6

(4)配置服务发现

       各节点的node-exporter服务运行起来后,我们需要配置prometheus去发现这些服务,并获取数据;配置prometheus发现服务是通过修改ConfigMap配置实现的,我们需要将监控的服务加入配置,并重新创建该配置文件使之生效。

# node服务发现配置如下
]# cat prometheus-cm.yaml 
……
    - job_name: 'kubernetes-nodes'
      kubernetes_sd_configs:
      - role: node
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config configured
# 使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

        上面的操作完成后,登录prometheus发现prometheus已经发现了三个节点,但是获取不到数据,这是因为prometheus去发现Node服务的时候,访问的端⼝默认是10250,但是此处我们指定了hostNetwork=true,所以在每个节点上就会绑定⼀个端⼝9100获取数据,我们需要将10250替换成9100。

        此处可使用Prometheus的relabel_configs中的replace进行替换。relabel可以在Prometheus采集数据之前,通过Target实例的   Metadata信息,动态重新写⼊Label的值。

# 匹配__address__Label标签,替换端⼝
]# cat prometheus-cm.yaml 
……
    - job_name: 'kubernetes-nodes'
      kubernetes_sd_configs:
      - role: node
      relabel_configs:
      - source_labels: [__address__]
        regex: '(.*):10250'
        replacement: '${1}:9100'
        target_label: __address__
        action: replace
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config configured
# 重新加载使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

        上面操作完成之后,再去查看prometheus就可以正常获取数据。

- job_name: 'kubernetes-nodes'
      kubernetes_sd_configs:
      - role: node
      relabel_configs:
      - source_labels: [__address__]
        regex: '(.*):10250'
        replacement: '${1}:9100'
        target_label: __address__
        action: replace
      # 将	Kubernetes的Label标签添加为Prometheus的指标标签:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+*)
# 使配置生效并重新加载
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config configured
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

         我们监控的node的节点在prometheus中只显示一个标签,这对于后续的查询等操作不提便利,如果需要显示个node节点的所有标签,可通过labelmap    这个属性将Kubernetes节点的Label标签添加为    Prometheus的指标标签:

- job_name: 'kubernetes-nodes'
      kubernetes_sd_configs:
      - role: node
      relabel_configs:
      - source_labels: [__address__]
        regex: '(.*):10250'
        replacement: '${1}:9100'
        target_label: __address__
        action: replace
      # 将	Kubernetes的Label标签添加为Prometheus的指标标签:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+*)
# 使配置生效并重新加载
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config configured
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

        __meta_kubernetes_node_label 只是 kubernetes_sd_configs其中一个标签,更多的标签可参考官方文档(https://prometheus.io/docs/prometheus/latest/configuration/configuration/#%3Ckubernetes_sd_config%3E

(5)常用服务的监控

        很多服务内置了⼀个/metrics接⼝,针对这类服务的监控我们可以通过接口获取相关的监控指标数据。有些服务没有该接口,我们需要利⽤exporter服务来为Prometheus提供指标数据。Prometheus官⽅为许多应⽤就提供了exporter应⽤,也有许多第三⽅的实现具体可参考prometheus官方文档(https://prometheus.io/docs/instrumenting/exporters/)。

# nginx的基于exporter监控的deployment的资源配置文件
]# cat redis-exporter.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis-exporter
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9121"
      labels:
        app: redis-exporter
    spec:
      containers:
      - name: redis
        image: redis:4
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379
      - name: redis-exporter
        image: oliver006/redis_exporter:latest
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 9121
---
kind: Service
apiVersion: v1
metadata:
  name: redis
spec:
  selector:
    app: redis-exporter
  ports:
  - name: redis
    port: 6379
    targetPort: 6379
  - name: prom
    port: 9121
    targetPort: 9121

        上面的资源创建完成后就可以通过9121端口去采集/metric数据。然后在prometheus配置文件中追加redis的配置并重新加载下配置就可在prometheus中获取redis的监控指标。

# Prometheus的configmap中追加redis配置
]# cat prometheus-cm.yaml
. . . . . .
    - job_name: "redis"
      static_configs:
      - targets: ['redis.default.svc:9121']
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config unchanged
# 使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

2、监控kubernetes常用资源对象

(1)容器的监控

       对于容器的监控,则使用cAdvisor,而cAdvisor则已经内置在了 kubelet 组件之

中,所以不需要单独去安装, cAdvisor 的数据路径为 /api/v1/nodes/<node>/proxy/metrics。

       对于容器的监控我们同样使用node 的服务发现模式,因为每⼀个节点下⾯都有 kubelet,⾃然都有cAdvisor采集到的数据指标。而使用cAdvisor监控kubernetes集群资源时需要使用https 的协议,https协议需要用到ca.cart 和 token 这两个⽂件,这两个文件在所有的pod启动时,kubernetes已经注入到了该pod中。

       监控容器的configmap配置文件如下:

]# cat prometheus-cm.yaml
. . . . . . 
    - job_name: 'kubernetes-cadvisor'
      kubernetes_sd_configs:
      - role: node
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - target_label: __address__
        replacement: kubernetes.default.svc:443
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config unchanged
# 使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

(2)监控kubelet

       由于cAdvisor集成在了kubelet组件内,所以kubelet的监控也可通过cAdvisor来实现,kubelet的数据路径为:/api/v1/nodes/[节点名称]/proxy/metrics。监控configmapconfigmap配置文件通监控容器的配置基本是一致的。

# 监控kubelet的configmap配置文件
]# cat prometheus-cm.yaml
. . . . . . 
    - job_name: 'kubernetes-cadvisor'
      kubernetes_sd_configs:
      - role: node
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - target_label: __address__
        replacement: kubernetes.default.svc:443
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config unchanged
# 使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

(3)监控apiserver

        apiserver作为Kubernetes最核⼼的组件,是非常有必要对其进行监控的,对于apiserver的监控可以直接通过kubernetes    的Service来获取

# 查看默认的svc
]# kubectl get svc
NAME           TYPE      CLUSTER-IP   EXTERNAL-IP   PORT(S)      AGE
kubernetes     ClusterIP   10.96.0.1      <none>  443/TCP       132d
mysqlendpoints ClusterIP   10.102.60.55   <none>  3306/TCP      124d

        要⾃动发现Service类型的服务,我们就需要⽤到role为Endpoints的kubernetes_sd_configs,我们可以在       ConfigMap对象中添加上⼀个Endpoints  类型的服务的监控任务。然后将我们自己需要的服务过滤出来。

        Apiserver的svc默认为namespace为default的,服务名为 kubernetes的元数据。所以可以通过可以根据对应的__meta_kubernetes_namespace和__meta_kubernetes_service_name这两个元数据来过滤保留相关的svc。而此处则通过keep而非replace这个动作把符合我们要求的给保留下。

# 监控apiservice的configmap配置
]# cat prometheus-cm.yaml
    - job_name: 'apiservers'
      kubernetes_sd_configs:
      - role: endpoints
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: default;kubernetes;https
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config unchanged
# 使配置生效
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

(4)service的监控

        K8s中的apiserver是⼀种特殊的svc,如果需要监控其他的svc,需要在role为Endpoints的kubernetes_sd_configs中根据需求帅选出符合条件的svc进行监控。

# 监控符合条件的svc
- job_name: kubernetes-service-endpoints
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - action: keep
        regex: true
        source_labels:
        - __meta_kubernetes_service_annotation_prometheus_io_scrape
      - action: replace
        regex: (https?)
        source_labels:
        - __meta_kubernetes_service_annotation_prometheus_io_scheme
        target_label: __scheme__
      - action: replace
        regex: (.+)
        source_labels:
        - __meta_kubernetes_service_annotation_prometheus_io_path
        target_label: __metrics_path__
      - action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        source_labels:
        - __address__
        - __meta_kubernetes_service_annotation_prometheus_io_port
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - action: replace
        source_labels:
        - __meta_kubernetes_namespace
        target_label: kubernetes_namespace
      - action: replace
        source_labels:
        - __meta_kubernetes_service_name
        target_label: kubernetes_name

        在上面的配置中第一项“__meta_kubernetes_service_annotation_prometheus_io_scrap”的帅选条件为Service的annotation区域需要有prometheus.io/scrape=true 的声明。

(5)kube-state-metrics

       kube-state-metrics主要是用来监控Kubernetes 集群上的Pod、DaemonSet、Deployment、Job、CronJob 等各种资源对象的状态。kube-state-metrics 的gitlab地址为:https://github.com/kubernetes/kube-state-metrics

       对于kube-state-metrics的安装我们只需将gitlab上该项目拉取下来,再通过kubec aply创建即可。

git clone https://github.com/kubernetes/kube-state-metrics.git
]# cd kube-state-metrics-master/examples/standard/
# 在server的metadata下添加annotations
annotations:
  prometheus.io/scraped: "true"
# 创建kube-state-metrics
]# kubectl apply -f ./service.yaml

     kube-state-metrics创建完成后需要在prometheus的配置文件中追加配置,抓取带有prometheus.io/scraped: "true"注解的endpoint

]# cat prometheus-cm.yaml
. . . . . . 
    - job_name: "kube-state-metrics"
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scraped]
        action: keep
        regex: true
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        action: replace
        target_label: service_name
# 重新加载配置
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config unchanged
# 使配置生效
]# curl -XPOST http://192.168.16.132:31736/-/reload

       上面操作完成后就可以在promeheus的”targets”中看到kube-state-metrics相关数据呢,kube-state-metrics对应的svc有两个端口,在prometheus中显示了两个target。

三、grafana的使用

        grafana 是⼀个可视化⾯板,有着⾮常漂亮的图表和布局展示,功能⻬全的度量仪表盘和图形编辑器,⽀持 Graphite、zabbix、InfluxDB、Prometheus、OpenTSDB、Elasticsearch 等作为数据源,⽐Prometheus⾃带的图表展示功能更强大更炫;并且有丰富的插件。

1、grafana的安装

        Grafana的各种安装方法见官方文档(https://grafana.com/docs/grafana/latest/)。grafana在docker中运行直接执行命令” docker run -d --name=grafana -p 3000:3000 grafana/grafana”即可。此处的安装我们同prometheus一样,将grafana通过deployment控制器运行k8s中,再通过svc访问。需要注意的是>=5.1的版本运行的userID是472。

# 创建一个基于nfs storage class的pvc
]# cat grafana-pvc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: grafana
  namespace: prometheus
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi
]# kubectl apply -f grafana-pvc.yaml
# 创建基于deployment控制器的pod
]# cat grafana-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: prometheus
  labels:
    app: grafana
spec:
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - name: grafana
        image: grafana/grafana:7.3.2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
          name: Grafana
        # 通过环境变量的方式传递用户名密码
        env:
        - name: GF_SECURITY_ADMIN_USER
          value: admin
        - name: GF_SECURITY_ADMIN_PASSWORD
          value: dayi123
        readinessProbe:
          failureThreshold: 10
          httpGet: 
            path: /api/health
            port: 3000
            scheme: HTTP
          initialDelaySeconds: 60
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 30
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /api/health
            port: 3000
            scheme: HTTP
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            cpu: 200m
            memory: 256Mi
          requests:
            cpu: 200m
            memory: 256Mi
        volumeMounts:
        - mountPath: /var/lib/grafana
          subPath: grafana
          name: storage
      # 定义grafana的用户
      securityContext:
        fsGroup: 472
        runAsUser: 472
      volumes:
      - name: storage
        persistentVolumeClaim:
          claimName: grafana
# 创建
]# kubectl apply -f grafana-deployment.yaml
# 创建NodePort类型的svc将grafana暴露出去便于访问
]# cat grafana-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: prometheus
  labels:
    app: grafana
spec:
  type: NodePort
  ports:
    - port: 3000
  selector:
    app: Grafana
# 查看创建的svc资源
]# kubectl get svc -n prometheus
NAME       TYPE     CLUSTER-IP   EXTERNAL-IP   PORT(S)            AGE
grafana   NodePort 10.108.43.11   <none>     3000:30380/TCP      5m6s
prometheus NodePort  10.111.61.27  <none>   9090:31736/TCP       55d

        上面所有的资源创建完成后我们就可以通过网页去访问grafana。用户名密码为在grafana的deployment中定义用户名密码。

2、使用grafana

        Grafana安装完成后就可以使用grafana,首先我们需要配置数据源,登录grafana后,点击“DATA SOURCE”进行数据源的设置。进入后选择“Prometheus”根据自己实际情况进行prometheus的一些相关设置。设置完成后保存即可。数据源设置如下:

        数据源设置完成后就可以添加dashboard,dashboard也可以导入通过导入的方式增加,操作如下:

        导入以id号为162的dashboard为例,可以将编号ID为162的dashboard下载到本地,然后这⾥重新上传即可,也可以在⽂本框中直接输⼊162编号回⻋导⼊这个 dashboard。

        在导入时一定要选择数据源。

        Dashboard导入后,dashboard中可能会没有数据,一方面可能是由于prometheus和grafana时间不一致导致的,需要修改时间,另一方面是由于该图表的查询语句无法查询到数据,需要修改查询语句。修改方法为:点击该图像标题,点击下拉框中的“Edit”进行编辑,对查询语句根据实际情况进行调整。

        Dashboard id号为162的第一个图像的原查询语法为:

(sum(node_memory_MemTotal) - sum(node_memory_MemFree +node_memory_Buffers +node_memory_Cached) ) / sum(node_memory_MemTotal) * 100

        由于prometheus中没有“node_memory_MemTotal”等相关的指标数据,所以根据自己的prometheus中指标将“node_memory_MemTotal”等修改为““node_memory_MemTotal”_bytes”即可查询到数据。

(sum(node_memory_MemTotal_bytes) - sum(node_memory_MemFree_bytes+node_memory_Buffers_bytes+node_memory_Cached_bytes) ) / sum(node_memory_MemTotal_bytes) * 100

       第二个图标中的原查询语句为:

sum(sum by (io_kubernetes_container_name)( rate(container_cpu_usage_seconds_total{image!=""}[1m] ) )) / count(node_cpu{mode="system"}) * 100

        由于prometheus中存储出的数据中实际标签为“container”,并不存在标签“io_kubernetes_container_name”,所以需要修改为“container”,另一方面node_cpu这样的指标,实际为“node_cpu_seconds_total”,所以修改后的查询语法为:

sum(sum by (container)( rate(container_cpu_usage_seconds_total{image!=""}[1m] ) )) / count(node_cpu_seconds_total{mode="system"}) * 100

        第三个图标和第一个图标差不多一样,也是不存在“node_filesystem_size”等这样的数据指标,需要进行修改。

# 原语句为
(sum(node_filesystem_size{device="rootfs"}) - sum(node_filesystem_free{device="rootfs"}) ) / sum(node_filesystem_size{device="rootfs"}) * 100
# 修改后语句为
(sum(node_filesystem_size_bytes{device="rootfs"}) - sum(node_filesystem_free_bytes{device="rootfs"}) ) / sum(node_filesystem_size_bytes{device="rootfs"}) * 100

        第四个图表为pod的cpu使用率的图表,然而在prometheus中不存在名称为”io_kubernetes_container_name”该标签,需要将该标签替换为“pod”即可。其他的图表则依据prometheus中数据的实际情况进行调整。图表的查询语句修改完成后部分dashboard的如下:

       除了上面的id号为162的dashboard模板为,还有常用的模板还有741(Deployment metrics)、747(Kubernetes Pod Metric)。

3、grafana中安装k8s插件

       除了上面通过一些dashboard模板监控k8s集群为,prometheus还提供呢一个插件grafana-kubernetes-app对kubernetes集群进行监控,该插件的官方文档地址为:(https://grafana.com/grafana/plugins/grafana-kubernetes-app/installation)。

(1)安装插件

       该插件的安装需要进入到grafana对应的pod中安装,安装完成后需要重启grafana所对应的pod。

# 查看pod
]# kubectl get pods -n prometheus
NAME                         READY   STATUS    RESTARTS   AGE
grafana-5d6f5f45bc-wsps7     1/1     Running   1          7h47m
# 进入pod
]# kubectl exec -it grafana-5d6f5f45bc-wsps7 /bin/sh -n prometheus
# 安装插件
/usr/share/grafana $ grafana-cli plugins install grafana-kubernetes-app
installing grafana-kubernetes-app @ 1.0.1
from: https://grafana.com/api/plugins/grafana-kubernetes-app/versions/1.0.1/download
into: /var/lib/grafana/plugins

✔ Installed grafana-kubernetes-app successfully 

Restart grafana after installing plugins . <service grafana-server restart>
# 退出删除pod(删除后会重新创建,达到了重启的效果)
/usr/share/grafana $ exit
[root@master prometheus]# kubectl delete pods grafana-5d6f5f45bc-wsps7 -n prometheus
pod "grafana-5d6f5f45bc-wsps7" deleted
[root@master prometheus]# kubectl get pods -n prometheus
NAME                         READY   STATUS    RESTARTS   AGE
grafana-5d6f5f45bc-876jx     0/1     Running   0          66s

         重启完grafana后,进入到插件页面发现会多了一个kubernetes插件,如下图所示:

(2)配置插件

        安装完该插件,我们点击该插件进入插件,在“configuer”中点击“Connect to your Kubernetes Cluster and deploy metric exporters”进行该插件的配置。

        配置kubernetes集群需要填写集群的名称。Kubernetes集群的地址(即apiservice地址)及认证方式 ,认证方式可选择tls证书认证(选择“TLS Client Auth”和“With CA Cert”)。证书文件可将” ~/.kube/config”文件中的内容通过base64解码后使用。

        相关的认证信息填写完成后,如果之前没有创建“Node Exporter”和“kube State Metrics”则点击“deploy”进行创建,如果已经创建则点击“save”即可。点击“save”后会在左边的菜单栏出现“kubernetes”的图表。在dashboard中就可以看到相关的dashboard,在新版本的grafana中需要根据prometheus的实际数据对dashboard图标查询语句进行一些调整。

4、grafana监控告警

(1)、配置告警方式

        设置grafana的邮件告警,需要在grafana的配置文件“/etc/grafana/grafan.ini”中设置smtp邮件服务器的地址。此处我们将grafana的配置文件通过configmap资源对象挂载到grafana的pod中。

# 创建grafana邮箱告警的configmap
]# cat grafana-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-config
  namespace: prometheus
data:
  grafana.ini: |
    [server]
    root_url = http://192.168.16.132:30380/
    [smtp]
    enable = true
    host = smtp.163.com:25
    user = dayi_123@163.com
    password = dayi123
    skip_verify = true
    from_address = dayi_123@163.com
    [alerting]
    enabled = true
execute_alerts = true
# 创建
]# kubectl apply -f grafana-cm.yaml
# 将configmap挂载到grafana的pod中
# 修改grafana-deployment.yaml的配置文件,将configmap挂载到pod中
]# cat grafana-deployment.yaml
. . . . . . 
        volumeMounts:
        - mountPath: /var/lib/grafana
          subPath: grafana
          name: storage
        - mountPath: "/etc/grafana"
          name: config
      volumes:
      - name: storage
        persistentVolumeClaim:
          claimName: grafana
      - name: config
        configMap:
          name: grafana-config
# 更新pod
]# kubectl apply -f grafana-deployment.yaml

         邮箱smtp设置后就可以设置告警发送到的邮箱等相关的信息。除了可以设置以邮件的方式告警外,还可以设置、钉钉、slack、 webhook等方式告警。设置钉钉告警需要在钉钉群里面添加机器人,类型为自定义机器人,添加完后将webhook 地址添设置钉钉告警的“Webhook URL”下即可。

(2)、设置告警

       告警方式设置完成后,需要进行告警相关的设置,告警的设置我们需要先选择Graph相关图表,点击编辑,进⼊Graph编辑⻚⾯可以看到有⼀个Alert模块,点击该模块后点击“create Alert”即可进行告警的相关设置,具体设置根据自己的实际情况进行设置。

四、prometheus的告警功能

       由于Grafana只⽀持Graph的图表的报警的报警功能,Grafana的报警功能⽐较弱,所以一般都是用prometheus的报警模块AlertManager进行报警。Alertmanager主要⽤于接收Prometheus发送的告警信息,它⽀持丰富的告警通知渠道,⽽且很容易做到告警信息进⾏去重,降噪,分组等。

1、AlertManager的安装

       AlertManager的官⽅⽂档地址为https://prometheus.io/docs/alerting/configuration/;默认的安装方式为下载二进制文件,通过命令“./alertmanager --config.file=simple.yml”即可运行AlertManager。

       由于prometheus运行在deployment控制器的pod中,所以将AlertManager的镜像也添加到prometheus所在的pod中。同时将AlerManager的配置文件以configmap的方式挂载到pod中。

# AlertManager的configmap文件
]# cat alertamager-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: alertmanager-cm
  namespace: prometheus
data:
  config.yml: |
global:
  # 在没有报警的情况下声明为已解决的时间
      resolve_timeout: 5m
      # 报警发送的邮箱地址
      smtp_smarthost: 'smtp.126.com'
      smtp_from: 'dayi_123@126.com'
      smtp_auth_username: 'dayi_123@126.com'
      smtp_auth_password: 'xxxxxx'
      smtp_hello: '126.com'
      smtp_require_tls: false
    # 所有报警信息进⼊后的根路由,⽤来设置报警的分发策略
route: 
# 是接收到报警信息后的重新分组标签,
  group_by: ['alertname', 'cluster']
  # 报警分组被创建后,初始化通知时间
      group_wait: 30s
      # 当第⼀个报警发送后,发送新的报警信息的间隔时间。
      group_interval: 5s
      # 如果⼀个报警信息已经发送成功了,重新发送时间
      repeat_interval: 5m
      # 默认的receiver:如果⼀个报警没有被⼀个route匹配,则发送给默认的接收器
      receiver: default
      - receiver: emil
        group_wait: 10s
        match_re:
          team: node
    # 接收邮件的邮箱,可以设置多个
    receivers:
    - name: 'default'
      email_configs:
      - to: 'liuyi@ecmoho.com'
        send_resolved: 'true'
    - name: email
      email_configs:
      - to: 'liuyi@ecmoho.com'
        send_resolved: 'true'
# 创建
]# kubectl apply -f alertamager-cm.yaml 
configmap/alertmanager-cm created

         AlertManager的configmap文件创建后,需要修改之前创建的prometheus的deployment的资源配置文件,在pod中新增AlertManager的镜像。即在prometheus的deployment中增加以下配置文件:

#在prometheus-deployment资源清单中配置文件中增加alertmanager镜像
]# cat prometheus-deployment.yaml
. . . . . . 
      - name: alertmanager
        image: prom/alertmanager:v0.21.0
        imagePullPolicy: IfNotPresent
        args:
        - "--config.file=/etc/alertmanager/config.yml"
        ports:
        - containerPort: 9093
          name: http
        volumeMounts:
        - mountPath: "/etc/alertmanager"
          name: alertcfg
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
          limits:
            cpu: 100m
            memory: 256Mi
      - name: alertcfg
        configMap:
          name: alertmanager-cm
# 删除重新创建
]# kubectl delete -f prometheus-deployment.yaml
]# kubectl apply-f prometheus-deployment.yaml
# 同时也可在prometheus的svc中添加alertmanager配置
]# cat prometheus-svc.yaml
. . . . .
  - name: alert 
    port: 9093
    targetPort: 9093
# 重新加载
]# kubectl apply -f prometheus-svc.yaml

2、配置告警

        AlertManager的容器启动起来后,我们还需要在Prometheus中配置AlertManager的地址,让Prometheus 能够访问到AlertManager。同时还需通过prometheus配置文件添加告警规则配置。

# 在prometheus中配置文件中配置alertmanager地址
]# cat prometheus-cm.yaml 
. . . . . .
    alerting:
      alertmanagers:
      - static_configs:
        - targets: ["localhost:9093"]
    rule_files:
      - /etc/prometheus/rules.yml
# 配置完成后重新创建并加载
]# kubectl delete -f prometheus-cm.yaml 
configmap "prometheus-config" deleted
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config created
]# curl -XPOST "http://192.168.16.132:3173

        Prometheus配置中告警规则是通过引入rule_files实现的,这⾥我们同样将rules.yml ⽂件⽤ConfigMap的形式挂载到/etc/prometheus⽬录下⾯即可。

# 配置告警规则
]# cat prometheus-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: prometheus
data:
  prometheus.yml: |
. . . . . . 
  rules.yml: |
    groups:
    - name: test-rule
      rules:
      - alert: NodeMemoryUsage
        expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) / node_memory_MemTotal_bytes * 100 > 80
        for: 2m
        labels: 
          team: node
        annotations:
          summary: "{{$labels.instance}}: High Memory usage detected"
          description: "{{$labels.instance}}: Memory usage is above 20% (current value is:{{ $value }}"
# 重新创建配置并加载
]# kubectl delete -f prometheus-cm.yaml 
configmap "prometheus-config" deleted
]# kubectl apply -f prometheus-cm.yaml 
configmap/prometheus-config created
]# curl -XPOST "http://192.168.16.132:31736/-/reload"

告警规则中各参数作用如下:

      for:使 Prometheus 服务等待指定的时间, 然后执⾏查询表达式。

      labels:允许指定额外的标签列表,把它们附加在告警上。

      Annotations:指定了另⼀组标签,它们不被当做告警实例的身份标识,它们经常⽤于存储些额外的信息,⽤于报警信息的展示之类的。

        除了上面的告警规则外,其余告警规则我们可根据自己需求自定义。如果相关的告警规则被触发我们可以在prometheus的alerts模块中(安装alertmanager后会出现)或alertmanager页面中查看。

3、配置钉钉告警

       要使用钉钉告警,首先需要我们定义webhook来接收报警信息,然后在webhook⾥⾯去进⾏告警信息的处理。在github上有人已经做了该项目(https://github.com/timonwong/prometheus-webhook-dingtalk),同时该项目也被人做成docker镜像(https://hub.docker.com/r/timonwong/prometheus-webhook-dingtalk);我们只需根据自己需求配置使用即可。

       在k8s集群中我们也将该webhook运行在deployment控制的pod中。资源清单定义如下:

]# cat ddtalk-hook.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ddtalk-hook
  namespace: prometheus
spec:
  selector:
    matchLabels:
      app: ddtalk-hook
  template:
    metadata: 
      labels:
        app: ddtalk-hook
    spec:
      containers:
      - name: ddtalk-hook
        image: timonwong/prometheus-webhook-dingtalk:v1.4.0
        args:
        - --ding.profile=webhook1=https://oapi.dingtalk.com/robot/send?access_token=53630694d60843f17b99e40949afba58fb247995554120bf054037f6111ea59f
        ports:
        - containerPort: 8060
          name: http
        resources:
          requests: 
            cpu: 50m
            memory: 100Mi
          limits:
            cpu: 50m
            memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
  name: ddtalk-hook
  namespace: prometheus
spec:
  selector:
    app: ddtalk-hook
  ports:
  - name: hook
    port: 8060
    targetPort: http
]# kubectl apply -f ddtalk-hook.yaml

        上面资源定义完成后我们需要在alermanager的配置文件中添加一个routes,用于将告警信息发送到接收钉钉告警的服务中。

]# cat alertamager-cm.yaml 
. . . . . .
      routes:
      . . . . . . 
      - receiver: webhook
        group_wait: 10s    
    receivers:
    - name: 'email'
      email_configs:
      - to: 'liuyi@ecmoho.com'
        send_resolved: true
. . . . . . 

五 、Prometheus Operator 的安装与使用

        Operator是由CoreOS公司开发的,⽤来扩展 Kubernetes API,是特定的应⽤程序控制器,它⽤来创建、配置和管理复杂的有状态应⽤,如数据库、缓存和监控系统。Operator基于Kubernetes的资源和控制器概念之上构建,但同时⼜包含了应⽤程序特定的⼀些专业知识,⽐如创建⼀个数据库的Operator,则必须对创建的数据库的各种运维⽅式⾮常了解,创建Operator 的关键是CRD(⾃定义资源)的设计。CRD 是对 Kubernetes API 的扩展,Kubernetes中的每个资源都是⼀个API对象的集合。

       Operator 是将运维⼈员对软件操作的知识给代码化,同时利⽤ Kubernetes 强⼤的抽象来管理⼤规模的软件应⽤。

1、Prometheus-Operator

官方文档地址:https://coreos.com/operators/prometheus/docs/latest/user-guides/getting-started.html

Github地址:https://github.com/prometheus-operator/prometheus-operator

Prometheus-operator程序地址:https://github.com/prometheus-operator/kube-prometheus

        Prometheus-Operator中Operator是最核⼼的部分,作为⼀个控制器,他会去创建Prometheus、ServiceMonitor、AlertManager以及PrometheusRule 4个 CRD 资源对象,然后会⼀直监控并维持这4个资源对象的状态。prometheus这种资源对象就是作为 Prometheus Server存在,⽽ServiceMonitor就是exporter的各种抽象;exporter是⽤来专⻔提供metrics数据接⼝的⼯具,Prometheus就是通过ServiceMonitor提供的metrics数据接⼝去pull数据的,alertmanager这种资源对象就是对应的AlertManager的抽象,⽽ PrometheusRule是⽤来被Prometheus实例使⽤的报警规则⽂件。这样我们要在集群中监控什么数据,就变成了直接去操作Kubernetes集群的资源对象了。

2、Prometheus-Operator的安装

        Prometheus-Operator的安装可以使用源码进⾏安装,也可以⽤Helm来进⾏⼀键安装。使用helm安装只需通过“helm install --name my-release stable/prometheus-operator”命令即可完成安装。使用源码安装的方法如下:

# 下载源码
]# git clone https://github.com/prometheus-operator/kube-prometheus
# 创建相关的名称空间及operator等相关资源
]# cd kube-prometheus/manifests/
]# kubectl apply -f setup/
# 创建prometheus等相关资源
]# kubectl apply -f ./
alertmanager.monitoring.coreos.com/main created
secret/alertmanager-main created
service/alertmanager-main created
serviceaccount/alertmanager-main created
. . . . . .

        由于使用prometheus-operator定义的资源数据都是存储在临时挂载目录中,服务重启后数据会丢失,为了保持数据持久化,我们需要创建一个StorageClass (使用之前创建的基于nfs的storageclass)。然后在prometheus的CRD资源对象中添加如下配置:

  storage:
    volumeClaimTemplate:
      spec:
        storageClassName: managed-nfs-storage
        resources:
          requests:
            storage: 5Gi	

        修改后的promehteus的crd资源定义如下:

# 查看之前创建的storageclass
]# kubectl get storageclass
NAME                  PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  10
# 修改后的promehteus crd资源
]# cat prometheus-prometheus.yaml 
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  labels:
    prometheus: k8s
  name: k8s
  namespace: monitoring
spec:
  alerting:
    alertmanagers:
    - name: alertmanager-main
      namespace: monitoring
      port: web
  storage:
    volumeClaimTemplate:
      spec:
        storageClassName: managed-nfs-storage
        resources:
          requests:
            storage: 5Gi
  image: quay.io/prometheus/prometheus:v2.22.1
  nodeSelector:
    kubernetes.io/os: linux
  podMonitorNamespaceSelector: {}
  podMonitorSelector: {}
  probeNamespaceSelector: {}
  probeSelector: {}
  replicas: 1
  resources:
    requests:
      memory: 400Mi
  ruleSelector:
    matchLabels:
      prometheus: k8s
      role: alert-rules
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
    runAsUser: 1000
  serviceAccountName: prometheus-k8s
  serviceMonitorNamespaceSelector: {}
  serviceMonitorSelector: {}
  version: v2.22.1
# 更新配置
]# kubectl apply -f  prometheus-prometheus.yaml

         上面的资源创建完成后,会生产相关的svc资源,为了能够正常访问promehteus及grafana我们需要将promehteus及grafana(新版默认为NodePort)的svc修改为NodePort类型。

# 生成的svc
]# kubectl get svc -n monitoring
NAME                 TYPE     CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
alertmanager-main  ClusterIP   10.97.233.207    <none>     9093/TCP                     39m
alertmanager-operated   ClusterIP   None      <none>        9093/TCP,9094/TCP,9094/UDP   30m
grafana                 NodePort    10.100.21.231    <none>        3000:30611/TCP               39m
kube-state-metrics      ClusterIP   None             <none>        8443/TCP,9443/TCP            39m
node-exporter           ClusterIP   None             <none>        9100/TCP                     39m
prometheus-adapter      ClusterIP   10.103.4.15      <none>        443/TCP                      39m
prometheus-k8s          ClusterIP   10.105.172.229   <none>        9090/TCP                     39m
prometheus-operated     ClusterIP   None             <none>        9090/TCP                     30m
prometheus-operator     ClusterIP   None             <none>        8443/TCP                     93m
# 修改prometheus的端口类型为NodePort
]# kubectl edit svc prometheus-k8s -n monitoring

       上面操作完成后,可登录prometheus查看,k8s集群中大部分资源都已经被监控,而grafana中也已经生成了相关的dashboard。

3、Prometheus-Operator的配置

        上面的资源创建后,prometheus已经将k8s集群的大部分资源监控。没有被监控到的资源包括kube-controller-manager和kube-scheduler这两个系统组件。kube-scheduler 组件对应的 ServiceMonitor 资源的定义如下:

]# cat prometheus-serviceMonitorKubeScheduler.yaml 
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: kube-scheduler
  name: kube-scheduler
  namespace: monitoring
spec:
  endpoints:
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
    interval: 30s
    port: https-metrics
    scheme: https
    tlsConfig:
      insecureSkipVerify: true
  jobLabel: k8s-app
  # 匹配某⼀命名空间中的service,如果想从所有的namespace中匹配⽤any: true
  namespaceSelector:
    matchNames:
    - kube-system
  # 匹配的Service的labels, 如果使⽤mathLabels,则下⾯的所有标签都匹配时才会匹配该service,如果使⽤matchExpressions,则⾄少匹配⼀个标签的service 
  selector:
    matchLabels:
      k8s-app: kube-scheduler

        通过监控kube-scheduler的ServiceMonitor资源发现,监控kube-scheduler是通过kube-system名称空间下的标签为k8s-app=kube-scheduler的svc采集监控数据的。而系统中没有该svc,所以监控不到kube-scheduler。需要我们去手动创建一个svc。

]# cat kube-schedule-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-scheduler
  labels:
    k8s-app: kube-scheduler
  annotations:
    prometheus.io/scrape: 'true'
spec:
  selector:
    component: kube-scheduler
  ports:
  - name: http-metrics
    port: 10251
    targetPort: 10251
    protocol: TCP
# 创建
]# kubectl apply -f kube-schedule-svc.yaml

        当kube-scheduler的svc创建后,在k8s的监控中已经发现了kube-scheduler的target,但是抓取数据时出错了,这是因为kubeadm搭建的集群中kube-scheduler 默认是绑定在127.0.0.1上⾯的。kube-scheduler绑定的地址更改成 0.0.0.0即可满⾜要求。

# 修改监听地址
]# sed -i "s@host: 127.0.0.1@host: 0.0.0.0@g" /etc/kubernetes/manifests/kube-scheduler.yaml

       修改完成后我们将该⽂件从当前⽂件夹中移除,隔⼀会⼉再移回该⽬录,就可以⾃动更新,然后再去看prometheus中kube-scheduler这个targe已经正常。

       kube-controller-manager的监控也可按照此方法配置,kube-controller-manager监听的地址是10252,晒选该资源的label是”k8s-app: kube-controller-manager”。

4、自定义Prometheus-Operator监控项

        在prometheus的集群中,处理监控集群的组件外,大多数时候我们需要根据业务需求自定义监控想,在promehteus-operator中自定义监控想需要通过以下步骤来完成:

(1)建立ServiceMonitor对象,用户Prometheus添加监控项

      (2)为ServiceMonitor对象关联metrics数据接口的Service对象

      (3)确保Service对象可以正确获取到metrics数据

       Prometheus-operator中并没有etcd的监控,为etcd自动以监控项的操作如下:

# 首先为用到的etcd证书创建一个secret资源
]# kubectl -n monitoring create secret generic etcd-certs --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.crt --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.key --from-file=/etc/kubernetes/pki/etcd/ca.crt 
secret/etcd-certs created
# 查看
]# kubectl get secret etcd-certs -n monitoring
NAME         TYPE     DATA   AGE
etcd-certs   Opaque   3      10m
# 然后将用到的证书配置到prometheus中
]# kubectl edit prometheus k8s -n monitoring
. . . . . .
  ruleSelector:
    matchLabels:
      prometheus: k8s
      role: alert-rules
  secrets:
  - etcd-certs
. . . . . .
# 查看prometheus中的证书
]# kubectl exec -it prometheus-k8s-0 ls /etc/prometheus/secrets/etcd-certs/ -n monitoring
ca.crt                  healthcheck-client.crt  healthcheck-client.key 

        因为很多时候etcd是独立于集群之外的,所以我们在创建svc的同时需要创建一个Endpoints将etcd代理到k8s集群,然后将svc绑定到Endpoints。需要注意的是svc和Endpoints的metadata区域内容要保持一致。

]# cat etcd-svcendpoints.yaml 
apiVersion: v1
kind: Service
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
spec:
  type: ClusterIP
  clusterIP: None     
  ports:
  - name: port
    port: 2379          
    protocol: TCP
---
apiVersion: v1
kind: Endpoints
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
subsets:
- addresses:
  - ip: 192.168.16.131
  ports:
  - port: 2379
# 创建
]# kubectl apply -f etcd-svcendpoints.yaml

        Svc资源创建完成后,就需要创建etcd的monitoring资源。由于证书中的serverName 和etcd中签发的可能不匹配,所以加上了在定义etcd的monitor资源时加上了insecureSkipVerify=true。

]# cat etcd-servicemonitor.yaml 
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: etcd-k8s
  namespace: monitoring
  labels:
    k8s-app: etcd-k8s
spec:
  jobLabel: k8s-app
  endpoints:
  - port: port
    interval: 30s
    scheme: https
    tlsConfig:
      caFile: /etc/prometheus/secrets/etcd-certs/ca.crt
      certFile: /etc/prometheus/secrets/etcd-certs/healthcheck-client.crt
      keyFile: /etc/prometheus/secrets/etcd-certs/healthcheck-client.key
      insecureSkipVerify: true
  selector:
    matchLabels:
      k8s-app: etcd
  namespaceSelector:
    matchNames:
    - kube-system
# 创建
]# kubectl apply -f etcd-servicemonitor.yaml

        Etcd的监控完成后可以在grafana中导入编号为3070的dashboard,便可获取etcd的监控图表。

5、配置 PrometheusRule

        安装完prometheus-operator后自带的监控项已经有了告警规则,我们自定义的监控项就需要我们自定义一些告警规则。手动搭建的prometheus中⾃定义告警需要在 Prometheus的配置⽂件中指定报警的rules⽂件或定义告警规则。Prometheus-operator中自定义告警规则需要创建⼀个具有prometheus=k8s和role=alert-rules标签的

        PrometheusRule对象即可。例如添加的etcd的监控项创建告警规则:

]# cat etcd-rules.yaml 
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  abels:
    prometheus: k8s
    role: alert-rules
  name: etcd-rules
  namespace: monitoring
spec:
  groups:
  - name: etcd
    rule:
    - alert: EtcdClusterUnavailable
      annotations:
        summary: etcd cluster small
        description: etcd cluster unavailable
      expr: |
        count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1)
      for: 3m
      labels:
        severity: critical
# 创建
]# kubectl apply -f etcd-rules.yaml 
prometheusrule.monitoring.coreos.com/etcd-rules created    

        pod中的promehteus的告警规则的位置为“/etc/prometheus/rules/prometheus-k8s-rulefiles-0/”。所以该资源创建后实际上会生成一个“<namespace>-<name>.yaml 的⽂件”。

]# kubectl exec -it prometheus-k8s-0 -n monitoring ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/ 
monitoring-etcd-rules.yaml            monitoring-prometheus-k8s-rules.yaml

6、配置告警

        Prometheus-operator中alertmanager的告警配置是通过“kube-prometheus/manifests/alertmanager-secret.yaml”这个配置文件配置的,这个创建后主要配置信息如下:

]# kubectl get secret alertmanager-main -n monitoring -o yaml
apiVersion: v1
data:
  alertmanager.yaml: Imdsb2JhbCI6CiAgInJlc29sdmVfdGltZW91dCI6ICI1bSIKImluaGliaXRfcnVsZXMiOgotICJlcXVhbCI6CiAgLSAibmFtZXNwYWNlIgogIC0gImFsZXJ0bmFtZSIKICAic291cmNlX21hdGNoIjoKICAgICJzZXZlcml0eSI6ICJjcml0aWNhbCIKICAidGFyZ2V0X21hdGNoX3JlIjoKICAgICJzZXZlcml0eSI6ICJ3YXJuaW5nfGluZm8iCi0gImVxdWFsIjoKICAtICJuYW1lc3BhY2UiCiAgLSAiYWxlcnRuYW1lIgogICJzb3VyY2VfbWF0Y2giOgogICAgInNldmVyaXR5IjogIndhcm5pbmciCiAgInRhcmdldF9tYXRjaF9yZSI6CiAgICAic2V2ZXJpdHkiOiAiaW5mbyIKInJlY2VpdmVycyI6Ci0gIm5hbWUiOiAiRGVmYXVsdCIKLSAibmFtZSI6ICJXYXRjaGRvZyIKLSAibmFtZSI6ICJDcml0aWNhbCIKInJvdXRlIjoKICAiZ3JvdXBfYnkiOgogIC0gIm5hbWVzcGFjZSIKICAiZ3JvdXBfaW50ZXJ2YWwiOiAiNW0iCiAgImdyb3VwX3dhaXQiOiAiMzBzIgogICJyZWNlaXZlciI6ICJEZWZhdWx0IgogICJyZXBlYXRfaW50ZXJ2YWwiOiAiMTJoIgogICJyb3V0ZXMiOgogIC0gIm1hdGNoIjoKICAgICAgImFsZXJ0bmFtZSI6ICJXYXRjaGRvZyIKICAgICJyZWNlaXZlciI6ICJXYXRjaGRvZyIKICAtICJtYXRjaCI6CiAgICAgICJzZXZlcml0eSI6ICJjcml0aWNhbCIKICAgICJyZWNlaXZlciI6ICJDcml0aWNhbCI=
kind: Secret
metadata:
   name: alertmanager-main
   namespace: monitoring

        该配置文件中的告警信息都是通过base64加密的,解密后即是告警相关的一些配置信息

]# echo "Imdsb2JhbCI6CiAgInJlc29sdmVfdGltZW91dCI6ICI1bSIKImluaGliaXRfcnVsZXMiOgotICJlcXVhbCI6CiAgLSAibmFtZXNwYWNlIgogIC0gImFsZXJ0bmFtZSIKICAic291cmNlX21hdGNoIjoKICAgICJzZXZlcml0eSI6ICJjcml0aWNhbCIKICAidGFyZ2V0X21hdGNoX3JlIjoKICAgICJzZXZlcml0eSI6ICJ3YXJuaW5nfGluZm8iCi0gImVxdWFsIjoKICAtICJuYW1lc3BhY2UiCiAgLSAiYWxlcnRuYW1lIgogICJzb3VyY2VfbWF0Y2giOgogICAgInNldmVyaXR5IjogIndhcm5pbmciCiAgInRhcmdldF9tYXRjaF9yZSI6CiAgICAic2V2ZXJpdHkiOiAiaW5mbyIKInJlY2VpdmVycyI6Ci0gIm5hbWUiOiAiRGVmYXVsdCIKLSAibmFtZSI6ICJXYXRjaGRvZyIKLSAibmFtZSI6ICJDcml0aWNhbCIKInJvdXRlIjoKICAiZ3JvdXBfYnkiOgogIC0gIm5hbWVzcGFjZSIKICAiZ3JvdXBfaW50ZXJ2YWwiOiAiNW0iCiAgImdyb3VwX3dhaXQiOiAiMzBzIgogICJyZWNlaXZlciI6ICJEZWZhdWx0IgogICJyZXBlYXRfaW50ZXJ2YWwiOiAiMTJoIgogICJyb3V0ZXMiOgogIC0gIm1hdGNoIjoKICAgICAgImFsZXJ0bmFtZSI6ICJXYXRjaGRvZyIKICAgICJyZWNlaXZlciI6ICJXYXRjaGRvZyIKICAtICJtYXRjaCI6CiAgICAgICJzZXZlcml0eSI6ICJjcml0aWNhbCIKICAgICJyZWNlaXZlciI6ICJDcml0aWNhbCI=" | base64 -d
"global":
  "resolve_timeout": "5m"
"inhibit_rules":
- "equal":
  - "namespace"
  - "alertname"
  "source_match":
    "severity": "critical"
  "target_match_re":
    "severity": "warning|info"
- "equal":
  - "namespace"
  - "alertname"
  "source_match":
    "severity": "warning"
  "target_match_re":
    "severity": "info"
"receivers":
- "name": "Default"
- "name": "Watchdog"
- "name": "Critical"
"route":
  "group_by":
  - "namespace"
  "group_interval": "5m"
  "group_wait": "30s"
  "receiver": "Default"
  "repeat_interval": "12h"
  "routes":
  - "match":
      "alertname": "Watchdog"
    "receiver": "Watchdog"
  - "match":
      "severity": "critical"
    "receiver": "Critical"

        因此,我们需要配置告警地址等信息,只许将配置文件创建为secret对象即可。

# 邮件告警及钉钉告警配置信息如下
]# cat alert-conf/alertmanager.yaml 
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.126.com:25'
  smtp_from: 'dayi_123@126.com'
  smtp_auth_username: 'dayi_123@126.com'
  smtp_auth_password: 'xxxxxx'
  smtp_hello: '126.com'
  smtp_require_tls: false
route:
  group_by: ['alertname', 'cluster']
  group_wait: 30s
  group_interval: 5s
  repeat_interval: 5m
  receiver: default
  routes:
  - receiver: email
    group_wait: 10s
    match_re:
      team: node
  - receiver: webhook
    group_wait: 10s    
receivers:
- name:
  webhook: 'webhook'
  webhook_configs:
  - url: 'http://ddtalk-hook:8060'
    send_resolved: true
- name: 'default'
  email_configs:
  - to: 'liuyi@ecmoho.com'
    send_resolved: true
- name: 'email'
  email_configs:
  - to: 'liuyi@ecmoho.com'
    send_resolved: true
# 删除之前的secret,创建新的secret
]# kubectl delete secret alertmanager-main -n monitoring
secret "alertmanager-main" deleted
]# kubectl create secret generic alertmanager-main --from-file=alert-conf/alertmanager.yaml -n monitoring
secret/alertmanager-main created

        定义了钉钉告警后,自然要定义告警接收程序,将前面prometheus的钉钉告警接收程序修改下名称空间放在当前名称空间即可。

# 接收处理钉钉告警资源配置如下
]# cat ddtalk-hook.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ddtalk-hook
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: ddtalk-hook
  template:
    metadata: 
      labels:
        app: ddtalk-hook
    spec:
      containers:
      - name: ddtalk-hook
        image: timonwong/prometheus-webhook-dingtalk:v1.4.0
        args:
        - --ding.profile=webhook1=https://oapi.dingtalk.com/robot/send?access_token=53630694d60843f17b99e40949afba58fb247995554120bf054037f6111ea59f
        ports:
        - containerPort: 8060
          name: http
        resources:
          requests: 
            cpu: 50m
            memory: 100Mi
          limits:
            cpu: 50m
            memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
  name: ddtalk-hook
  namespace: prometheus
spec:
  selector:
    app: ddtalk-hook
  ports:
  - name: hook
    port: 8060
    targetPort: http
# 创建
]# kubectl apply -f ddtalk-hook.yaml

 

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值