从监控平台本身的业务需求来看,至少应该通过平台获取到以下的监控数据:
性能指标(如:CPU、Memory、Load、磁盘、网络等)
状态指标
获取监控数据之后,还需要对监控进行可视化展示,以及对监控中出现的异常情况进行告警。
本文旨在实践一整套监控方案,篇幅限制,不会对Prometheus等组件的基础原理做具体介绍。Prometheus的基本原理可以参考此书:prometheus-book
目前对于kubernetes的主流监控方案主要有以下几种:
总体实现思路如下:
cAdvisor是谷歌开源的一个容器监控工具,cadvisor采集了主机上容器相关的性能指标数据,通过容器的指标还可进一步计算出pod的指标。
cadvisor提供的一些主要指标有:
container_cpu_*
container_fs_*
container_memory_*
container_network_*
container_spec_*(cpu/memory)
container_start_time_*
container_tasks_state_*
可以看到基本都是容器相关的一些资源使用情况。
目前cAdvisor集成到了kubelet组件内,可以在kubernetes集群中每个启动了kubelet的节点使用cAdvisor提供的metrics接口获取该节点所有容器相关的性能指标数据。1.7.3版本以前,cadvisor的metrics数据集成在kubelet的metrics中,在1.7.3以后版本中cadvisor的metrics被从kubelet的metrics独立出来了,在prometheus采集的时候变成两个scrape的job。
cAdvisor对外提供服务的默认端口为***4194***,主要提供两种接口:
Prometheus作为一个时间序列数据收集,处理,存储的服务,能够监控的对象必须通过http api暴露出基于Prometheus认可的数据模型的监控数据,cAdvisor接口(nodeIP:4194/metrics)暴露的监控指标数据如下所示:
# HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.
# TYPE cadvisor_version_info gauge
cadvisor_version_info{cadvisorRevision="",cadvisorVersion="",dockerVersion="1.12.6",kernelVersion="4.9.0-1.2.el7.bclinux.x86_64",osVersion="CentOS Linux 7 (Core)"} 1
# HELP container_cpu_cfs_periods_total Number of elapsed enforcement period intervals.
# TYPE container_cpu_cfs_periods_total counter
container_cpu_cfs_periods_total{container_name="",id="/kubepods/burstable/pod1b0c1f83322defae700f33b1b8b7f572",image="",name="",namespace="",pod_name=""} 7.062239e+06
container_cpu_cfs_periods_total{container_name="",id="/kubepods/burstable/pod7f86ba308f28df9915b802bc48cfee3a",image="",name="",namespace="",pod_name=""} 1.574206e+06
container_cpu_cfs_periods_total{container_name="",id="/kubepods/burstable/podb0c8f695146fe62856bc23709a3e056b",image="",name="",namespace="",pod_name=""} 7.107043e+06
container_cpu_cfs_periods_total{container_name="",id="/kubepods/burstable/podc8cf73836b3caba7bf952ce1ac5a5934",image="",name="",namespace="",pod_name=""} 5.932159e+06
container_cpu_cfs_periods_total{container_name="",id="/kubepods/burstable/podfaa9db59-64b7-11e8-8792-00505694eb6a",image="",name="",namespace="",pod_name=""} 6.979547e+06
container_cpu_cfs_periods_total{container_name="calico-node",id="/kubepods/burstable/podfaa9db59-64b7-11e8-8792-
...
可以看到以上接口的数据是按prometheus的格式输出的。
如下配置Prometheus来定期拉取cAdvisor的metrics:
- job_name: 'cadvisor'
# 通过https访问apiserver,通过apiserver的api获取数据
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从k8s的node对象获取数据
- role: node
relabel_configs:
# 用新的前缀代替原label name前缀,没有replacement的话功能就是去掉label name前缀
# 例如:以下两句的功能就是将__meta_kubernetes_node_label_kubernetes_io_hostname
# 变为kubernetes_io_hostname
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# replacement中的值将会覆盖target_label中指定的label name的值,
# 即__address__的值会被替换为kubernetes.default.svc:443
- target_label: __address__
replacement: kubernetes.default.svc:443
# 获取__meta_kubernetes_node_name的值
- source_labels: [__meta_kubernetes_node_name]
#匹配一个或多个任意字符,将上述source_labels的值生成变量
regex: (.+)
# replacement中的值将会覆盖target_label中指定的label name的值,
# 即__metrics_path__的值会被替换为/api/v1/nodes/${1}/proxy/metrics,
# 其中${1}的值会被替换为__meta_kubernetes_node_name的值
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
metric_relabel_configs:
- action: replace
source_labels: [id]
regex: '^/machine\.slice/machine-rkt\\x2d([^\\]+)\\.+/([^/]+)\.service$'
target_label: rkt_container_name
replacement: '${2}-${1}'
- action: replace
source_labels: [id]
regex: '^/system\.slice/(.+)\.service$'
target_label: systemd_service_name
replacement: '${1}'
之后,在prometheus的target(IP:Port/targets)中可以看到cadvisor相应的target:
备注
关于配置文件的一些说明:
- 以上配置遵照官方example配置,通过apiserver提供的api做代理获取cAdvisor( https://kubernetes.default.svc:443/api/v1/nodes/k8smaster01/proxy/metrics/cadvisor )的监控指标(和从nodeIP:4194/metrics获取到的内容是一样的),而不是直接从node上获取。为什么这样做,官方这样解释的:This means it will work if Prometheus is running out of cluster, or can’t connect to nodes for some other reason (e.g. because of firewalling)。
- Promethues在K8S集群内通过DNS地址 https://kubernetes.default.svc访问apiserver来scrape数据
- Prometheus配置文件的语法规则较复杂,为便于理解,我加了一些注释;更多语法规则请见Prometheus官方文档。
关于target中label的一些说明,target中必有的几个source label有:
__address__
(当static_configs时通过targets手工配置,当kubernetes_sd_configs时,值从apiserver中获取)、__metrics_path__
(默认值是/metrics)、__scheme__
(默认值http)job
其他source label则是根据kubernetes_sd_configs时设置的
- role
(如endpoints、nodes、service、pod等)从k8s资源对象的label、annotation及其他一些信息中提取的。
Prometheus社区提供的NodeExporter项目可以对主机的关键度量指标进行监控,通过Kubernetes的DeamonSet可以在各个主机节点上部署有且仅有一个NodeExporter实例,实现对主机性能指标数据的监控。node-exporter所采集的指标主要有:
node_cpu_*
node_disk_*
node_entropy_*
node_filefd_*
node_filesystem_*
node_forks_*
node_intr_total_*
node_ipvs_*
node_load_*
node_memory_*
node_netstat_*
node_network_*
node_nf_conntrack_*
node_scrape_*
node_sockstat_*
node_time_seconds_*
node_timex _*
node_xfs_*
可以看到全是节点相关的一些资源使用情况。
我的NodeExporter部署文件node-exporter-daemonset.yaml如下,可从github下载。
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: prometheus-node-exporter
namespace: kube-system
labels:
app: prometheus-node-exporter
spec:
template:
metadata:
name: prometheus-node-exporter
labels:
app: prometheus-node-exporter
spec:
containers:
- image: prom/node-exporter:v0.16.0
imagePullPolicy: IfNotPresent
name: prometheus-node-exporter
ports:
- name: prom-node-exp
#^ must be an IANA_SVC_NAME (at most 15 characters, ..)
containerPort: 9100
hostPort: 9100
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
hostNetwork: true
hostPID: true
hostIPC: true
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: 'true'
prometheus.io/app-metrics: 'true'
prometheus.io/app-metrics-path: '/metrics'
name: prometheus-node-exporter
namespace: kube-system
labels:
app: prometheus-node-exporter
spec:
clusterIP: None
ports:
- name: prometheus-node-exporter
port: 9100
protocol: TCP
selector:
app: prometheus-node-exporter
type: ClusterIP
备注:
1.为了让容器里的node-exporter获取到主机上的网络、PID、IPC指标,这里设置了hostNetwork: true、hostPID: true、hostIPC: true,来与主机共用网络、PID、IPC这三个namespace。
2.为了
2.此处在Service的annotations中定义标注prometheus.io/scrape: 'true'
,表明该Service需要被Promethues发现并采集数据。
通过NodeExporter暴露的metrics接口(nodeIP:9100/metrics)查看采集到的数据,可以看到是按Prometheus的格式输出的数据:
# HELP node_arp_entries ARP entries by device
# TYPE node_arp_entries gauge
node_arp_entries{device="calid63983a5754"} 1
node_arp_entries{device="calid67ce395c9e"} 1
node_arp_entries{device="calid857f2bf9d5"} 1
node_arp_entries{device="calief3a4b64165"} 1
node_arp_entries{device="eno16777984"} 9
# HELP node_boot_time Node boot time, in unixtime.
# TYPE node_boot_time gauge
node_boot_time 1.527752719e+09
# HELP node_context_switches Total number of context switches.
# TYPE node_context_switches counter
node_context_switches 3.1425612674e+10
# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="guest"} 0
node_cpu{cpu="cpu0",mode="guest_nice"} 0
node_cpu{cpu="cpu0",mode="idle"} 2.38051096e+06
node_cpu{cpu="cpu0",mode="iowait"} 11904.19
node_cpu{cpu="cpu0",mode="irq"} 0
node_cpu{cpu="cpu0",mode="nice"} 2990.94
node_cpu{cpu="cpu0",mode="softirq"} 8038.3
...
配置Prometheus来scrape node-exporter的metrics:
- job_name: 'prometheus-node-exporter'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
#The endpoints role discovers targets from listed endpoints of a service. For each
#endpoint address one target is discovered per port. If the endpoint is backed by
#a pod, all additional container ports of the pod, not bound to an endpoint port,
#are discovered as targets as well
- role: endpoints
relabel_configs:
# 只保留endpoints的annotations中含有prometheus.io/scrape: 'true'和port的name为prometheus-node-exporter的endpoint
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_endpoint_port_name]
regex: true;prometheus-node-exporter
action: keep
# Match regex against the concatenated source_labels. Then, set target_label to replacement,
# with match group references (${1}, ${2}, ...) in replacement substituted by their value.
# If regex does not match, no replacement takes place.
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)(?::\d+);(\d+)
replacement: $1:$2
# 去掉label name中的前缀__meta_kubernetes_service_label_
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
# 将__meta_kubernetes_namespace重命名为kubernetes_namespace
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
# 将__meta_kubernetes_service_name重命名为kubernetes_name
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
在Prometheus中可以看到相应的target:
有的应用具有暴露容器内具体进程性能指标的需求,这些指标由应用侧实现采集并暴露,平台侧做汇聚。
平台侧可以约定好带哪些annotation前缀的服务是自主暴露监控指标的服务。应用添加平台侧约定的这些annotations,平台侧可以根据这些annotations实现Prometheus的scrape。
例如,应用侧为自己的服务添加如下平台侧约定约定的annotation:
prometheus.io/scrape: 'true'
prometheus.io/app-metrics: 'true'
prometheus.io/app-metrics-port: '8080'
prometheus.io/app-metrics-path: '/metrics'
Prometheus可以:
prometheus.io/scrape: 'true'
获知对应的endpoint是需要被scrape的prometheus.io/app-metrics: 'true'
获知对应的endpoint中有应用进程暴露的metricsprometheus.io/app-metrics-port: '8080'
获知进程暴露的metrics的端口号prometheus.io/app-metrics-path: '/metrics'
获知进程暴露的metrics的具体路径可能还需要根据平台和业务的需求添加其他一些以prometheus.io/app-info-
为前缀的annotation,Prometheus截取下前缀,保留后半部分做key,连同value保留下来。这样满足在平台对应用做其他一些标识的需求。比如加入如下annotation来标识应用所属的的环境、租户以及应用名称:
prometheus.io/app-info-env: 'test'
prometheus.io/app-info-tenant: 'test-tenant'
prometheus.io/app-info-name: 'test-app'
Prometheus的config配置如下:
- job_name: 'kubernetes-app-metrics'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
#The endpoints role discovers targets from listed endpoints of a service. For each
#endpoint address one target is discovered per port. If the endpoint is backed by
#a pod, all additional container ports of the pod, not bound to an endpoint port,
#are discovered as targets as well
- role: endpoints
relabel_configs:
# 只保留endpoint中含有prometheus.io/scrape: 'true'的annotation的endpoint
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_app_metrics]
regex: true;true
action: keep
# 将用户指定的进程的metrics_path替换默认的metrics_path
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_app_metrics_path]
action: replace
target_label: __metrics_path__
regex: (.+)
# 用pod_ip和用户指定的进程的metrics端口组合成真正的可以拿到数据的地址来替换原始__address__
- source_labels: [__meta_kubernetes_pod_ip, __meta_kubernetes_service_annotation_prometheus_io_app_metrics_port]
action: replace
target_label: __address__
regex: (.+);(.+)
replacement: $1:$2
# 去掉label name中的前缀__meta_kubernetes_service_annotation_prometheus_io_app_info_
- action: labelmap
regex: __meta_kubernetes_service_annotation_prometheus_io_app_info_(.+)
备注:
最后两行的作用是将例如
prometheus.io/app-info-tenant
的annotation名切割成名为tenant
的label。
在Prometheus中可以获取到对应的应用进程targets:
blackbox-exporter是一个黑盒探测工具,可以对服务的http、tcp、icmp等进行网络探测。
我的blackbox-exporter部署文件如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: prometheus-blackbox-exporter
namespace: kube-system
spec:
selector:
matchLabels:
app: prometheus-blackbox-exporter
replicas: 1
template:
metadata:
labels:
app: prometheus-blackbox-exporter
spec:
restartPolicy: Always
containers:
- name: prometheus-blackbox-exporter
image: prom/blackbox-exporter:v0.12.0
imagePullPolicy: IfNotPresent
ports:
- name: blackbox-port
containerPort: 9115
readinessProbe:
tcpSocket:
port: 9115
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
requests:
memory: 50Mi
cpu: 100m
limits:
memory: 60Mi
cpu: 200m
volumeMounts:
- name: config
mountPath: /etc/blackbox_exporter
args:
- --config.file=/etc/blackbox_exporter/blackbox.yml
- --log.level=debug
- --web.listen-address=:9115
volumes:
- name: config
configMap:
name: prometheus-blackbox-exporter
nodeSelector:
node-role.kubernetes.io/master: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
---
apiVersion: v1
kind: Service
metadata:
labels:
app: prometheus-blackbox-exporter
name: prometheus-blackbox-exporter
namespace: kube-system
annotations:
prometheus.io/scrape: 'true'
spec:
type: NodePort
selector:
app: prometheus-blackbox-exporter
ports:
- name: blackbox
port: 9115
targetPort: 9115
nodePort: 30009
protocol: TCP
对应的configmap如下:
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: prometheus-blackbox-exporter
name: prometheus-blackbox-exporter
namespace: kube-system
data:
blackbox.yml: |-
modules:
http_2xx:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2"]
valid_status_codes: []
method: GET
preferred_ip_protocol: "ip4"
http_post_2xx: # http post 监测模块
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2"]
method: POST
preferred_ip_protocol: "ip4"
tcp_connect:
prober: tcp
timeout: 10s
icmp:
prober: icmp
timeout: 10s
icmp:
preferred_ip_protocol: "ip4"
备注:
blackbox-exporter的配置文件为/etc/blackbox_exporter/blackbox.yml,可以运行时动态的重新加载配置文件,当重新加载配置文件失败时,不影响在运行的配置。重载方式:curl -XPOST http://IP:9115/-/reload
在Prometheus的config文件中分别配置对http和tcp的探测:
- job_name: 'kubernetes-service-http-probe'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: service
# 将metrics_path由默认的/metrics改为/probe
metrics_path: /probe
# Optional HTTP URL parameters.
# 生成__param_module="http_2xx"的label
params:
module: [http_2xx]
relabel_configs:
# 只保留含有label为prometheus/io=scrape的service
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_http_probe]
regex: true;true
action: keep
- source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_namespace, __meta_kubernetes_service_annotation_prometheus_io_http_probe_port, __meta_kubernetes_service_annotation_prometheus_io_http_probe_path]
action: replace
target_label: __param_target
regex: (.+);(.+);(.+);(.+)
replacement: $1.$2:$3$4
# 用__address__这个label的值创建一个名为__param_target的label为blackbox-exporter,值为内部service的访问地址,作为blackbox-exporter采集用
#- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_http_probe_path]
# action: replace
# target_label: __param_target
# regex: (.+);(.+)
# replacement: $1$2
# 用blackbox-exporter的service地址值”prometheus-blackbox-exporter:9115"替换原__address__的值
- target_label: __address__
replacement: prometheus-blackbox-exporter:9115
- source_labels: [__param_target]
target_label: instance
# 去掉label name中的前缀__meta_kubernetes_service_annotation_prometheus_io_app_info_
- action: labelmap
regex: __meta_kubernetes_service_annotation_prometheus_io_app_info_(.+)
#- source_labels: [__meta_kubernetes_namespace]
# target_label: kubernetes_namespace
#- source_labels: [__meta_kubernetes_service_name]
# target_label: kubernetes_name
## kubernetes-services and kubernetes-ingresses are blackbox_exporter related
# Example scrape config for probing services via the Blackbox Exporter.
#
# The relabeling allows the actual service scrape endpoint to be configured
# for all or only some services.
- job_name: 'kubernetes-service-tcp-probe'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: service
# 将metrics_path由默认的/metrics改为/probe
metrics_path: /probe
# Optional HTTP URL parameters.
# 生成__param_module="tcp_connect"的label
params:
module: [tcp_connect]
relabel_configs:
# 只保留含有label为prometheus/io=scrape的service
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_tcp_probe]
regex: true;true
action: keep
- source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_namespace, __meta_kubernetes_service_annotation_prometheus_io_tcp_probe_port]
action: replace
target_label: __param_target
regex: (.+);(.+);(.+)
replacement: $1.$2:$3
# 用__address__这个label的值创建一个名为__param_target的label为blackbox-exporter,值为内部service的访问地址,作为blackbox-exporter采集用
#- source_labels: [__address__]
# target_label: __param_target
# 用blackbox-exporter的service地址值”prometheus-blackbox-exporter:9115"替换原__address__的值
- target_label: __address__
replacement: prometheus-blackbox-exporter:9115
- source_labels: [__param_target]
target_label: instance
# 去掉label name中的前缀__meta_kubernetes_service_annotation_prometheus_io_app_info_
- action: labelmap
regex: __meta_kubernetes_service_annotation_prometheus_io_app_info_(.+)
应用可以在service中指定平台侧约定的annotation,实现监控平台对该应用的网络服务进行探测:
prometheus.io/scrape: 'true'
prometheus.io/http-probe: 'true'
prometheus.io/http-probe-port: '8080'
prometheus.io/http-probe-path: '/healthz'
prometheus.io/scrape: 'true'
prometheus.io/tcp-probe: 'true'
prometheus.io/tcp-probe-port: '80'
Prometheus根据这些annotation可以获知相应service是需要被探测的,探测的具体网络协议是http还是tcp或其他,以及具体的探测端口。http探测的话还要知道探测的具体url。
在Prometheus中可以获取到对应的targets:
kube-state-metrics采集了k8s中各种资源对象的状态信息:
kube_daemonset_*(创建时间、所处的阶段、期望跑在几台节点上、应当正在运行的节点数量、不应该跑却跑了daemon pod的节点数、跑好了pod(ready)的节点数)
kube_deployment_*(创建时间、是否将k8s的label转化为prometheus的label、所处的阶段、是不是以处于paused状态并不再被dp controller处理、期望副本数、rolling update时最多不可用副本数、dp controller观察到的阶段、实际副本数、availabel副本数、unavailabel副本数、updated副本数)
kube_job_*(是否执行完成、创建时间戳...)
kube_namespace_*
kube_node_*
kube_persistentvolumeclaim_*
kube_pod_container_*
kube_pod_*
kube_replicaset_*
kube_service_*
kube_statefulset_*
查看数据(IP:Port/metrics),可以看到是以prometheus的格式输出:
我的kube-state-metrics部署文件kube-state-metrics-deployment.yaml如下,可以直接从github下载。
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube-state-metrics
namespace: kube-system
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kube-state-metrics
namespace: kube-system
labels:
app: kube-state-metrics
spec:
replicas: 1
template:
metadata:
labels:
app: kube-state-metrics
spec:
serviceAccountName: kube-state-metrics
containers:
- name: kube-state-metrics
image: daocloud.io/liukuan73/kube-state-metrics:v1.1.0
ports:
- containerPort: 8080
restartPolicy: Always
nodeSelector:
node-role.kubernetes.io/master: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
---
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: 'true'
prometheus.io/http-probe: 'true'
prometheus.io/http-probe-path: '/healthz'
prometheus.io/http-probe-port: '8080'
name: kube-state-metrics
namespace: kube-system
labels:
app: kube-state-metrics
spec:
type: NodePort
ports:
- name: kube-state-metrics
port: 8080
targetPort: 8080
nodePort: 30005
selector:
app: kube-state-metrics
配置Prometheus来scrape来自kube-state-metrics的metrics:
- job_name: 'kube-state-metrics'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
#The endpoints role discovers targets from listed endpoints of a service. For each
#endpoint address one target is discovered per port. If the endpoint is backed by
#a pod, all additional container ports of the pod, not bound to an endpoint port,
#are discovered as targets as well
- role: endpoints
relabel_configs:
# 只保留endpoint中的annotations含有prometheus.io/scrape: 'true'和port的name为prometheus-node-exporter的endpoint
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape,__meta_kubernetes_endpoint_port_name]
regex: true;kube-state-metrics
action: keep
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)(?::\d+);(\d+)
replacement: $1:$2
# 去掉label name中的前缀__meta_kubernetes_service_label_
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
# 将__meta_kubernetes_namespace重命名为kubernetes_namespace
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
# 将__meta_kubernetes_service_name重命名为kubernetes_name
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
在prometheus中可以看到相应的target:
etcd、kube-controller-manager、kube-scheduler、kube-proxy、kube-apiserver、kubelet这几个k8d平台组件分别向外暴露了prometheus标准的指标接口/metrics
。可通过配置prometheus来进行读取。
以kubeadm启动的k8s集群中,etcd是以static pod的形式启动的,默认没有service及对应的endpoint可供集群内的prometheus访问。所以首先创建一个用来为prometheus提供接口的service(endpoint),etcd-svc.yaml文件如下:
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: etcd-prometheus-discovery
labels:
component: etcd
annotations:
prometheus.io/scrape: 'true'
spec:
selector:
component: etcd
type: ClusterIP
clusterIP: None
ports:
- name: http-metrics
port: 2379
targetPort: 2379
protocol: TCP
prometheus配置抓取的文件加入如下配置:
- job_name: 'etcd'
# 通过https访问apiserver
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从endpoints获取apiserver数据
- role: endpoints
#relabel_configs允许在抓取之前对任何目标及其标签进行修改。
relabel_configs:
# 选择哪些label
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_namespace, __meta_kubernetes_service_name]
# 上述选择的label的值需要与下述对应
regex: true;kube-system;etcd-prometheus-discovery
# 含有符合regex的source_label的endpoints进行保留
action: keep
kube-proxy通过10249端口暴露/metrics指标。与3.6.1同理,kube-proxy-svc.yaml如下:
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: kube-proxy-prometheus-discovery
labels:
k8s-app: kube-proxy
annotations:
prometheus.io/scrape: 'true'
spec:
selector:
k8s-app: kube-proxy
type: ClusterIP
clusterIP: None
ports:
- name: http-metrics
port: 10249
targetPort: 10249
protocol: TCP
prometheus配置抓取的文件加入如下配置:
- job_name: 'kube-proxy'
# 通过https访问apiserver
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从endpoints获取apiserver数据
- role: endpoints
#relabel_configs允许在抓取之前对任何目标及其标签进行修改。
relabel_configs:
# 选择哪些label
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_namespace, __meta_kubernetes_service_name]
# 上述选择的label的值需要与下述对应
regex: true;kube-system;kube-proxy-prometheus-discovery
# 含有符合regex的source_label的endpoints进行保留
action: keep
kube-scheduler通过10251端口暴露/metrics指标。与3.6.1同理,kube-scheduler-svc.yaml如下:
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: kube-scheduler-prometheus-discovery
labels:
k8s-app: kube-scheduler
annotations:
prometheus.io/scrape: 'true'
spec:
selector:
component: kube-scheduler
type: ClusterIP
clusterIP: None
ports:
- name: http-metrics
port: 10251
targetPort: 10251
protocol: TCP
prometheus对应的配置如下:
- job_name: 'kube-scheduler'
# 通过https访问apiserver
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从endpoints获取apiserver数据
- role: endpoints
#relabel_configs允许在抓取之前对任何目标及其标签进行修改。
relabel_configs:
# 选择哪些label
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_namespace, __meta_kubernetes_service_name]
# 上述选择的label的值需要与下述对应
regex: true;kube-system;kube-scheduler-prometheus-discovery
# 含有符合regex的source_label的endpoints进行保留
action: keep
kube-controller-manager通过10252端口暴露/metrics指标。与3.6.1同理,kube-controller-manager-svc.yaml如下:
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: kube-controller-manager-prometheus-discovery
labels:
k8s-app: kube-controller-manager
annotations:
prometheus.io/scrape: 'true'
spec:
selector:
component: kube-controller-manager
type: ClusterIP
clusterIP: None
ports:
- name: http-metrics
port: 10252
targetPort: 10252
protocol: TCP
prometheus配置抓取的文件加入如下配置:
- job_name: 'kube-controller-manager'
# 通过https访问apiserver
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从endpoints获取apiserver数据
- role: endpoints
#relabel_configs允许在抓取之前对任何目标及其标签进行修改。
relabel_configs:
# 选择哪些label
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_namespace, __meta_kubernetes_service_name]
# 上述选择的label的值需要与下述对应
regex: true;kube-system;kube-controller-manager-prometheus-discovery
# 含有符合regex的source_label的endpoints进行保留
action: keep
以上四步配置好后可以看到分别增加了etcd-prometheus-discovery、kube-controller-manager-prometheus-discovery、kube-scheduler-prometheus-discovery和kube-proxy四个endpints:
prometheus中也可以看到抓取到了相应target:
kube-apiserver与上面四个组件不同的是,部署好后集群中默认会有一个名为kubernetes的service和对应的名为kubernetes的endpoint,这个endpoint就是集群内的kube-apiserver的访问入口。可以如下配置prometheus抓取数据:
- job_name: 'kube-apiservers'
# 通过https访问apiserver
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从endpoints获取apiserver数据
- role: endpoints
#relabel_configs允许在抓取之前对任何目标及其标签进行修改。
relabel_configs:
# 选择哪些label
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
# 上述选择的label的值需要与下述对应
regex: default;kubernetes;https
# 含有符合regex的source_label的endpoints进行保留
action: keep
之后就可以看到prometheus多了一个kube-apiserver的target:
kubelet暴露的metrics端口默认为 10255:
kubelet采集的指标主要有:
apiserver_client_certificate_expiration_seconds_bucket
apiserver_client_certificate_expiration_seconds_sum
apiserver_client_certificate_expiration_seconds_count
etcd_helper_cache_entry_count
etcd_helper_cache_hit_count
etcd_helper_cache_miss_count
etcd_request_cache_add_latencies_summary
etcd_request_cache_add_latencies_summary_sum
etcd_request_cache_add_latencies_summary_count
etcd_request_cache_get_latencies_summary
etcd_request_cache_get_latencies_summary_sum
etcd_request_cache_get_latencies_summary_count
kubelet_cgroup_manager_latency_microseconds
kubelet_containers_per_pod_count
kubelet_docker_operations
kubelet_network_plugin_operations_latency_microseconds
kubelet_pleg_relist_interval_microseconds
kubelet_pleg_relist_latency_microseconds
kubelet_pod_start_latency_microseconds
kubelet_pod_worker_latency_microseconds
kubelet_running_container_count
kubelet_running_pod_count
kubelet_runtime_operations*
kubernetes_build_info
process_cpu_seconds_total
reflector*
rest_client_request_*
storage_operation_duration_seconds_*
查看kubelet监控指标数据(nodeIP:10255/metrics):
# HELP apiserver_audit_event_total Counter of audit events generated and sent to the audit backend.
# TYPE apiserver_audit_event_total counter
apiserver_audit_event_total 0
# HELP apiserver_client_certificate_expiration_seconds Distribution of the remaining lifetime on the certificate used to authenticate a request.
# TYPE apiserver_client_certificate_expiration_seconds histogram
apiserver_client_certificate_expiration_seconds_bucket{le="0"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="21600"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="43200"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="86400"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="172800"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="345600"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="604800"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="2.592e+06"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="7.776e+06"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="1.5552e+07"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="3.1104e+07"} 0
apiserver_client_certificate_expiration_seconds_bucket{le="+Inf"} 4161
apiserver_client_certificate_expiration_seconds_sum 1.3091542942737878e+12
apiserver_client_certificate_expiration_seconds_count 4161
...
kubelet由于在每个节点上都有且仅有一个,所以可以通过k8s的node对象找到kubelet的指标,prometheus配置如下:
- job_name: 'kubelet'
# 通过https访问apiserver,通过apiserver的api获取数据
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#以k8s的角色(role)来定义收集,比如node,service,pod,endpoints,ingress等等
kubernetes_sd_configs:
# 从k8s的node对象获取数据
- role: node
relabel_configs:
# 用新的前缀代替原label name前缀,没有replacement的话功能就是去掉label_name前缀
# 例如:以下两句的功能就是将__meta_kubernetes_node_label_kubernetes_io_hostname
# 变为kubernetes_io_hostname
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# replacement中的值将会覆盖target_label中指定的label name的值,
# 即__address__的值会被替换为kubernetes.default.svc:443
- target_label: __address__
replacement: kubernetes.default.svc:443
#replacement: 10.142.21.21:6443
# 获取__meta_kubernetes_node_name的值
- source_labels: [__meta_kubernetes_node_name]
#匹配一个或多个任意字符,将上述source_labels的值生成变量
regex: (.+)
# 将# replacement中的值将会覆盖target_label中指定的label name的值,
# 即__metrics_path__的值会被替换为/api/v1/nodes/${1}/proxy/metrics,
# 其中${1}的值会被替换为__meta_kubernetes_node_name的值
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics
#or:
#- source_labels: [__address__]
# regex: '(.*):10250'
# replacement: '${1}:4194'
# target_label: __address__
#- source_labels: [__meta_kubernetes_node_label_role]
# action: replace
# target_label: role
前面介绍了K8S平台的监控数据怎么采集出来,接下来介绍怎么用prometheus收集和处理。
configmap-prom-config.yaml,这个是我改写的prometheus全局配置的configmap文件,我参考的Github官方示例,然后做适当改动并增加了一些注释。prometheus的config文件的更详细语法请见官网
Prometheus中的告警规则允许用户基于PromQL表达式定义告警触发条件,Prometheus后端对这些触发规则进行周期性的计算,当满足触发条件后会触发告警通知。用户可以通过Prometheus的Web界面查看这些告警规则(/rules)以及告警的触发状态(/alerts)。当Promthues与Alertmanager关联之后,可以将告警发送到外部服务如Alertmanager中并通过Alertmanager可以对这些告警进行进一步的处理。
在Prometheus全局配置文件中通过rule_files
指定一组告警规则文件的路径。Prometheus启动后会自动扫描这些路径下规则文件中定义的内容,并且根据这些规则计算是否向外部发送通知。计算告警触发条件的周期可以通过global下的evaluation_interval
进行配置:
global:
[ evaluation_interval: | default = 1m ]
rule_files:
[ - ... ]
告警规则文件使用yaml格式进行定义,一个典型的告警配置如下:
groups:
- name: example
rules:
- alert: HighErrorRate
expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
for: 10m
labels:
severity: page
annotations:
summary: High request latency
description: description info
在告警规则文件中,我们可以将一组相关的规则设置定义在一个group下。在每一个group中我们可以定义多个告警规则(rule)。一条告警规则主要由以下几部分组成:
alert
:告警规则的名称。expr
:基于PromQL表达式告警触发条件,用于计算是否有时间序列满足该条件。for
:评估等待时间,可选参数。用于表示只有当触发条件持续一段时间后才发送告警。在等待期间新产生告警的状态为pending。labels
:自定义标签,允许用户指定要附加到告警上的一组附加标签。annotations
:用于指定一组附加信息,比如用于描述告警详细信息的文字等。Prometheus根据global.evaluation_interval定义的周期计算PromQL表达式。如果PromQL表达式能够找到匹配的时间序列则会为每一条时间序列产生一个告警实例。
rules的config文件的详细语法请见官网
一般来说,在告警规则文件的annotations中使用summary描述告警的概要信息,description用于描述告警的详细信息。同时Alertmanager的UI也会根据这两个标签值,显示告警信息。为了让告警信息具有更好的可读性,Prometheus支持模板化label和annotations的中标签的值。
通过$labels.
变量可以访问当前告警实例中指定标签的值。$value
则可以获取当前PromQL表达式计算的样本值。
# To insert a firing element's label values:
{{ $labels. }}
# To insert the numeric expression value of the firing element:
{{ $value }}
例如,可以通过模板化优化summary以及description的内容的可读性:
groups:
- name: example
rules:
# Alert for any instance that is unreachable for >5 minutes.
- alert: InstanceDown
expr: up == 0
for: 5m
labels:
severity: page
annotations:
summary: "Instance {{ $labels.instance }} down"
description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
# Alert for any instance that has a median request latency >1s.
- alert: APIHighRequestLatency
expr: api_http_request_latencies_second{quantile="0.5"} > 1
for: 10m
annotations:
summary: "High request latency on {{ $labels.instance }}"
description: "{{ $labels.instance }} has a median request latency above 1s (current value: {{ $value }}s)"
configmap-prom-rule.yaml,这是我的prometheus配置告警规则的configmap文件。参考的这里
告警规则允许你定义基于Prometheus语言表达的报警条件,并发送报警通知到外部服务,如AlertManager。rules的config文件的详细语法请见官网
可以在Prometheus的alert界面看到告警规则:
可以在Prometheus的alert界面看到告警信息:
prometheus.yaml是prometheus以deployment起在kubernetes上的部署文件,给出了两种部署方式,分别是集群开启和未开启rbac时的部署文件,以开启rbac时的为例,内容如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: prometheus
namespace: kube-system
labels:
app: prometheus
spec:
replicas: 1
template:
metadata:
name: prometheus
labels:
app: prometheus
spec:
serviceAccountName: prometheus
# hostNetwork: true
containers:
- name: prometheus
image: prom/prometheus:v2.3.2
imagePullPolicy: IfNotPresent
args:
- '--storage.tsdb.path=/prometheus/data/'
- '--storage.tsdb.retention=1d'
- '--config.file=/etc/prometheus/prometheus.yaml'
- '--web.enable-lifecycle'
ports:
- name: webui
containerPort: 9090
resources:
requests:
cpu: 500m
memory: 500M
# limits:
# cpu: 500m
# memory: 500M
volumeMounts:
- name: config-volume
mountPath: /etc/prometheus
- name: rules-volume
mountPath: /etc/prometheus-rules
volumes:
- name: config-volume
configMap:
name: prometheus
- name: rules-volume
configMap:
name: prometheus-rules
nodeSelector:
node-role.kubernetes.io/master: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
---
apiVersion: v1
kind: Service
metadata:
name: prometheus
namespace: kube-system
labels:
app: prometheus
annotations:
prometheus.io/scrape: 'true'
spec:
type: NodePort
# type: ClusterIP
ports:
- name: webui
port: 9090
protocol: TCP
nodePort: 30006
selector:
app: prometheus
对args参数做几点说明:
--storage.tsdb.path
:tsdb数据库存储路径--storage.tsdb.retention
:数据保留多久,可以看官方文档存储部分--config.file
:指定prometheus的config文件的路径--web.enable-lifecycle
:加上这个参数后可以向/-/reload
(curl -XPOST 10.142.232.150:30006/-/reload)发送HTTP POST请求实现prometheus在config文件修改后的动态reload,更多信息请查看官方文档--web.enable-admin-api
:加上这个参数可以为一些高级用户暴露操作数据库功能的API,比如快照备份(curl -XPOST http://>/api/v2/admin/tsdb/snapshot),更多信息请查看官方文档 TSDB Admin APIs
部分
启动后可以(IP:Port/targets)查看所有targets:
更多告警规则用法请参考:https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/alert/prometheus-alert-rule
rpm部署方式:
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm
yum -y localinstall grafana-5.0.4-1.x86_64.rpm
systemctl enable grafana-server
systemctl start grafana-server
docker部署方式:
docker run -d -p 3000:3000 --name=grafana -e "GF_SERVER_HTTP_PORT=3000" -e "GF_AUTH_BASIC_ENABLED=false" -e "GF_AUTH_ANONYMOUS_ENABLED=true" -e "GF_AUTH_ANONYMOUS_ORG_ROLE=Admin" -e "GF_SERVER_ROOT_URL=/" daocloud.io/liukuan73/grafana:5.0.0
kubernetes部署方式(推荐):
安装grafana,grafana.yaml如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: monitoring-grafana
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
task: monitoring
k8s-app: grafana
spec:
containers:
- name: grafana
image: daocloud.io/liukuan73/grafana:5.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
protocol: TCP
volumeMounts:
- mountPath: /var
name: grafana-storage
env:
- name: INFLUXDB_HOST
value: monitoring-influxdb
- name: GF_SERVER_HTTP_PORT
value: "3000"
# The following env variables are required to make Grafana accessible via
# the kubernetes api-server proxy. On production clusters, we recommend
# removing these env variables, setup auth for grafana, and expose the grafana
# service using a LoadBalancer or a public IP.
- name: GF_AUTH_BASIC_ENABLED
value: "false"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
value: Admin
- name: GF_SERVER_ROOT_URL
# If you're only using the API Server proxy, set this value instead:
# value: /api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
value: /
volumes:
- name: grafana-storage
emptyDir: {}
nodeSelector:
node-role.kubernetes.io/master: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
---
apiVersion: v1
kind: Service
metadata:
labels:
# For use as a Cluster add-on (https://github.com/kubernetes/kubernetes/tree/master/cluster/addons)
# If you are NOT using this as an addon, you should comment out this line.
kubernetes.io/cluster-service: 'true'
kubernetes.io/name: monitoring-grafana
annotations:
prometheus.io/scrape: 'true'
prometheus.io/tcp-probe: 'true'
prometheus.io/tcp-probe-port: '80'
name: monitoring-grafana
namespace: kube-system
spec:
type: NodePort
# In a production setup, we recommend accessing Grafana through an external Loadbalancer
# or through a public IP.
# type: LoadBalancer
# You could also use NodePort to expose the service at a randomly-generated port
# type: NodePort
ports:
- port: 80
targetPort: 3000
nodePort: 30007
selector:
k8s-app: grafana
配置prometheus数据源:
点击“Add data source”配置数据源:
配置dashboard:
可以手工配置dashboard,也可以如下图直接使用官网上别人分享的已配好的模板,直接输入需要import的模板号即可:
效果:
一些比较实用的模板:
设置警报和通知的主要步骤:
部署文件alertmanager.yaml如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: alertmanager
namespace: kube-system
spec:
replicas: 1
template:
metadata:
name: alertmanager
labels:
app: alertmanager
spec:
containers:
- name: alertmanager
image: prom/alertmanager:v0.11.0
args
- '-config.file=/etc/alertmanager/config.yml'
- '-storage.path=/alertmanager'
- '-web.external-url=http://alertmanager:9093'
ports:
- name: alertmanager
containerPort: 9093
# env:
# - name: EXTERNAL_URL
# valueFrom:
# configMapKeyRef:
# name: external-url
# key: url
volumeMounts:
- name: config-volume
mountPath: /etc/alertmanager
# - name: templates-volume
# mountPath: /etc/alertmanager-templates
- name: alertmanager
mountPath: /alertmanager
volumes:
- name: config-volume
configMap:
name: alertmanager
# - name: templates-volume
# configMap:
# name: alertmanager-templates
- name: alertmanager
emptyDir: {}
nodeSelector:
node-role.kubernetes.io/master: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
effect: "NoSchedule"
---
apiVersion: v1
kind: Service
metadata:
name: alertmanager
namespace: kube-system
annotations:
prometheus.io/scrape: 'true'
prometheus.io/path: '/alertmanager/metrics'
labels:
name: alertmanager
spec:
selector:
app: alertmanager
type: NodePort
ports:
- name: alertmanager
protocol: TCP
port: 9093
targetPort: 9093
nodePort: 30008
alertmanager的配置文件configmap-alertmanager.yaml如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager
namespace: kube-system
data:
config.yml: |-
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.exmail.qq.com:25'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'yourpassword'
slack_api_url: ''
route:
receiver: slack-notifications
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 15m
routes:
- match:
severity: email
receiver: email_alert
receivers:
- name: 'email_alert'
email_configs:
- to: '[email protected]'
from: 'test.com'
smarthost: "smtp.163.com:25"
auth_username: "liukuan73"
auth_password: "123456"
require_tls: true
- name: 'slack-notifications'
slack_configs:
- channel: '#alerts'
- name: 'test-webhook'
webhook_configs:
- url: 'alertmanager:9093/api/v1/monitor'
send_resolved: true
可以在运行时动态的重新加载配置文件,当重新加载配置文件失败时,不影响在运行的配置。重载方式:curl -XPOST http://IP:9093/-/reload。告警部分的配置语法请见官网文档
在Prometheus的架构中被划分成两个独立的部分。Prometheus负责产生告警,而Alertmanager负责告警产生后的后续处理。因此Alertmanager部署完成后,需要在Prometheus中设置Alertmanager相关的信息。
编辑Prometheus配置文件prometheus.yml,并添加以下内容
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
reload Prometheus后可以在AlertManager的webui上查看告警信息:http://IP:Port
Alertmanager的配置主要包含两个部分:路由(route)以及接收器(receivers)。所有的告警信息都会从配置中的顶级路由(route)进入路由树,根据路由规则将告警信息发送给相应的接收器。
在Alertmanager中可以定义一组接收器,比如可以按照角色(比如系统运维,数据库管理员)来划分多个接收器。接收器可以关联邮件,Slack以及其它方式接收告警信息。
route:
receiver: 'default-receiver'
receivers:
- name: default-receiver
以上配置文件中定义了一个默认的接收者default-receiver,由于这里没有设置接收方式,目前只相当于一个占位符。
在配置文件中使用route定义了顶级的路由,路由是一个基于标签匹配规则的树状结构。所有的告警信息从顶级路由开始,根据标签匹配规则进入到不同的子路由,并且根据子路由设置的接收器发送告警。目前配置文件中只设置了一个顶级路由route并且定义的接收器为default-receiver。因此,所有的告警都会发送给default-receiver。
路由的配置格式如下:
[ receiver: ]
[ group_by: '[' , ... ']' ]
[ continue: | default = false ]
match:
[ : , ... ]
match_re:
[ : , ... ]
[ group_wait: | default = 30s ]
[ group_interval: | default = 5m ]
[ repeat_interval: | default = 4h ]
routes:
[ - ... ]
首先每一个告警都会从配置文件中顶级的route进入路由树,需要注意的是顶级的route必须匹配所有告警,即不能有任何的匹配设置(match/match_re),每一个路由都可以定义自己的接收器。告警进入到顶级路由后会遍历所有的子节点。如果设置了continue
的值为false,则告警在匹配到第一个子节点之后就直接停止。如果continue
为true,报警则会继续进行后续子节点的匹配。如果当前告警匹配不到任何的子节点,那么该告警将会基于当前路由节点的接收器配置方式进行处理。
其中告警的匹配有两种方式可以选择。一种方式基于字符串验证,通过设置match
规则判断当前告警中是否存在标签labelname并且其值等于labelvalue。第二种方式则基于正则表达式,通过设置match_re
验证当前告警标签的值是否满足正则表达式的内容。
在之前的部分有讲过,Alertmanager可以对告警通知进行分组,将多条告警合合并为一个通知。这里我们可以使用group_by
来定义分组规则。基于告警中包含的标签,如果满足group_by
中定义标签名称,那么这些告警将会合并为一个通知发送给接收器。
有的时候为了能够一次性收集和发送更多的相关信息,可以通过group_wait
参数设置等待时间,如果在等待时间内当前group接收到了新的告警,这些告警将会合并为一个通知向receiver发送。
而group_interval
配置,则用于定义相同的Gourp之间发送告警通知的时间间隔。
如果警报已经成功发送通知, 如果想设置发送告警通知之前要等待时间,则可以通过repeat_interval
参数进行设置。
例如,当使用Prometheus监控多个集群以及部署在集群中的应用和数据库服务,并且定义以下的告警处理路由规则来对集群中的异常进行通知。
route:
receiver: 'default-receiver'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
group_by: [cluster, alertname]
routes:
- receiver: 'database-pager'
group_wait: 10s
match_re:
service: mysql|cassandra
- receiver: 'frontend-pager'
group_by: [product, environment]
match:
team: frontend
默认情况下所有的告警都会发送给集群管理员default-receiver,因此在Alertmanager的配置文件的根路由中,对告警信息按照集群以及告警的名称对告警进行分组。
如果告警时来源于数据库服务如MySQL或者Cassandra,此时则需要将告警发送给相应的数据库管理员(database-pager)。这里定义了一个单独子路由,如果告警中包含service标签,并且service为MySQL或者Cassandra,则向database-pager发送告警通知,由于这里没有定义group_by等属性,这些属性的配置信息将从上级路由继承,database-pager将会接收到按cluser和alertname进行分组的告警通知。
而某些告警规则来源可能来源于开发团队的定义,这些告警中通过添加标签team来标示这些告警的创建者。在Alertmanager配置文件的告警路由下,定义单独子路由用于处理这一类的告警通知,如果匹配到告警中包含标签team,并且team的值为frontend,Alertmanager将会按照标签product和environment对告警进行分组。此时如果应用出现异常,开发团队就能清楚的知道哪一个环境(environment)中的哪一个应用程序出现了问题,可以快速对应用进行问题定位。
更多路由配置实例请参考:https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/alert/alert-manager-routes
告警接收器可以通过以下形式进行配置:
receivers:
- ...
每一个receiver具有一个全局唯一的名称,并且对应一个或者多个通知方式:
name:
email_configs:
[ - , ... ]
hipchat_configs:
[ - , ... ]
pagerduty_configs:
[ - , ... ]
pushover_configs:
[ - , ... ]
slack_configs:
[ - , ... ]
opsgenie_configs:
[ - , ... ]
webhook_configs:
[ - , ... ]
victorops_configs:
[ - , ... ]
目前官方内置的第三方通知集成包括:
每一个receiver可以对应一组邮件通知配置email_configs,如下所示:
name:
email_configs:
[ - , ... ]
email_config配置:
# Whether or not to notify about resolved alerts.
[ send_resolved: | default = false ]
# The email address to send notifications to.
to:
# The sender address.
[ from: | default = global.smtp_from ]
# The SMTP host through which emails are sent.
[ smarthost: | default = global.smtp_smarthost ]
# SMTP authentication information.
[ auth_username: | default = global.smtp_auth_username ]
[ auth_password: | default = global.smtp_auth_password ]
[ auth_secret: | default = global.smtp_auth_secret ]
[ auth_identity: | default = global.smtp_auth_identity ]
# The SMTP TLS requirement.
[ require_tls: | default = global.smtp_require_tls ]
# The HTML body of the email notification.
[ html: | default = '{{ template "email.default.html" . }}' ]
# Further headers email header key/value pairs. Overrides any headers
# previously set by the notification implementation.
[ headers: { : , ... } ]
如果所有的邮件配置使用了相同的SMTP配置,则可以直接定义全局的SMTP配置。
global:
[ smtp_from: ]
[ smtp_smarthost: ]
[ smtp_auth_username: ]
[ smtp_auth_password: ]
[ smtp_auth_secret: ]
[ smtp_auth_identity: ]
[ smtp_require_tls: | default = true ]
以Gmail邮箱为例:
global:
smtp_smarthost: smtp.gmail.com:587
smtp_from:
smtp_auth_username:
smtp_auth_identity:
smtp_auth_password:
receivers:
- name: default-receiver
email_configs:
- to:
在某些情况下除了Alertmanager已经内置的集中告警通知方式以外,对于不同的用户和组织而言还需要一些自定义的告知方式支持。通过Alertmanager提供的webhook支持可以轻松实现这一类的扩展。除了用于支持额外的通知方式,webhook还可以与其他第三方系统集成实现运维自动化,或者弹性伸缩等。
在Alertmanager中可以使用如下配置定义基于webhook的告警接收器receiver。一个receiver可以对应一组webhook配置。
name:
webhook_configs:
[ - , ... ]
每一项webhook_config的具体配置格式如下:
# Whether or not to notify about resolved alerts.
[ send_resolved: | default = true ]
# The endpoint to send HTTP POST requests to.
url:
# The HTTP client's configuration.
[ http_config: | default = global.http_config ]
send_resolved用于指定是否在告警消除时发送回执消息。url则是用于接收webhook请求的地址。http_configs则是在需要对请求进行SSL配置时使用。
当用户定义webhook用于接收告警信息后,当告警被触发时,Alertmanager会按照以下格式向这些url地址发送HTTP Post请求,请求内容如下:
{
"version": "4",
"groupKey": , // key identifying the group of alerts (e.g. to deduplicate)
"status": "",
"receiver": ,
"groupLabels":
更多webhook方式实例请参看:https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/alert/alert-manager-extension-with-webhook
更多K8S精彩内容,请订阅本人微信公众号:K8SPractice
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!