Kube Prometheus 监控

2,620 阅读9分钟

介绍

Prometheus Operator 为 Kubernetes 提供了对 Prometheus 机器相关监控组件的本地部署和管理方案,该项目的目的是为了简化和自动化基于 Prometheus 的监控栈配置,主要包括以下几个功能:

Kubernetes 自定义资源:使用 Kubernetes CRD 来部署和管理 Prometheus、Alertmanager 和相关组件。 简化的部署配置:直接通过 Kubernetes 资源清单配置 Prometheus,比如版本、持久化、副本、保留策略等等配置。 Prometheus 监控目标配置:基于熟知的 Kubernetes 标签查询自动生成监控目标配置,无需学习 Prometheus 特地的配置。

Prometheus Operator 的架构图:

92965293-CF39-451B-A84A-B8FC5040AA8D.png

kube-prometheus是通过k8s operator的方式实现的监控方案,首先会在k8s集群内注册多个crd资源,其中最主要四种的crd资源,并利用 Operator 编写了一系列常用的监控资源清单。

Prometheus: 由 Operator 依据一个自定义资源kind: Prometheus类型中,所描述的内容而部署的 Prometheus Server 集群,可以将这个自定义资源看作是一种特别用来管理Prometheus Server的StatefulSets资源。

ServiceMonitor: 这个CRD定义了,我们需要监控的动态服务,通过获取到svc到label标签进行绑定到,指定的svc然后获取到对应的ep资源的metics路由(可以定义目标的metrics的url),得而可以提取了pod的监控数据。Operator也会实时的watch servicemonitor资源的变化,自动更新/etc/prometheus/config_out/prometheus.env.yaml配置文件,并对prometheus-server进行reload的操作。

Alertmanager:该 CRD 定义了在 Kubernetes 集群中运行的 Alertmanager 的配置,同样提供了多种配置,包括持久化存储。 对于每个 Alertmanager 资源,Operator 都会在相同的命名空间中部署一个对应配置的 StatefulSet,Alertmanager Pods 被配置为包含一个名为 的 Secret,该 Secret 以 alertmanager.yaml 为 key 的方式保存使用的配置文件。

PrometheusRule: 该CRD定义了我们需要监控告警的规则,有非常重要的一个属性 ruleSelector,用来匹配 rule 规则的过滤器,要求匹配具有 prometheus=k8s 和 role=alert-rules 标签的 PrometheusRule 资源对象。(其实就是把创建的prometheusrule资源聚合到prometheus-k8s-rulefiles-0这个configmap里面,然后挂载到prometheus-server的/etc/prometheus/rules/prometheus-k8s-rulefiles-0/这个路径下面)

然后会在集群里以deployment的方式运行prometheus-operator的controller自定义控制器。这个控制器会定时的list/watch上述的四种主要的crd资源,通过loop循环的方式来调谐管理对应的资源,从而有效的管理监控资源。

日常管理使用

创建监控的流程:

  1. 在程序开发的时候暴露metrics接口并提供监控数据
  2. 创建SVC,确保通过svc的可以正常获取到ep的监控数据
  3. 创建servicemonitor通过svc的label进行绑定,并设置jobLabel(定义通过ep的哪个label的值设置为job的名称),如果metrics接口不是/metrics的时候也可以通过配置path修改默认值

监控ETCD案例:

修改ETCD的metrics的监听地址

这边环境使用kubeadm部署,通过kubectl获取到etcd的配置文件查看:

`[root@dm01 ~]# kubectl get po etcd-dm01 -n kube-system -o yaml| grep -C 10 metrics`
  - command:
    - etcd
    - --advertise-client-urls=https://115.238.100.73:2379
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://115.238.100.73:2380
    - --initial-cluster=dm01=https://115.238.100.73:2380,dm02=https://192.168.1.12:2380,dm03=https://192.168.1.13:2380
    - --key-file=/etc/kubernetes/pki/etcd/server.key
    - --listen-client-urls=https://127.0.0.1:2379,https://115.238.100.73:2379
    - --listen-metrics-urls=http://127.0.0.1:2381  #可以看到默认的是监听在127.0.0.1这个地址上面的 
    - --listen-peer-urls=https://115.238.100.73:2380
    - --name=dm01
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    image: registry.aliyuncs.com/k8sxio/etcd:3.4.13-0
    imagePullPolicy: IfNotPresent

可以看到启动参数里面有一个 --listen-metrics-urls=http://127.0.0.1:2381 的配置,该参数就是来指定 metrics 接口运行在 2381 端口下面的,而且是 http 的协议,所以也不需要什么证书配置,这就比以前的版本要简单许多了,以前的版本需要用 https 协议访问,所以要配置对应的证书。

