介绍
Prometheus Operator 为 Kubernetes 提供了对 Prometheus 机器相关监控组件的本地部署和管理方案,该项目的目的是为了简化和自动化基于 Prometheus 的监控栈配置,主要包括以下几个功能:
Kubernetes 自定义资源:使用 Kubernetes CRD 来部署和管理 Prometheus、Alertmanager 和相关组件。 简化的部署配置:直接通过 Kubernetes 资源清单配置 Prometheus,比如版本、持久化、副本、保留策略等等配置。 Prometheus 监控目标配置:基于熟知的 Kubernetes 标签查询自动生成监控目标配置,无需学习 Prometheus 特地的配置。
Prometheus Operator 的架构图:
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循环的方式来调谐管理对应的资源,从而有效的管理监控资源。
日常管理使用
创建监控的流程:
- 在程序开发的时候暴露metrics接口并提供监控数据
- 创建SVC,确保通过svc的可以正常获取到ep的监控数据
- 创建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的监控数据
数据采集到后,可以在 grafana 中导入编号为 3070 的 dashboard,就可以获取到 etcd 的监控图表
创建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页面上看到这个规则
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界面
可以通过告警测试,查看有没有问题
配置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的状态
企业微信收到告警
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没有权限获取资源
原因
由于我们默认部署的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
prometheus默认保存数据时长修改
修改prometheus operator时间是通过retention参数进行修改,在prometheus.spec下填写
retention: 7d