修改/etc/kubernetes/manifest/ 目录下面(静态 Pod 默认的目录)的 etcd.yaml 文件中将上面的listen-metrics-urls 更改http://0.0.0.0:2381 对外暴露即可,不然等会通过servicemonitor获取的数据的时候会出现被拒绝的情况。

创建ServiceMonitor资源


apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: etcd-k8s  
spec:
  endpoints:
  - interval: 15s     
    port: port
  jobLabel: k8s-app   #设定通过哪个label的值作为job的名称
  namespaceSelector:
    matchNames:
    - kube-system     #匹配哪个命令空间
  selector:
    matchLabels:
      k8s-app: etcd-demo     #匹配svc的label

创建SVC和endpoints

apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: etcd-demo
  name: etcd-k8s
  namespace: kube-system
spec:
  clusterIP: None
  ports:
  - name: port
    port: 2381
    protocol: TCP
    targetPort: 2381
  type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    k8s-app: etcd-demo
  name: etcd-k8s
  namespace: kube-system
subsets:
- addresses:
  - ip: 192.168.1.11
    nodeName: dm01
  - ip: 192.168.1.12
    nodeName: dm02
  - ip: 192.168.1.13
    nodeName: dm03
  ports:
  - name: port
    port: 2381
    protocol: TCP

去prometheus页面上面查看是否获取到ETCD的监控数据

image.png 数据采集到后,可以在 grafana 中导入编号为 3070 的 dashboard,就可以获取到 etcd 的监控图表

image.png

创建PrometheusRule

ETCD监控指标示例

我们设定一个规则,如果ETCD集群存活的节点数小于3的话就触发报警

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: k8s
    role: alert-rules
  name: etcd-rules
  namespace: monitoring
spec:
  groups:
  - name: etcd
    rules:
    - alert: EtcdClusterUnavailable
      annotations:
        description: Node survival is not equal to three
        summary: etcd cluster small
      expr: "sum(up{job="etcd-demo"}) < 3"
      for: 1m 
      labels:
        severity: critical

关键配置说明

1. 创建rule的时候下面的两个label必须满足,这样才能被识别,这个可以通过查看prometheus这个CRD资源到yaml文件中查看到ruleSeletor的定义

`[root@dm01 /opt/softs]# kubectl get Prometheus k8s -o yaml -n monitoring `
···
  ruleSelector:
    matchLabels:
      prometheus: k8s
      role: alert-rules
···

2. expr表示PromQ语法判断有没有满足设定的阀值,for表示满足这个条件多久才会发生告警,一般的话满足条件会处于pending状态,这个表示过了一分钟以后会出firing

      expr: "sum(up{job="etcd-demo"}) < 3"
      for: 1m 

创建完成之后可以在prometheus的rules页面上看到这个规则

image.png

Node内存监控指标示例

`[root@dm01 /opt/softs]# cat node-mem.yaml `
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: k8s
    role: alert-rules
  name: node-mem
  namespace: monitoring
spec:
  groups:
  - name: cronjob
    rules:
    - alert: node-mem-limit
      annotations:
        description: node-exporter {{ $labels.instance }} mem only {{ printf "%.2f" $value}}%  < 15%
        summary: node-mem-limit  alert
      expr: " (node_memory_MemAvailable_bytes{job='node-exporter'} / node_memory_MemTotal_bytes{job='node-exporter'}) * 100 < 15 "
      for: 1m
      labels:
        severity: warning

说明:

这边description参数,{{ $labels.instance }}代表着被监控的服务的label标签下面的那个key值,然后后面{{ printf "%.2f" $value}}这个是对value的一些处理,printf “%.2f”是指value这个值取小数点后面的两位

实现的效果:

description参数=====>> node-exporter cn-hangzhou.xx mem only 11.50% < 15%

容器CPU使用量超过200%

Record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate
`具体实现`
sum by(cluster, namespace, pod, container) (irate(container_cpu_usage_seconds_total{image!="",job="kubelet",metrics_path="/metrics/cadvisor"}[5m])) * on(cluster, namespace, pod) group_left(node) topk by(cluster, namespace, pod) (1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""})) * 100 > 200

容器内存的使用量超过1G

container_memory_working_set_bytes {pod!=""} / (1024*1024*1024) > 1

Altermanager实现企业微信告警

这边测试实现告警时通过Altermanager+prometheusAlter调用企业微信的机器人实现告警。

部署prometheusAlter服务并修改app.conf文件

kubectl apply -n monitoring -f https://raw.githubusercontent.com/feiyu563/PrometheusAlert/master/example/kubernetes/PrometheusAlert-Deployment.yaml

prometheusAlter的配置文件时通过ConfigMap的形式挂载进去的,这个服务提供非常多的告警渠道,我们这边只是使用了微信告警的模式

修改关键配置

`[root@dm01 /etc/kubernetes]# kubectl edit configmap prometheus-alert-center-conf -n monitoring -o yaml`
···
#是否开启微信告警通道,可同时开始多个通道0为关闭,1为开启
open-weixin=1
#默认企业微信机器人地址
wxurl=xxxxx
···

通过创建ingress配置域名访问他的UI界面

可以通过告警测试,查看有没有问题

image.png

image.png

配置Altermanager服务的配置

注:Altermanager的报警文件是存储在alertmanager-secret这个secret里面的,编辑配置

[root@dm01 /etc/kubernetes]# cat /root/kube-prometheus/manifests/alertmanager.yaml
global:
  resolve_timeout: 5m
route:
  group_by: ['instance']
  group_wait: 30s  # 当一个新的报警分组被创建后,需要等待至少 group_wait 时间来初始化通知,这种方式可以确保您能有足够的时间为同一分组来获取多个警报,然后一起触发这个报警信息。
  group_interval: 10s # 相同的group之间发送告警通知的时间间隔
  repeat_interval: 10m  # 如果一个报警信息已经发送成功了,等待 repeat_interval 时间来重新发送他们,不同类型告警发送频率需要具体配置
  receiver: 'web.hook.prometheusalert' # 默认的receiver:如果一个报警没有被一个route匹配,则发送给默认的接收器
  
# 上面所有的属性都由所有子路由继承,并且可以在每个子路由上进行覆盖。
  routes:
  - receiver: 'web.hook.prometheusalert'
    group_wait: 10s
    match:
      level: '1'
receivers:
- name: 'web.hook.prometheusalert'
  webhook_configs: #定义我们上面部署的PrometheusAlter服务的svc地址
  - url: 'http://prometheus-alert-center.monitoring.svc.cluster.local:8080/prometheus/alert'
#如果需要at某人然后使用模板的操作的话可以选用下面这种url,这个url是企业微信的告警形式,还有tpl后面接的是模板,具体可以参考prometheusalert的github说明进行配置 ** 
 # - url: 'https://prometheus-alert.center.monitoring.svc.cluster.local:8080/prometheusalert?type=wx&tpl=aliyun-prometheus&wxurl=微信机器人地址&at=zhangsan'

重新创建alertmanager-main这个secret实现更新

[root@dm01 /etc/kubernetes]# kubectl delete secret alertmanager-main -n monitoring
secret "alertmanager-main" deleted
[root@dm01 /etc/kubernetes]# kubectl create secret generic alertmanager-main --from-file=/root/kube-prometheus/manifests/alertmanager.yaml -n monitoring

prometheusalert模板创建示例

{{ $var := .externalURL}}{{ range $k,$v:=.alerts }}
{{if eq $v.status "resolved"}}
#### [Prometheus恢复信息]({{$v.generatorURL}})

> <font color="info">告警名称</font>:[{{$v.labels.alertname}}]({{$var}})
> <font color="info">告警级别</font>:{{$v.labels.severity}}
> <font color="info">开始时间</font>:{{GetCSTtime $v.startsAt}}
> <font color="info">结束时间</font>:{{GetCSTtime $v.endsAt}}
> <font color="info">主机名称</font>:{{$v.labels.instance}}

**{{$v.annotations.description}}**
{{else}}
#### [Prometheus告警信息]({{$v.generatorURL}})

> <font color="#FF0000">告警名称</font>:[{{$v.labels.alertname}}]({{$var}})
> <font color="#FF0000">告警级别</font>:{{$v.labels.severity}}
> <font color="#FF0000">开始时间</font>:{{GetCSTtime $v.startsAt}}
> <font color="#FF0000">结束时间</font>:{{GetCSTtime $v.endsAt}}
> <font color="#FF0000">主机名称</font>:{{$v.labels.instance}}

**{{$v.annotations.description}}**
{{end}}
{{ end }}

触发报警测试

使一个节点的ETCD挂掉

在kubeadm部署的环境里面直接mv走这个etcd的yaml文件就可以

[root@dm01 /etc/kubernetes/manifests]# mv etcd.yaml /opt/softs/
[root@dm01 /etc/kubernetes/manifests]# docker ps | grep -i etcd

过一分钟查看Alter的状态

image.png

企业微信收到告警

image.png

golang的基础监控实现

用一段最基础的代码

package main

import (
        "net/http"

        "github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {
        http.Handle("/metrics", promhttp.Handler())
        http.ListenAndServe(":2112", nil)
}

通过Dockerfile打包

### Build the manager binary
FROM golang:1.15 as builder

WORKDIR /workspace
ENV GOPROXY="https://goproxy.cn,direct"
# Copy the go source
COPY . .

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -o gotest main.go

# Runtime
FROM alpine

WORKDIR /usr/local/bin
COPY --from=builder /workspace/gotest /usr/local/bin/gotest

CMD ["gotest"]

打包后部署到k8s环境并创建servicemonitor资源

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: go-demo
  namespace: monitoring
  labels:
    k8s-app: go-demo
spec:
  jobLabel: k8s-app
  endpoints:
  - port: port
    interval: 15s
  selector:
    matchLabels:
      k8s-app: go-demo
  namespaceSelector:
    matchNames:
    - test008
---
apiVersion: v1
kind: Service
metadata:
  name: go-demo
  namespace: test008
  labels:
    k8s-app: go-demo
spec:
  type: ClusterIP
  ports:
  - name: port
    port: 2121
  selector:
    k8s-app: go-demo

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-demo
  namespace: test008
  labels:
    k8s-app: go-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: go-demo
  template:
    metadata:
      labels:
        k8s-app: go-demo
    spec:
      containers:
      - name: go-demo
        image: xxx
        ports:
        - containerPort: 2121

问题

这个时候我们创建起来查看控制台会发现,其实并没有获取到我们部署到这个服务,查看prometheus的日志发现,由于prometheus对这个test008没有权限获取资源 image.png

原因

由于我们默认部署的kube-prometheus,他的role和rolebinding只对三个命名空间创建绑定了权限“default”,“monitoring”,“kube-system”,获取别的命名空间里的数据时需要创建对应的role和rolebinding规则

###对指定命名空间创建Role


apiVersion: rbac.authorization.k8s.io/v1
items:
- apiVersion: rbac.authorization.k8s.io/v1
  kind: Role
  metadata:
    name: prometheus-k8s
    namespace: default
  rules:
  - apiGroups:
    - ""
    resources:
    - services
    - endpoints
    - pods
    verbs:
    - get
    - list
    - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses
    verbs:
    - get
    - list
    - watch
- apiVersion: rbac.authorization.k8s.io/v1
  kind: Role
  metadata:
    name: prometheus-k8s
    namespace: kube-system
  rules:
  - apiGroups:
    - ""
    resources:
    - services
    - endpoints
    - pods
    verbs:
    - get
    - list
    - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses
    verbs:
    - get
    - list
    - watch
- apiVersion: rbac.authorization.k8s.io/v1
  kind: Role
  metadata:
    name: prometheus-k8s
    namespace: monitoring
  rules:
  - apiGroups:
    - ""
    resources:
    - services
    - endpoints
    - pods
    verbs:
    - get
    - list
    - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses
    verbs:
    - get
    - list
    - watch
- apiVersion: rbac.authorization.k8s.io/v1
  kind: Role
  metadata:
    name: prometheus-k8s
    namespace: test008
  rules:
  - apiGroups:
    - ""
    resources:
    - services
    - endpoints
    - pods
    verbs:
    - get
    - list
    - watch
  - apiGroups:
    - extensions
    resources:
    - ingresses
    verbs:
    - get
    - list
    - watch
kind: RoleList

创建Rolebinding

apiVersion: rbac.authorization.k8s.io/v1
items:
- apiVersion: rbac.authorization.k8s.io/v1
  kind: RoleBinding
  metadata:
    name: prometheus-k8s
    namespace: default
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: prometheus-k8s
  subjects:
  - kind: ServiceAccount
    name: prometheus-k8s
    namespace: monitoring
- apiVersion: rbac.authorization.k8s.io/v1
  kind: RoleBinding
  metadata:
    name: prometheus-k8s
    namespace: kube-system
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: prometheus-k8s
  subjects:
  - kind: ServiceAccount
    name: prometheus-k8s
    namespace: monitoring
- apiVersion: rbac.authorization.k8s.io/v1
  kind: RoleBinding
  metadata:
    name: prometheus-k8s
    namespace: monitoring
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: prometheus-k8s
  subjects:
  - kind: ServiceAccount
    name: prometheus-k8s
    namespace: monitoring
- apiVersion: rbac.authorization.k8s.io/v1
  kind: RoleBinding
  metadata:
    name: prometheus-k8s
    namespace: test008
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: prometheus-k8s
  subjects:
  - kind: ServiceAccount
    name: prometheus-k8s
    namespace: monitoring
kind: RoleBindingList

控制台查看Target

image.png

prometheus默认保存数据时长修改

修改prometheus operator时间是通过retention参数进行修改,在prometheus.spec下填写

retention: 7d

image.png