K8S监控-Prometheus

K8S监控-Prometheus

在 Kubernetes(K8s)中使用 Prometheus 进行监控时,有一些关键的指标和参数,通常需要关注以确保集群的健康和性能

1、API Server

参数 含义
apiserver_request_duration_seconds API 请求的响应时间
apiserver_request_total API 请求的总次数,区分成功与失败
apiserver_dropped_requests_total 丢失的请求数
apiserver_long_running_queries 长时间运行的查询

2、Controller Manager

参数 含义
controller_manager_runs_total 控制器管理器的执行次数
controller_manager_duration_seconds 控制器管理器运行的时间

3、Scheduler

参数 含义
scheduler_e2e_duration_seconds 调度的总时长
scheduler_queue_latency_seconds 队列延迟的时间

4、Node Metrics

参数 含义
node_cpu_seconds_total 节点的 CPU 使用时间
node_memory_bytes 节点的内存使用量
node_disk_io_time_seconds_total 节点磁盘 I/O 时间
node_network_receive_bytes_total 网络流量的接收字节数
node_network_transmit_bytes_total 网络流量的发送字节数

5、Kubelet

参数 含义
kubelet_running_pods 当前正在运行的 pod 数量
kubelet_network_receive_bytes_total/kubelet_network_transmit_bytes_total Kubelet 网络流量
kubelet_cpu_usage_seconds_total Kubelet 使用的 CPU 时间
kubelet_memory_usage_bytes Kubelet 使用的内存量

6、Kube Proxy

参数 含义
kubeproxy_connections_open 当前打开的连接数
kubeproxy_errors_total 代理组件的错误总数

7、Pod

参数 含义
container_cpu_usage_seconds_total 容器的 CPU 使用时间
container_memory_usage_bytes 容器的内存使用量
container_memory_rss 容器的常驻内存集大小
container_network_receive_bytes_total/container_network_transmit_bytes_total 容器的网络接收或发送字节数
container_fs_usage_bytes 容器使用的文件系统存储量
container_fs_inodes_usage 容器使用的文件系统 inode 数量
kube_pod_container_status_restarts_total Pod 容器重启的总次数

8、Controller

参数 含义
kube_deployment_status_replicas 当前 Deployment 的副本数量
kube_replica_set_status_replicas 当前 ReplicaSet 的副本数量
kube_pod_status_ready Pod 是否处于就绪状态

9、SVC/Node

参数 含义
apiserver_request_total 向 Kubernetes API Server 发起的请求总数
kube_endpoint_address_available 服务的端点是否可用
service_request_duration_seconds 服务请求的响应时间
kube_node_status_allocatable_cpu_cores 节点可分配的 CPU 核心数
kube_node_status_allocatable_memory_bytes 节点可分配的内存量
kube_pod_container_resource_requests_cpu_cores Pod 对 CPU 的请求
kube_pod_container_resource_requests_memory_bytes Pod 对内存的请求

Prometheus简介

Prometheus 是一个开源的监控和报警系统,专门设计用于大规模的分布式系统监控。它最初由 SoundCloud 开发,后来成为 CNCF(云原生计算基金会)的一部分。Prometheus 主要用于收集、存储、查询和可视化指标数据(metrics),并能够通过定义的规则触发报警。它在容器化环境和微服务架构中尤其流行,广泛应用于 Kubernetes、Docker 和云原生应用的监控。

Prometheus 的核心功能

1、数据采集:Prometheus 通过 HTTP 协议定期从被监控的应用或服务中拉取(Pull)指标数据。这些数据通常是以时间序列(Time Series)的形式存储,每个时间序列都有一个唯一的标识符,通常由 指标名称 和一组 标签(Labels)组成

2、时间序列存储:Prometheus 使用自己的时序数据库(TSDB)来存储监控数据,支持高效地存储和查询时间序列数据。这些数据按时间戳组织,可以精确到秒级,支持长期存储

3、强大的查询语言(PromQL):Prometheus 提供了一种称为 PromQL(Prometheus Query Language)的查询语言,允许用户以灵活的方式查询存储的时间序列数据。你可以使用 PromQL 来执行聚合、过滤、计算、切分等操作

4、自动发现服务: Prometheus 支持自动服务发现(Service Discovery),可以自动识别和抓取目标的指标数据。它支持多种服务发现机制,如 Kubernetes、Consul、DNS、EC2 等。对于 Kubernetes,Prometheus 可以自动发现各个 Pod 和服务,轻松集成在容器化环境中

5、报警功能: Prometheus 具有强大的报警功能,用户可以基于 PromQL 查询表达式设置报警规则。如果某个指标超过指定阈值,Prometheus 可以将警报发送给 Alertmanager(一个专门处理警报的组件),并通过电子邮件、Slack、PagerDuty 等渠道发送警报通知

6、Grafana 集成: Prometheus 生成的时间序列数据可以通过 Grafana 进行可视化,Grafana 提供了丰富的仪表板模板,用户可以非常方便地展示 Prometheus 采集的数据

Prometheus架构和工作流程

Prometheus架构

核心组件

1、Prometheus Server:Prometheus 生态最重要的组件,主要用于抓取和存储时间序列数据,同时提供数据的查询和告警策略的配置管理

2、Exporters:主要用来采集监控数据,比如主机的监控数据可以通过 node_exporter采集,MySQL 的监控数据可以通过 mysql_exporter 采集,之后 Exporter 暴露一个接口,比如/metrics,Prometheus 可以通过该接口采集到数据,常见的Exporter有:Node Exporter(监控主机(如 CPU、内存、磁盘、网络等)级别的指标)、Kube-State-Metrics(提供 Kubernetes 集群和资源(如 Pod、节点、部署等)的状态指标)、Blackbox Exporter(用于检查 HTTP、HTTPS、DNS 等服务的可用性)

3、Alertmanager: Alertmanager 用于接收来自 Prometheus 的报警,并根据报警规则执行相应的动作(如发送邮件、Slack 通知、Webhook 等)。它负责报警的抑制、分组和路由

4、Service Discovery: Prometheus 可以通过 服务发现机制 自动发现需要监控的目标,这对于动态变化的环境(如 Kubernetes、Docker 容器、云环境等)尤其重要

5、Push Gateway:Prometheus 本身是通过 Pull 的方式拉取数据,但是有些监控数据可能是短期的,如果没有采集数据可能会出现丢失。Push Gateway 可以用来解决此类问题,它可以用来接收数据,也就是客户端可以通过 Push 的方式将数据推送到 Push Gateway,之后 Prometheus 可以通过 Pull 拉取该数据

6、PromQL:PromQL 其实不算 Prometheus 的组件,它是用来查询数据的一种语法,比如查询数据库的数据,可以通过 SQL 语句,查询 Loki 的数据,可以通过 LogQL,查询 Prometheus 数据的叫做 PromQL

7、Grafana: Grafana 是一个开源的数据可视化工具,通常与 Prometheus 配合使用,用于展示Prometheus 收集的时间序列数据,提供丰富的图表和仪表盘

Prometheus工作流程

1、数据收集: Prometheus 使用 HTTP 轮询方式从目标(如 Kubernetes Pod、节点、应用程序)拉取监控指标。被监控的服务通常会暴露一个 /metrics 的 HTTP 接口,Prometheus 会定期访问这些接口以收集数据

2、存储: Prometheus 将收集到的指标数据存储在本地时序数据库中,并根据时间戳索引这些数据。每个指标数据都以时间序列的方式保存,这些时间序列数据由标签(如 pod、service、namespace)等维度进行区分

3、查询: Prometheus 提供 PromQL 查询语言,允许用户对存储的时间序列数据进行灵活查询。用户可以通过 PromQL 查询出如 CPU 使用率、内存占用等指标,并进行聚合分析、计算等操作

4、报警: 基于 PromQL 表达式,用户可以设置报警规则(如 CPU 使用率超过 80%)。当某个指标触发报警条件时,Prometheus 会将报警通知发送给 Alertmanager

5、可视化: 可视化方面,Prometheus 本身提供了一些基本的图表功能,但通常与 Grafana 配合使用,Grafana 提供了更强大、更友好的数据可视化功能,支持通过 Prometheus 数据源绘制各种图表、仪表板、报告等

Prometheus的安装

Prometheus的安装有多种方式,包括二进制安装、容器安装、Helm、Prometheus Operator和Kube-Prometheus Stack。本文档采用Kube-Prometheus Stack的方式进行安装

访问kube-prometheus的项目地址,查看K8S集群和当前技术栈的匹配信息,作者的K8S集群版本为1.30.x

https://github.com/prometheus-operator/kube-prometheus/

compatibility

拉取对应版本的git包(注意:当前的网络问题和后面的镜像拉取问题,请参考作者的日志收集章节或云原生存储章节配置代理)

[root@master-01 ~]# git clone -b release-0.14 https://github.com/prometheus-operator/kube-prometheus.git
Cloning into 'kube-prometheus'...
remote: Enumerating objects: 20499, done.
remote: Counting objects: 100% (3921/3921), done.
remote: Compressing objects: 100% (285/285), done.
remote: Total 20499 (delta 3738), reused 3714 (delta 3617), pack-reused 16578 (from 1)
Receiving objects: 100% (20499/20499), 12.43 MiB | 1.20 MiB/s, done.
Resolving deltas: 100% (14112/14112), done.

切换到manifests目录下,包含了创建Prometheus技术栈包含的所有资源,setup目录下包含了Prometheus的CRD定义。首先需要创建setup目录下的资源,这些 CRD 使 Kubernetes 可以处理不同的监控和告警资源

[root@master-01 manifests]# kubectl create -f setup/
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com created
namespace/monitoring created

读者也可以用此方法进行创建(创建命名空间和 CRD,然后等待它们可用,然后再创建剩余资源 )

[root@master-01 manifests]# kubectl wait \
> --for condition=Established \
> --all CustomResourceDefinition \
> --namespace=monitoring
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/bgpfilters.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org condition met
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/redisclusters.cache.tongdun.net condition met
customresourcedefinition.apiextensions.k8s.io/redisstandbies.cache.tongdun.net condition met
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com condition met
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com condition met

等待资源声明完成,随后创建manifests目录中的其余资源(此处会创建非常多的资源,并且新版本的Prometheus-operator会在此处生成,旧版本在上一步会生成),读者可以在创建前配置持久化存储、修改SVC类型或者修改对应Pod资源的Replcation数量

[root@master-01 kube-prometheus]# kubectl apply -f manifests/
alertmanager.monitoring.coreos.com/main created
networkpolicy.networking.k8s.io/alertmanager-main created
poddisruptionbudget.policy/alertmanager-main created
prometheusrule.monitoring.coreos.com/alertmanager-main-rules created
secret/alertmanager-main created
service/alertmanager-main created
serviceaccount/alertmanager-main created
servicemonitor.monitoring.coreos.com/alertmanager-main created
clusterrole.rbac.authorization.k8s.io/blackbox-exporter created
clusterrolebinding.rbac.authorization.k8s.io/blackbox-exporter created
configmap/blackbox-exporter-configuration created
deployment.apps/blackbox-exporter created
networkpolicy.networking.k8s.io/blackbox-exporter created
service/blackbox-exporter created
serviceaccount/blackbox-exporter created
servicemonitor.monitoring.coreos.com/blackbox-exporter created
secret/grafana-config created
secret/grafana-datasources created
configmap/grafana-dashboard-alertmanager-overview created
configmap/grafana-dashboard-apiserver created
configmap/grafana-dashboard-cluster-total created
configmap/grafana-dashboard-controller-manager created
configmap/grafana-dashboard-grafana-overview created
configmap/grafana-dashboard-k8s-resources-cluster created
configmap/grafana-dashboard-k8s-resources-multicluster created
configmap/grafana-dashboard-k8s-resources-namespace created
configmap/grafana-dashboard-k8s-resources-node created
configmap/grafana-dashboard-k8s-resources-pod created
configmap/grafana-dashboard-k8s-resources-workload created
configmap/grafana-dashboard-k8s-resources-workloads-namespace created
configmap/grafana-dashboard-kubelet created
configmap/grafana-dashboard-namespace-by-pod created
configmap/grafana-dashboard-namespace-by-workload created
configmap/grafana-dashboard-node-cluster-rsrc-use created
configmap/grafana-dashboard-node-rsrc-use created
configmap/grafana-dashboard-nodes-darwin created
configmap/grafana-dashboard-nodes created
configmap/grafana-dashboard-persistentvolumesusage created
configmap/grafana-dashboard-pod-total created
configmap/grafana-dashboard-prometheus-remote-write created
configmap/grafana-dashboard-prometheus created
configmap/grafana-dashboard-proxy created
configmap/grafana-dashboard-scheduler created
configmap/grafana-dashboard-workload-total created
configmap/grafana-dashboards created
deployment.apps/grafana created
networkpolicy.networking.k8s.io/grafana created
prometheusrule.monitoring.coreos.com/grafana-rules created
service/grafana created
serviceaccount/grafana created
servicemonitor.monitoring.coreos.com/grafana created
prometheusrule.monitoring.coreos.com/kube-prometheus-rules created
clusterrole.rbac.authorization.k8s.io/kube-state-metrics created
clusterrolebinding.rbac.authorization.k8s.io/kube-state-metrics created
deployment.apps/kube-state-metrics created
networkpolicy.networking.k8s.io/kube-state-metrics created
prometheusrule.monitoring.coreos.com/kube-state-metrics-rules created
service/kube-state-metrics created
serviceaccount/kube-state-metrics created
servicemonitor.monitoring.coreos.com/kube-state-metrics created
prometheusrule.monitoring.coreos.com/kubernetes-monitoring-rules created
servicemonitor.monitoring.coreos.com/kube-apiserver created
servicemonitor.monitoring.coreos.com/coredns created
servicemonitor.monitoring.coreos.com/kube-controller-manager created
servicemonitor.monitoring.coreos.com/kube-scheduler created
servicemonitor.monitoring.coreos.com/kubelet created
clusterrole.rbac.authorization.k8s.io/node-exporter created
clusterrolebinding.rbac.authorization.k8s.io/node-exporter created
daemonset.apps/node-exporter created
networkpolicy.networking.k8s.io/node-exporter created
prometheusrule.monitoring.coreos.com/node-exporter-rules created
service/node-exporter created
serviceaccount/node-exporter created
servicemonitor.monitoring.coreos.com/node-exporter created
clusterrole.rbac.authorization.k8s.io/prometheus-k8s created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-k8s created
networkpolicy.networking.k8s.io/prometheus-k8s created
poddisruptionbudget.policy/prometheus-k8s created
prometheus.monitoring.coreos.com/k8s created
prometheusrule.monitoring.coreos.com/prometheus-k8s-prometheus-rules created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s-config created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s-config created
role.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s created
service/prometheus-k8s created
serviceaccount/prometheus-k8s created
servicemonitor.monitoring.coreos.com/prometheus-k8s created
Warning: resource apiservices/v1beta1.metrics.k8s.io is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resouces created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io configured
clusterrole.rbac.authorization.k8s.io/prometheus-adapter created
Warning: resource clusterroles/system:aggregated-metrics-reader is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be usd on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader configured
clusterrolebinding.rbac.authorization.k8s.io/prometheus-adapter created
clusterrolebinding.rbac.authorization.k8s.io/resource-metrics:system:auth-delegator created
clusterrole.rbac.authorization.k8s.io/resource-metrics-server-resources created
configmap/adapter-config created
deployment.apps/prometheus-adapter created
networkpolicy.networking.k8s.io/prometheus-adapter created
poddisruptionbudget.policy/prometheus-adapter created
rolebinding.rbac.authorization.k8s.io/resource-metrics-auth-reader created
service/prometheus-adapter created
serviceaccount/prometheus-adapter created
servicemonitor.monitoring.coreos.com/prometheus-adapter created
clusterrole.rbac.authorization.k8s.io/prometheus-operator created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-operator created
deployment.apps/prometheus-operator created
networkpolicy.networking.k8s.io/prometheus-operator created
prometheusrule.monitoring.coreos.com/prometheus-operator-rules created
service/prometheus-operator created
serviceaccount/prometheus-operator created
servicemonitor.monitoring.coreos.com/prometheus-operator created

查看容器状态,需要确保容器都处于正常运行状态

[root@master-01 manifests]# kubectl get pods -n monitoring
NAME                                   READY   STATUS    RESTARTS   AGE
alertmanager-main-0                    2/2     Running   0          14h
alertmanager-main-1                    2/2     Running   0          14h
alertmanager-main-2                    2/2     Running   0          14h
blackbox-exporter-74465f5fcb-z7q8z     3/3     Running   0          14h
grafana-b4bcd98cc-t6vnm                1/1     Running   0          14h
kube-state-metrics-59dcf5dbb-645v6     3/3     Running   0          14h
node-exporter-4vsd9                    2/2     Running   0          14h
node-exporter-cfng2                    2/2     Running   0          14h
node-exporter-m2lp5                    2/2     Running   0          14h
node-exporter-pd4v9                    2/2     Running   0          14h
node-exporter-x9sqm                    2/2     Running   0          14h
prometheus-adapter-5794d7d9f5-bdrh9    1/1     Running   0          14h
prometheus-adapter-5794d7d9f5-tkwz2    1/1     Running   0          14h
prometheus-k8s-0                       2/2     Running   0          14h
prometheus-k8s-1                       2/2     Running   0          14h
prometheus-operator-6f948f56f8-tft4h   2/2     Running   0          14h

修改Gafana的SVC类型为NodePort

[root@master-01 manifests]# kubectl edit -n monitoring service grafana
service/grafana edited
[root@master-01 manifests]# kubectl get svc -n monitoring
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
alertmanager-main       ClusterIP   10.96.85.152    <none>        9093/TCP,8080/TCP            14h
alertmanager-operated   ClusterIP   None            <none>        9093/TCP,9094/TCP,9094/UDP   14h
blackbox-exporter       ClusterIP   10.96.200.93    <none>        9115/TCP,19115/TCP           14h
grafana                 NodePort    10.96.214.185   <none>        3000:30584/TCP               14h
kube-state-metrics      ClusterIP   None            <none>        8443/TCP,9443/TCP            14h
node-exporter           ClusterIP   None            <none>        9100/TCP                     14h
prometheus-adapter      ClusterIP   10.96.28.210    <none>        443/TCP                      14h
prometheus-k8s          ClusterIP   10.96.204.197   <none>        9090/TCP,8080/TCP            14h
prometheus-operated     ClusterIP   None            <none>        9090/TCP                     14h
prometheus-operator     ClusterIP   None            <none>        8443/TCP                     14h

Grafana 默认登录的账号密码为 admin/admin。然后相同的方式更改 Prometheus 的 Service 为NodePort

[root@master-01 manifests]# kubectl edit -n monitoring service prometheus-k8s
service/prometheus-k8s edited
[root@master-01 manifests]# kubectl get svc -n monitoring
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
alertmanager-main       ClusterIP   10.96.85.152    <none>        9093/TCP,8080/TCP               14h
alertmanager-operated   ClusterIP   None            <none>        9093/TCP,9094/TCP,9094/UDP      14h
blackbox-exporter       ClusterIP   10.96.200.93    <none>        9115/TCP,19115/TCP              14h
grafana                 NodePort    10.96.214.185   <none>        3000:30584/TCP                  14h
kube-state-metrics      ClusterIP   None            <none>        8443/TCP,9443/TCP               14h
node-exporter           ClusterIP   None            <none>        9100/TCP                        14h
prometheus-adapter      ClusterIP   10.96.28.210    <none>        443/TCP                         14h
prometheus-k8s          NodePort    10.96.204.197   <none>        9090:32675/TCP,8080:32446/TCP   14h
prometheus-operated     ClusterIP   None            <none>        9090/TCP                        14h
prometheus-operator     ClusterIP   None            <none>        8443/TCP                        14h

通过浏览器访问,访问格式IP+NP端口(注意:由于官方为了安全性考虑,为Pod配置了NetworkPolicy,所以直接访问是不行的,需要将之前的网络策略删除)

[root@master-01 manifests]# kubectl delete networkpolicy --all -n monitoring
networkpolicy.networking.k8s.io "alertmanager-main" deleted
networkpolicy.networking.k8s.io "blackbox-exporter" deleted
networkpolicy.networking.k8s.io "grafana" deleted
networkpolicy.networking.k8s.io "kube-state-metrics" deleted
networkpolicy.networking.k8s.io "node-exporter" deleted
networkpolicy.networking.k8s.io "prometheus-adapter" deleted
networkpolicy.networking.k8s.io "prometheus-k8s" deleted
networkpolicy.networking.k8s.io "prometheus-operator" deleted
[root@master-01 manifests]# telnet 192.168.132.236 30277
Trying 192.168.132.236...
Connected to 192.168.132.236.
Escape character is '^]'.

Grafana访问界面,登录后提示需要修改密码。登录到主界面后,依次单击Home→Explore→Metrics按钮,即可观察集群的资源图表

grafana

main界面

Prometheus的UI也是同样的访问方法(http://192.168.132.236:32675/)。注意:刚开始的时候会出现告警,此时可以忽略

Prometheus监控数据来源

非云原生的监控一般采用exporter进行监控,而云原生的应用的一般通过服务自身暴露的/metrics接口让Prometheus进行pull采集监控信息

比如,node-exporter监听的9100端口,其实就是监控采集的数据来源

[root@master-01 manifests]# ps -aux | grep node_exporter
nfsnobo+  16629  0.8  0.3 1242204 18672 ?       Ssl  Nov24  13:14 /bin/node_exporter --web.listen-address=127.0.0.1:9100 --path.sysfs=/host/sys --path.rootfs=/host/root --path.udev.data=/host/root/run/udev/data --no-collector.wifi --no-collector.hwmon --no-collector.btrfs --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|run/k3s/containerd/.+|var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/) --collector.netclass.ignored-devices=^(veth.*|[a-f0-9]{15})$ --collector.netdev.device-exclude=^(veth.*|[a-f0-9]{15})$
root      95083  0.0  0.0 112828  2304 pts/0    S+   23:24   0:00 grep --color=auto node_exporter
[root@master-01 manifests]# ss -lntp | grep 9100
LISTEN     0      16384  192.168.132.169:9100                     *:*                   users:(("kube-rbac-proxy",pid=17188,fd=3))
LISTEN     0      16384  127.0.0.1:9100                     *:*                   users:(("node_exporter",pid=16629,fd=3))
[root@master-01 manifests]# curl 127.0.0.1:9100/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 3.0034e-05
go_gc_duration_seconds{quantile="0.25"} 4.7561e-05
go_gc_duration_seconds{quantile="0.5"} 5.7244e-05
go_gc_duration_seconds{quantile="0.75"} 6.7569e-05
go_gc_duration_seconds{quantile="1"} 0.078837684
go_gc_duration_seconds_sum 4.79348581
go_gc_duration_seconds_count 28174
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 8

Grafana导入数据来源和下载模版,即可对这些数据进行可视化的展示

grafana数据展示

常用的exporter工具如下

类型 Exporter
数据库 MySQL Exporter, Redis Exporter, MongoDB Exporter, MSSQL Exporter
硬件 Apcupsd Exporter,IoT Edison Exporter, IPMI Exporter, Node Exporter
消息队列 Beanstalkd Exporter, Kafka Exporter, NSQ Exporter, RabbitMQ Exporter
存储 Ceph Exporter, Gluster Exporter, HDFS Exporter, ScaleIO Exporter
HTTP 服务 Apache Exporter, HAProxy Exporter, Nginx Exporter
API 服务 AWS ECS Exporter, Docker Cloud Exporter, Docker Hub Exporter, GitHub Exporter
日志 Fluentd Exporter, Grok Exporter
监控系统 Collectd Exporter, Graphite Exporter, InfluxDB Exporter, Nagios Exporter, SNMP Exporter
其它 Blackbox Exporter, JIRA Exporter, Jenkins Exporter, Confluence Exporter
云原生ETCD监控

ServiceMonitor 是 Prometheus Operator 提供的一个 Custom Resource (CR),它用于定义 Prometheus 如何抓取 Kubernetes 服务(Service)暴露的监控数据。ServiceMonitor 的主要作用是通过 Kubernetes 服务(Service)发现并抓取暴露的指标

ServiceMonitor 通过定义 spec.selector 和 spec.endpoints 来指定要抓取的目标服务(Service)和暴露的端口。ServiceMonitor 还支持其他配置,如 interval(抓取频率)、path(指标端点路径)、scheme(抓取协议)等。ServiceMonitor 配置完成后,Prometheus Operator 会定期查询 Kubernetes API,根据 ServiceMonitor 定义的规则来自动发现和抓取对应服务的指标。

测试访问Etcd Metrics接口

[root@master-01 etcd]# curl -s --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key https://192.168.132.169:2379/metrics -k | tail -10
# TYPE process_virtual_memory_max_bytes gauge
process_virtual_memory_max_bytes 1.8446744073709552e+19
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 2
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

创建Etcd的Service以及Endpoint

[root@master-01 ~]# vim etcd-svc.yaml
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    app: etcd-prom
  name: etcd-prom
  namespace: kube-system
subsets:
- addresses:
  - ip: 192.168.132.169
  - ip: 192.168.132.170
  - ip: 192.168.132.171
  ports:
  - name: https-metrics
    port: 2379 # etcd 端口
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: etcd-prom
  name: etcd-prom
  namespace: kube-system
spec:
  ports:
  - name: https-metrics
    port: 2379
    protocol: TCP
    targetPort: 2379
  type: ClusterIP

创建资源并查看对应的ClusterIP(注意:该SVC是创建在kube-system命名空间下的,其次如果读者有配置代理的话,请将对应的ClusterIP放行,否则monitor无法采集数据)

[root@master-01 ~]# kubectl create -f etcd-svc.yaml
endpoints/etcd-prom created
service/etcd-prom created
[root@master-01 manifests]# kubectl get svc -n kube-system
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                        AGE
etcd-prom        ClusterIP   10.96.116.30   <none>        2379/TCP                       5m48s
[root@master-01 manifests]# kubectl get endpoints -n kube-system
NAME             ENDPOINTS                                                                        AGE
etcd-prom        192.168.132.169:2379,192.168.132.170:2379,192.168.132.171:2379                   6m2s

对SVC的ClusterIP进行访问测试(注意:只有该步骤成功才能继续往下操作,否则是获取不到数据的)

[root@master-01 ~]# curl -s --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key https://10.96.116.30:2379/metrics -k | tail -2
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

创建Etcd的Secret(注意:证书路径需要根据实际路径填写)

[root@master-01 ~]# kubectl create secret generic etcd-ssl --from-file=/etc/kubernetes/pki/etcd/ca.crt --from-file=/etc/kubernetes/pki/etcd/server.crt --from-file=/etc/kubernetes/pki/etcd/server.key -n monitoring
secret/etcd-ssl created

将Secret挂载到Prometheus容器上

[root@master-01 ~]# kubectl edit prometheus -n monitoring k8s
spec: 
...省略部分输出...
  secrets:
  - etcd-ssl
...省略部分输出...
prometheus.monitoring.coreos.com/k8s edited

挂载完成后,可以观察到prometheus容器开始重启

[root@master-01 ~]# kubectl get pods -n monitoring
NAME                                   READY   STATUS     RESTARTS   AGE
alertmanager-main-0                    2/2     Running    0          38h
alertmanager-main-1                    2/2     Running    0          38h
alertmanager-main-2                    2/2     Running    0          38h
blackbox-exporter-74465f5fcb-z7q8z     3/3     Running    0          38h
grafana-b4bcd98cc-t6vnm                1/1     Running    0          38h
kube-state-metrics-59dcf5dbb-645v6     3/3     Running    0          38h
node-exporter-4vsd9                    2/2     Running    0          38h
node-exporter-cfng2                    2/2     Running    0          38h
node-exporter-m2lp5                    2/2     Running    0          38h
node-exporter-pd4v9                    2/2     Running    0          38h
node-exporter-x9sqm                    2/2     Running    0          38h
prometheus-adapter-5794d7d9f5-bdrh9    1/1     Running    0          38h
prometheus-adapter-5794d7d9f5-tkwz2    1/1     Running    0          38h
prometheus-k8s-0                       2/2     Running    0          38h
prometheus-k8s-1                       0/2     Init:0/1   0          103s
prometheus-operator-6f948f56f8-tft4h   2/2     Running    0          38h

查看证书是否挂载到容器内部

[root@master-01 ~]# kubectl exec -n monitoring prometheus-k8s-0 -c prometheus -- ls /etc/prometheus/secrets/etcd-ssl/
ca.crt
server.crt
server.key

创建 Etcd 的 ServiceMonitor

[root@master-01 ~]# cat servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: etcd
  namespace: monitoring
  labels:
    app: etcd
spec:
  jobLabel: k8s-app
  endpoints:
  - interval: 30s  # 采集频率
    port: https-metrics  # 这个 port 对应 Service.spec.ports.name
    scheme: https  # 采集协议
    tlsConfig:
      caFile: /etc/prometheus/secrets/etcd-ssl/ca.crt  # CA 证书路径
      certFile: /etc/prometheus/secrets/etcd-ssl/server.crt   # 客户端证书路径
      keyFile: /etc/prometheus/secrets/etcd-ssl/server.key  # 客户端证书私钥路径
      insecureSkipVerify: true  # 关闭证书校验
  selector:
    matchLabels:
      app: etcd-prom  # 与 Service 的标签匹配
  namespaceSelector:
    matchNames:
    - kube-system  # 在 kube-system 命名空间中寻找 Service

创建资源并查看资源状态

[root@master-01 ~]# kubectl create -f servicemonitor.yaml
servicemonitor.monitoring.coreos.com/etcd created
[root@master-01 ~]# kubectl get servicemonitors.monitoring.coreos.com -n monitoring etcd
NAME   AGE
etcd   5m1s

登录Grafana的UI界面,依次单击Dashboards→New→New dashboard→Import dashboard,在出现的Import dashboard界面填写心仪的dashboard界面即可。下面附带官网提供的dashboard模板链接

https://grafana.com/grafana/dashboards/

import dashboard

添加dashboard的名称和添加prometheus数据源后,单击import按钮,等待一段时间即可查看Etcd监控数据

import dashboard-2

监控数据

非云原生监控 Exporter

使用 MySQL 作为测试用例,演示如何使用 Exporter 监控非云原生应用

部署Mysql服务,为Mysql设置密码,并暴露3306端口

[root@master-01 ~]# kubectl create deploy mysql --image=registry.cn-beijing.aliyuncs.com/dotbalo/mysql:5.7.23
deployment.apps/mysql created
[root@master-01 ~]# kubectl set env deploy/mysql MYSQL_ROOT_PASSWORD=mysql
deployment.apps/mysql env updated
[root@master-01 ~]# kubectl expose deploy mysql --port 3306
service/mysql exposed

检查容器和Service服务是否正常

[root@master-01 ~]# kubectl get po -l app=mysql
NAME                     READY   STATUS    RESTARTS   AGE
mysql-7d6ff9c689-m5smn   1/1     Running   0          32s
[root@master-01 ~]# kubectl get svc -l app=mysql
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
mysql   ClusterIP   10.96.175.244   <none>        3306/TCP   22s

登录Mysql,创建 Exporter 所需的用户和权限

[root@master-01 ~]# kubectl exec -it mysql-7d6ff9c689-m5smn -- bash
root@mysql-7d6ff9c689-m5smn:/# mysql -uroot -pmysql
mysql: [Warning] Using a password on the command line interface can be insecure                                                                                                                               .
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.23 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create user 'exporter'@'%' identified by 'exporter' with MAX_USER_CONNECTIONS 3;
Query OK, 0 rows affected (0.02 sec)
mysql> grant process,replication client,select on *.* to 'exporter'@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye
root@mysql-7d6ff9c689-m5smn:/# exit
exit

配置 MySQL Exporter 采集 MySQL 监控数据(注意 DATA_SOURCE_NAME 的配置,需要将 exporter:exporter@(mysql.default:3306)改成 自 己 的 实 际 配 置 , 格 式 如 下 USERNAME:PASSWORD@MYSQL_HOST_ADDRESS:MYSQL_PORT)

[root@master-01 ~]# vim mysql-exporter
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-exporter
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: mysql-exporter
  template:
    metadata:
      labels:
        k8s-app: mysql-exporter
    spec:
      containers:
        - name: mysql-exporter
          image: registry.cn-beijing.aliyuncs.com/dotbalo/mysqld-exporter
          env:
            - name: DATA_SOURCE_NAME
              value: "exporter:exporter@(mysql.default:3306)/"
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9104
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-exporter
  namespace: monitoring
  labels:
    k8s-app: mysql-exporter
spec:
  type: ClusterIP
  selector:
    k8s-app: mysql-exporter
  ports:
    - name: api
      port: 9104
      protocol: TCP
[root@master-01 ~]# kubectl create -f mysql-exporter
deployment.apps/mysql-exporter created
service/mysql-exporter created
[root@master-01 ~]# kubectl get -f mysql-exporter
NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-exporter   1/1     1            1           21h

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/mysql-exporter   ClusterIP   10.96.191.150   <none>        9104/TCP   21h

对暴露的SVC端口进行访问测试(读者也可以直接使用curl serviceIP+Port进行访问)

[root@master-01 ~]# kubectl port-forward -n monitoring svc/mysql-exporter 9104:                                                                                                                               9104
Forwarding from 127.0.0.1:9104 -> 9104
Forwarding from [::1]:9104 -> 9104
Handling connection for 9104

打开新的终端窗口,访问127.0.0.1:9104/metrics(上面的命令就是将本地9104端口与容器的9104端口进行映射)

[root@master-01 ~]# curl http://127.0.0.1:9104/metrics | tail -4
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collec                                                                                                                               tion cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0

配置mysql ServiceMonitor,并创建资源

[root@master-01 ~]# vim mysqlmonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: mysql-exporter
  namespace: monitoring
  labels:
    k8s-app: mysql-exporter
spec:
  jobLabel: k8s-app
  endpoints:
    - port: api
      interval: 30s
      scheme: http
  selector:
    matchLabels:
      k8s-app: mysql-exporter
  namespaceSelector:
    matchNames:
      - monitoring

等待数据采集完成,通过Prometheus UI界面可以看到mysql-exporter已经上线(依次单击Status→Service Discovery)

serviceMonitor/monitoring/mysql-exporter/0 (1 / 47 active targets)

导入Grafana Dashboard界面,即可将监控数据可视化,下面附带Dashboard链接

https://grafana.com/grafana/dashboards/14057-mysql/

mysql数据展示

Prometheus无法监控kube-controller-manager和kube-scheduler

表现:Prometheus界面无法观察到数据,并且两个组件都处于Firing状态

两个组件告警

原因:两个组件都只监听127.0.0.1,Prometheus的ServiceMonitor没有找到组件对应的Service

解决方法如下:

所有master节点修改kube-controller-manager配置文件,将监听地址修改为0.0.0.0(注意:Kubeadm安装和二进制安装的路径可能不一致,请读者按照实际情况进行修改)

[root@master-01 ~]# vim /etc/kubernetes/manifests/kube-controller-manager.yaml
...省略部分输出...
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --bind-address=0.0.0.0
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --cluster-cidr=172.16.0.0/16
    - --cluster-name=kubernetes
...省略部分输出...

在/etc/kubernetes/manifests/目录下的文件为集群的静态容器配置,配置完成后不需要手动重启容器,集群会自动读取配置文件进行重启容器

[root@master-01 kubernetes]# kubectl get pods -n kube-system
NAME                                      READY   STATUS    RESTARTS        AGE
...省略部分输出...
kube-apiserver-master-03                  1/1     Running   21 (2d3h ago)   28d
kube-controller-manager-master-01         1/1     Running   0               5h23m
kube-controller-manager-master-02         1/1     Running   0               42s
kube-controller-manager-master-03         0/1     Pending   0               1s
kube-proxy-84trv                          1/1     Running   6 (2d3h ago)    28d
...省略部分输出...

修改完成后,查看ServiceMonitor配置,可以观察到kube-controller-manager组件对应匹配的命名空间为kube-system,对应匹配的标签为app.kubernetes.io/name: kube-controller-manager,对应的service端口为https-metrics

[root@master-01 ~]# kubectl get servicemonitors.monitoring.coreos.com -n monitoring | egrep 'kube-controller-manager|kube-scheduler'
kube-controller-manager   2d19h
kube-scheduler            2d19h
[root@master-01 ~]# kubectl get servicemonitors.monitoring.coreos.com -n monitoring kube-controller-manager -oyaml | tail -20
      insecureSkipVerify: true
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
    interval: 5s
    metricRelabelings:
    - action: drop
      regex: process_start_time_seconds
      sourceLabels:
      - __name__
    path: /metrics/slis
    port: https-metrics
    scheme: https
    tlsConfig:
      insecureSkipVerify: true
  jobLabel: app.kubernetes.io/name
  namespaceSelector:
    matchNames:
    - kube-system
  selector:
    matchLabels:
      app.kubernetes.io/name: kube-controller-manager

检查kube-system命名空间下并没有对应的Service

[root@master-01 ~]# kubectl get service -n kube-system -l app.kubernetes.io/name=kube-controller-manager
No resources found in kube-system namespace.

创建kube-controller-manager对应的service,新版本对应监听的端口为10257(注意:labels和ports名称要与servicemonitor相匹配)

[root@master-01 ~]# vim controller-svc.yaml
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    app.kubernetes.io/name: kube-controller-manager
  name: kube-controller-manager-prom
  namespace: kube-system
subsets:
  - addresses:
      - ip: 192.168.132.169
      - ip: 192.168.132.170
      - ip: 192.168.132.171
    ports:
      - name: https-metrics
        port: 10257
        protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: kube-controller-manager
  name: kube-controller-manager-prom
  namespace: kube-system
spec:
  ports:
    - name: https-metrics
      port: 10257
      protocol: TCP
      targetPort: 10257
  sessionAffinity: None
  type: ClusterIP
[root@master-01 ~]# kubectl create -f controller-svc.yaml
endpoints/kube-controller-manager-prom created
service/kube-controller-manager-prom created
[root@master-01 ~]# kubectl get service -n kube-system -l app.kubernetes.io/name=kube-controller-manager
NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
kube-controller-manager-prom   ClusterIP   10.96.22.199   <none>        10257/TCP   5s

注意!!旧版本的kube-controller-manager为HTTP协议,可以直接进行测试,但是新版本换成了HTTPS协议,直接访问测试会提示没有权限或者返回空。解决方案参见以下链接:重新编写一个clusterrole,权限是对metrics接口有get权限,创建clusterrolebinding,绑定到某个serviceaccount上,然后通过对应的Token构造HTTPS头部进行访问

https://zhuanlan.zhihu.com/p/601741895

完成上述操作后,Prometheus上关于controller-manager的告警会消失,并且在Service Discovery界面会出现关于controller-manager的监控项

serviceMonitor/monitoring/kube-controller-manager/0 (3 / 28 active targets)
serviceMonitor/monitoring/kube-controller-manager/1 (3 / 28 active targets)

恢复kube-scheduler组件告警的方法跟controller-manager相似,master节点修改/etc/kubernetes/manifests/kube-scheduler.yaml文件的监听端口为0.0.0.0

[root@master-01 ~]# vim /etc/kubernetes/manifests/kube-scheduler.yaml
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=0.0.0.0
    - --kubeconfig=/etc/kubernetes/scheduler.conf
...省略部分输出...

静态容器自动重启

[root@master-01 ~]# kubectl get pods -n kube-system
NAME                                      READY   STATUS    RESTARTS         AGE
kube-proxy-rjf4q                          1/1     Running   6 (2d19h ago)    29d
kube-scheduler-master-01                  1/1     Running   0                18s
kube-scheduler-master-02                  1/1     Running   0                21s
kube-scheduler-master-03                  1/1     Running   0                22s

查看kube-scheduler的servicemonitor,检查是否有对应的Service,若无则创建(kube-scheduler监听的端口为10259)

[root@master-01 ~]# ss -lntp | grep kube-scheduler
LISTEN     0      16384     [::]:10259                 [::]:*                   users:(("kube-scheduler",pid=67358,fd=3))
[root@master-01 ~]# kubectl get servicemonitors.monitoring.coreos.com -n monitoring kube-scheduler -oyaml  | tail -12
    path: /metrics/slis
    port: https-metrics
    scheme: https
    tlsConfig:
      insecureSkipVerify: true
  jobLabel: app.kubernetes.io/name
  namespaceSelector:
    matchNames:
    - kube-system
  selector:
    matchLabels:
      app.kubernetes.io/name: kube-scheduler
[root@master-01 ~]# vim scheduler-svc.yaml
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    app.kubernetes.io/name: kube-scheduler
  name: kube-scheduler-prom
  namespace: kube-system
subsets:
  - addresses:
      - ip: 192.168.132.169
      - ip: 192.168.132.170
      - ip: 192.168.132.171
    ports:
      - name: https-metrics
        port: 10259
        protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: kube-scheduler
  name: kube-scheduler-prom
  namespace: kube-system
spec:
  ports:
    - name: https-metrics
      port: 10259
      protocol: TCP
      targetPort: 10259
  sessionAffinity: None
  type: ClusterIP

创建完成后,Prometheus上的告警消失

[root@master-01 ~]# kubectl create -f scheduler.yaml
endpoints/kube-scheduler-prom created
service/kube-scheduler-prom created
[root@master-01 ~]# kubectl get svc -n kube-system -l app.kubernetes.io/name=kube-scheduler
NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
kube-scheduler-prom   ClusterIP   10.96.87.125   <none>        10259/TCP   26s
serviceMonitor/monitoring/kube-scheduler/0 (3 / 31 active targets)
serviceMonitor/monitoring/kube-scheduler/1 (3 / 31 active targets)

通过 Service Monitor 监控应用时,如果监控没有找到目标主机的排查步骤时,排查步骤大致如下:

1、 确认 Service Monitor 是否成功创建

2、确认 Prometheus 是否生成了相关配置

3、确认存在 Service Monitor 匹配的 Service

4、确认通过 Service 能够访问程序的 Metrics 接口

5、确认 Service 的端口和 Scheme 和 Service Monitor 一致

黑盒监控

Prometheus 黑盒监控(Blackbox Exporter)是 Prometheus 生态中一个非常重要的组件,通常用于监控无法直接暴露指标的外部服务,比如 HTTP、HTTPS、DNS、TCP 等协议的服务。黑盒监控并不依赖于被监控目标本身的指标导出,而是通过主动发起请求、检查服务的可用性来评估目标服务的健康状态

新版 Prometheus Stack 已经默认安装了 BlackboxExporter

[root@master-01 ~]# kubectl get servicemonitors -n monitoring -l app.kubernetes.io/name=blackbox-exporter
NAME                AGE
blackbox-exporter   4d2h

BlackboxExporter同时也会创建一个 Service,可以通过该 Service 访问 Blackbox Exporter 并传递一些参数

[root@master-01 ~]# kubectl get svc -n monitoring -l app.kubernetes.io/name=blackbox-exporter
NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)              AGE
blackbox-exporter   ClusterIP   10.96.200.93   <none>        9115/TCP,19115/TCP   4d2h

检测blog.caijxlinux.work网站的状态(注意:使用任何一个公网域名或者公司内的域名探测都可以,若读者有使用代理,请unset http_proxy变量和https_proxy变量,否则Service无法访问对应的域名)

[root@master-01 ~]# curl -s "http://10.96.200.93:19115/probe?target=blog.caijxlinux.work&module=http_2xx" | tail -1
probe_tls_version_info{version="TLS 1.2"} 1
参数 解析
probe 接口地址
target 检测目标
module 使用对应的模块检测

Prometheus静态配置

考虑到有些读者可能使用传统的安装方法进行安装,如二进制等,需要使用静态文件更新Prometheus配置,所以使用黑盒监控作为例子,演示在集群内部如何使用静态配置添加监控

创建prometheus-additional.yaml文件,将此文件配置为Secret,作为Prometheus的静态配置

[root@master-01 ~]# touch prometheus-additional.yaml
[root@master-01 ~]# kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml -n monitoring
secret/additional-configs created

编辑Prometheus的配置文件,添加以下内容

[root@master-01 ~]# kubectl edit prometheus -n monitoring k8s
...省略部分输出...
spec:
  additionalScrapeConfigs:
    key: prometheus-additional.yaml
    name: additional-configs
    optional: true
...省略部分输出...

添加完成后,写入对应的监控内容到prometheus-additional.yaml文件内

[root@master-01 ~]# vim prometheus-additional.yaml
- job_name: 'blackbox'
  metrics_path: /probe
  params:
    module: [http_2xx] # Look for a HTTP 200 response.
  static_configs:
    - targets:
        - https://blog.caijxlinux.work # Target to probe with http.
        - https://www.baidu.com # Target to probe with https.
  relabel_configs:
    - source_labels: [__address__]
      target_label: __param_target
    - source_labels: [__param_target]
      target_label: instance
    - target_label: __address__
      replacement: blackbox-exporter:19115 # The blackbox exporter's real hostname:port.

热更新Secret

[root@master-01 ~]# kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml --dry-run=client -oyaml | kubectl replace -f - -n monitoring
secret/additional-configs replaced

等待一段时间后,打开Prometheus UI界面,依次单击Status→Targets,即可观察到对应的黑盒监控

caijx_http

监控处于正常状态后,在Grafana UI界面,导入黑盒监控模板,即可将监控结果可视化。在下方附带图表链接

blackboix

https://grafana.com/grafana/dashboards/13659

Prometheus监控Windows主机

下载对应的Exporter到Windows主机内(类似于zabbix-agent),选择安装的版本为windows_exporter-0.30.0-rc.0-amd64.msi

https://github.com/prometheus-community/windows_exporter/releases/tag/v0.30.0-rc.0

在Windows主机安装完成后,可以通过CMD查看暴露的端口为9182

netstat -anio
 TCP    0.0.0.0:9182           0.0.0.0:0              LISTENING       26632

在prometheus-additional.yaml文件内添加配置

- job_name: 'WindowsServerMonitor'
  static_configs:
    - targets:
        - "192.168.132.1:9182"
      labels:
        server_type: 'windows'
  relabel_configs:
    - source_labels: [__address__]
      target_label: instance

热更新Secret

[root@master-01 ~]# kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml --dry-run=client -oyaml | kubectl replace -f - -n monitoring
secret/additional-configs replaced

在Prometheus UI查看到对应的监控数据,导入Grafana模板即可。此处不再赘述

windows

windows grafa

https://grafana.com/grafana/dashboards/12566

Prometheus 语法 PromQL

PromQL是查询 Prometheus 数据的强大工具,可以执行实时分析、计算和监控规则。读者需要掌握该工具,用于查询和计算某些特定的数据,并且PromQL是后续章节用来构造告警规则的基础语句

基本组成部分

1、指标名 (Metric Name):表示某一特定的时间序列数据

up

up #查询 up 指标,通常用于检查目标是否存活

2、标签(Labels):使用 {} 过滤指标,基于键值对

labels

http_requests_total{job="api-server", method="GET"} #查询 http_requests_total 指标中 job="api-server" 且 method="GET" 的数据

3、时间范围 (Range Vector):使用 [时间范围] 表示一段时间的数据

rate(http_requests_total[5m]) #计算过去 5 分钟的每秒请求速率

PromQL也支持如下表达式

!= #不等于;
=~ #表示等于符合正则表达式的指标;
!~ #和=~类似,=~表示正则匹配,!~表示正则不匹配。
up{node!=master-01}

查看Kubernetes集群中每个宿主机的磁盘总量

node_filesystem

node_filesystem_size_bytes

查询自定分区大小

node_filesystem_size_bytes{mountpoint="/"}

查询分区不是/boot,且磁盘是/dev/开头的分区大小

node_filesystem_size_bytes{device=~"/dev/.*", mountpoint!="/boot"}

查询主机 master-01 在最近 5 分钟可用的磁盘空间变化

node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"}[5m]

查询10分钟之前磁盘可用空间,指定offset参数

node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"} offset 10m

查询 10 分钟之前,5 分钟区间的磁盘可用空间的变化

node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"}[5m] offset 10m
PromQL 操作符

将查询到的主机磁盘的空间数据,转换为GB

node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"} / 1024 / 1024 / 1024
node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"} / (1024 ^ 3)

在master-01执行df -Th命令,与上图(主机磁盘空间)和下图(磁盘可用率)结果进行对比

[root@master-01 ~]# df -Th
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  2.4G     0  2.4G   0% /dev
tmpfs                   tmpfs     2.5G     0  2.5G   0% /dev/shm
tmpfs                   tmpfs     2.5G   30M  2.4G   2% /run
tmpfs                   tmpfs     2.5G     0  2.5G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        39G   12G   27G  30% /

查询master-01根分区磁盘可用率

node_filesystem_avail_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"} / node_filesystem_size_bytes{instance="master-01", mountpoint="/",device="/dev/mapper/centos-root"}

查询所有主机根分区可用率

node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}

转化为百分百的形式

(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100

找到集群中根分区空间可用率大于 60%的主机

(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 > 60

PromQL支持语法

参数 含义
== 相等
> 大于
< 小于
>= 大于等于
<= 小于等于
and 并且
or
unless 排除

磁盘可用率大于 30%小于等于 60%的主机

30 < (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 <= 60
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 > 30 and (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 <=60
PromQL 常用函数

使用 sum 函数统计当前监控目标所有主机根分区剩余的空间

sum(node_filesystem_free_bytes{mountpoint="/"}) / 1024^3

根据 statuscode 字段对http_request_total进行统计请求数据

sum(http_request_total) by (statuscode)

根据 statuscode 和 handler 两个指标进一步统计

sum(http_request_total) by (statuscode, handler)

PromQL还支持topk()、bottomk()、min()、max()、avg()、ceil()、floor()、sort()、sort_desc()等其他函数,在此处附带一篇文档,里面有关于PromQL函数的详细解析,有需要的读者可以认真阅读,会受益匪浅。

https://blog.caijxlinux.work/promql-learning.pdf

Alertmanager 告警

Alertmanager 是 Prometheus 的一个组件,用于管理和处理警报。它可以接收来自 Prometheus 的警报并进行聚合、抑制、路由、通知等操作。使用 Alertmanager 可以确保警报被适当地管理,并且通知相关人员或者系统。

1、警报路由:根据警报的标签、级别或其他条件将警报路由到不同的接收器(如 Slack、邮件、Webhooks、OpsGenie、PagerDuty 等)。

2、警报抑制:在一定条件下,Alertmanager 可以抑制重复的警报,避免对同一问题发出多次告警。例如,当已经有一个警报正在处理时,可以抑制相同条件的其他警报。

3、警报聚合:将多个警报聚合成一个警报。例如,多个服务出现类似问题时,可以合并成一个警报,避免产生过多的噪音。

4、通知模板:支持自定义通知内容,通过 Go 模板对告警信息进行格式化。可以将告警内容定制为有用的、易读的格式。

5、持久化和分组:支持按标签对警报进行分组,避免同一个问题触发多个通知,减少通知的数量。

[root@master-01 ~]# vim alertmanager.yaml
# global块配置下的配置选项在本配置文件内的所有配置项下可见
global:
  # 在Alertmanager内管理的每一条告警均有两种状态: "resolved"或者"firing". 在altermanager首次发送告警通知后, 该告警会一直处于firing状态,设置resolve_timeout可以指定处于firing状态的告警间隔多长时间会被设置为resolved状态, 在设置为resolved状态的告警后,altermanager不会再发送firing的告警通知.
  resolve_timeout: 1h

  # 邮件告警配置
  smtp_smarthost: 'smtp.exmail.qq.com:25'
  smtp_from: 'jxcai@xxx.com'
  smtp_auth_username: 'jxcai@xxx.com'
  smtp_auth_password: 'DKxxx'
  # HipChat告警配置
  # hipchat_auth_token: '123456789'
  # hipchat_auth_url: 'https://hipchat.foobar.org/'
  # wechat
  wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
  wechat_api_secret: 'JJ'
  wechat_api_corp_id: 'ww'

  # 告警通知模板
templates:
- '/etc/alertmanager/config/*.tmpl'

# route: 根路由,该模块用于该根路由下的节点及子路由routes的定义. 子树节点如果不对相关配置进行配置,则默认会从父路由树继承该配置选项。每一条告警都要进入route,即要求配置选项group_by的值能够匹配到每一条告警的至少一个la  belkey(即通过POST请求向altermanager服务接口所发送告警的labels项所携带的<labelname>),告警进入到route后,将会根据子路由routes节点中的配置项match_re或者match来确定能进入该子路由节点的告警(由在match_re或者match下配置的labelkey: labelvalue是否为告警labels的子集决定,是的话则会进入该子路由节点,否则不能接收进入该子路由节点).
route:
  # 例如所有labelkey:labelvalue含cluster=A及altertname=LatencyHigh labelkey的告警都会被归入单一组中
  group_by: ['job', 'altername', 'cluster', 'service','severity']
  # 若一组新的告警产生,则会等group_wait后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在group_wait内合并为单一的告警后再发送
  group_wait: 30s
  # 再次告警时间间隔
  group_interval: 5m
  # 如果一条告警通知已成功发送,且在间隔repeat_interval后,该告警仍然未被设置为resolved,则会再次发送该告警通知
  repeat_interval: 12h
  # 默认告警通知接收者,凡未被匹配进入各子路由节点的告警均被发送到此接收者
  receiver: 'wechat'
  # 上述route的配置会被传递给子路由节点,子路由节点进行重新配置才会被覆盖

  # 子路由树
  routes:
  # 该配置选项使用正则表达式来匹配告警的labels,以确定能否进入该子路由树
  # match_re和match均用于匹配labelkey为service,labelvalue分别为指定值的告警,被匹配到的告警会将通知发送到对应的receiver
  - match_re:
      service: ^(foo1|foo2|baz)$
    receiver: 'wechat'
    # 在带有service标签的告警同时有severity标签时,他可以有自己的子路由,同时具有severity != critical的告警则被发送给接收者team-ops-mails,对severity == critical的告警则被发送到对应的接收者即team-ops-pager
    routes:
    - match:
        severity: critical
      receiver: 'wechat'
  # 比如关于数据库服务的告警,如果子路由没有匹配到相应的owner标签,则都默认由team-DB-pager接收
  - match:
      service: database
    receiver: 'team-ops-mails'
  # 我们也可以先根据标签service:database将数据库服务告警过滤出来,然后进一步将所有同时带labelkey为database
  - match:
      severity: critical
    receiver: 'wechat'
# 抑制规则,当出现critical告警时 忽略warning
inhibit_rules:
- source_match:
    severity: 'critical'
  target_match:
    severity: 'warning'
  # Apply inhibition if the alertname is the same.
  #   equal: ['alertname', 'cluster', 'service']
  #
# 收件人配置
receivers:
- name: 'team-ops-mails'
  email_configs:
  - to: 'jxcai@xxx.com'
- name: 'wechat'
  wechat_configs:
  - send_resolved: true
    corp_id: 'ww'
    api_secret: 'JJ'
    to_tag: '1'
    agent_id: '1000002'
    api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
    message: '{{ template "wechat.default.message" . }}'
#- name: 'team-X-pager'
#  email_configs:
#  - to: 'team-X+alerts-critical@example.org'
#  pagerduty_configs:
#  - service_key: <team-X-key>
#
#- name: 'team-Y-mails'
#  email_configs:
#  - to: 'team-Y+alerts@example.org'
#
#- name: 'team-Y-pager'
#  pagerduty_configs:
#  - service_key: <team-Y-key>
#
#- name: 'team-DB-pager'
#  pagerduty_configs:
#  - service_key: <team-DB-key>
#  
#- name: 'team-X-hipchat'
#  hipchat_configs:
#  - auth_token: <auth_token>
#    room_id: 85
#    message_format: html
#    notify: true 

Alertmanager 的配置主要分为五大块:

参数 解析
Global 全局配置,主要用来配置一些通用的配置,比如邮件通知的账号、密码、SMTP服务器、微信告警等。Global 块配置下的配置选项在本配置文件内的所有配置项下可见,但是文件内其它位置的子配置可以覆盖 Global 配置
Templates 用于放置自定义模板的位置
Route 告警路由配置,用于告警信息的分组路由,可以将不同分组的告警发送给不同的收件人。比如将数据库告警发送给 DBA,服务器告警发送给 OPS
Inhibit_rules 告警抑制,主要用于减少告警的次数,防止“告警轰炸”。比如某个宿主机宕机,可能会引起容器重建、漂移、服务不可用等一系列问题,如果每个异常均有告警,会一次性发送很多告警,造成告警轰炸,并且也会干扰定位问题的思路,所以可以使用告警抑制,屏蔽由宿主机宕机引来的其他问题,只发送宿主机宕机的消息即可
Receivers 告警收件人配置,每个 receiver 都有一个名字,经过 route 分组并且路由后需要指定一个 receiver,就是在此位置配置的
Alertmanager 路由规则
route:
  receiver: Default
  group_by:
    - namespace
    - job
    - alertname
  routes:
    - receiver: Watchdog
      match:
        alertname: Watchdog
    - receiver: Critical
      match:
        severity: critical
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 10m
参数 解析
receiver 告警的通知目标,需要和 receivers 配置中 name 进行匹配。需要注意的route.routes 下也可以有 receiver 配置,优先级高于 route.receiver 配置的默认接收人,当告警没有匹配到子路由时,会使用 route.receiver 进行通知,比如上述配置中的Default
group_by 分组配置,值类型为列表。比如配置成['job', 'severity'],代表告警信息包含job 和 severity 标签的会进行分组,且标签的 key 和 value 都相同才会被分到一组
continue 决定匹配到第一个路由后,是否继续后续匹配。默认为 false,即匹配到第一个子节点后停止继续匹配
match 一对一匹配规则,比如 match 配置的为 job: mysql,那么具有 job=mysql 的告警会进入该路由
match_re 和 match 类似,只不过是 match_re 是正则匹配
group_wait 告警通知等待,值类型为字符串。若一组新的告警产生,则会等 group_wait后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在 group_wait 内合并为单一的告警后再发送,防止告警过多,默认值 30s
group_interval 同一组告警通知后,如果有新的告警添加到该组中,再次发送告警通知的时间,默认值为 5m
repeat_interval 如果一条告警通知已成功发送,且在间隔 repeat_interval 后,该告警仍然未被设置为 resolved,则会再次发送该告警通知,默认值 4h
Alertmanager配置邮件告警

由于本次实验全部组件都使用容器搭建,所有Alertmanager的配置文件是通过secret定义的,修改对应的配置文件,添加的内容进行分段解释

[root@master-01 ~]# vim kube-prometheus/manifests/alertmanager-secret.yaml

在global下方添加smtp(发信)配置,本次实验使用163邮箱,填写对应的账号名称、SMTP服务器地址和调用SMTP服务器的密码

SMTP服务

...省略部分输出...
  alertmanager.yaml: |-
    "global":
      "resolve_timeout": "5m"
      smtp_from: "caijunxiancloud@163.com"
      smtp_smarthost: "smtp.163.com:465"
      smtp_hello: "163.com"
      smtp_auth_username: "caijunxiancloud@163.com"
      smtp_auth_password: "AS56...dsM"
      smtp_require_tls: false
...省略部分输出...

在receivers下配置接收告警的账号

...省略部分输出...
    "receivers":
    - "name": "Default"
      "email_configs":
      - to: "caijunxiancloud@163.com"
        send_resolved: true
...省略部分输出...

在route下添加分组方式,添加job、alertname和instance

...省略部分输出...
    "route":
      "group_by":
      - "namespace"
      - "job"
      - "alertname"
      - "instance"
...省略部分输出...

配置完成后,重新加载Secret配置文件

[root@master-01 ~]# kubectl replace -f kube-prometheus/manifests/alertmanager-secret.yaml
secret/alertmanager-main replaced

修改alertmanager的Service端口类型为NodePort,已经重复介绍过多次,此处不再赘述(9093端口为Web UI端口,8080端口为alertmanager和Prometheus通信的端口,读者不要混淆)

[root@master-01 ~]# kubectl get svc -n monitoring | grep alertmanager-main
alertmanager-main       NodePort    10.96.85.152    <none>        9093:31016/TCP,8080:31810/TCP   7d21h

通过Service暴露的31016端口访问alertmanager的UI界面,可以观察到首页的Alerts界面已经增加了分组方式

new

单击上方导航栏的Status按钮,下拉至出现Config字段,可以观察到配置已经发生变化

Config

登录对应接收告警信息的邮箱账号,已经可以观察到对应的告警信息了(读者在使用时,只要等找到可以用于发信的SMTP服务器即可,本质上就是邮件发送)。此处的截图可以观察到是发送到其他的邮箱账户

coremail

Alertmanager 企业微信通知

读者需要先注册企业,如果已经有企微并且有对应的后台权限,可以忽略该步骤。注册链接如下

https://work.weixin.qq.com/

注册完成后,进入登录界面,单击上方导航栏中,我的企业按钮。在页面的最下面找到企业 ID(corp_id)并记录

我的企业

单击上方导航通讯录按钮,创建对应接收告警信息的部门。对应部门的ID需要进行记录

创建部门

单击上方导航栏应用管理按钮,在页面最下方找到自建,单击创建应用

自建

创建应用

选择对应的部门或成员

选择部门

创建完成后,记录该应用对应的Agentld和Secret(注意:Secret单击查看后,需要前往企业微信内部查看)

Secret

注意:添加完成后,旧版本的企微直接修改alertmanager配置文件即可,但是新版的企业如果需要使用对应的接口,需要添加可信域名和可信IP,步骤如下

单击企微上方导航栏,在页面最后找到网页授权及JS-SDK。(配置该步骤需要完成前置条件:首先必须有一个公网可以访问的域名,并且该域名需要备案。其次需要将授权文件放在域名的根目录下,即通过https://域名/授权文件 可以直接访问该文件)。授权文件在网页会提供下载链接。配置完成后结果如下

可信域名

注意,配置完成后,依旧是无法实现企微告警,但是此处先不进行其他操作,按照大部分网上的教程继续。

修改alertmanager-secret配置文件,添加全局配置,增加企微对应的API接口和企业码

[root@master-01 ~]# vim kube-prometheus/manifests/alertmanager-secret.yaml
    "global":
      "resolve_timeout": "5m"
      wechat_api_url: "https://qyapi.weixin.qq.com/cgi-bin/"
      wechat_api_corp_id: "ww8...c7c"
...省略部分输出...

receivers字段下,增加企微对应的配置

    - name: wechat
      wechat_configs:
      - send_resolved: true
        to_party: 2 #部门ID
        to_user: '@all' #部门的所有人接收告警信息,也可以指定对应用户
        agent_id: 1000002 #应用的Agentld
        api_secret: "58zQz...vHM1is" #应用的Secret
...省略部分输出...

修改子路由配置,将Watchdog的告警发送给wechat接收者

      "routes":
      - "matchers":
        - "alertname = Watchdog"
        "receiver": "wechat"
...省略部分输出...

如果读者想快速看到效果,可以修改route字段下的 repeat_interval参数

"repeat_interval": "1m"

修改完成后,重载Alertmanager Secret配置文件,等待一段时间在Web UI看到配置文件发生变化

[root@master-01 ~]# kubectl replace -f kube-prometheus/manifests/alertmanager-secret.yaml
secret/alertmanager-main replaced

此时,读者会发现,企微仍然无法接收告警,通过查看alertmanager容器的日志文件,可以发现如下提示

ts=2024-12-02T16:40:03.083Z caller=dispatch.go:353 level=error component=dispatcher msg="Notify for alerts failed" num_alerts=1 err="wechat/wechat[0]: notify retry canceled due to unrecoverable error after 1 attempts: not allow to access from your ip, hint: [1733157603031422631558704], from ip: 120.230.86.159, more info at https://open.work.weixin.qq.com/devtool/query?e=60020"

通过查找对应的错误码,可以发现是出口IP被拒绝了,所以需要将出口IP添加到企业可信IP内。该选项在应用管理下。添加后结果如下

可信IP

企微发送告警结果如下

企微告警

自定义告警模板

使用alertmanager自带的告警模板,在告警繁多的情况下,不易于定位告警内容,针对此问题,使用自定义的告警模板进行告警通知

此处将整个配置文件贴出,供读者参考(严格遵守缩进)

[root@master-01 ~]# cat kube-prometheus/manifests/alertmanager-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    app.kubernetes.io/component: alert-router
    app.kubernetes.io/instance: main
    app.kubernetes.io/name: alertmanager
    app.kubernetes.io/part-of: kube-prometheus
    app.kubernetes.io/version: 0.27.0
  name: alertmanager-main
  namespace: monitoring
stringData:
  wechat.tmpl: |-
    {{ define "wechat.default.messages" }}
    {{- if gt (len .Alerts.Firing) 0 -}}
    {{- range $index, $alert := .Alerts -}}
    {{- if eq $index 0 }}
    ==========异常告警==========
    告警类型: {{ $alert.Labels.alertname }}
    告警级别: {{ $alert.Labels.severity }}
    告警详情:
    {{ $alert.Annotations.message }}{{ $alert.Annotations.description }}; {{$alert.Annotations.summary}}
    故障时间: {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
    {{- if gt (len $alert.Labels.instance) 0 }}
    实例信息: {{ $alert.Labels.instance }}
    {{- end }}
    {{- if gt (len $alert.Labels.namespace) 0 }}
    命名空间: {{ $alert.Labels.namespace }}
    {{- end }}
    {{- if gt (len $alert.Labels.node) 0 }}
    节点信息: {{ $alert.Labels.node }}
    {{- end }}
    {{- if gt (len $alert.Labels.pod) 0 }}
    实例名称: {{ $alert.Labels.pod }}
    {{- end }}
    ===========END============
    {{- end }}
    {{- end }}
    {{- end }}

    {{- if gt (len .Alerts.Resolved) 0 -}}
    {{- range $index, $alert := .Alerts -}}
    {{- if eq $index 0 }}
    ==========异常恢复==========
    告警类型: {{ $alert.Labels.alertname }}
    告警级别: {{ $alert.Labels.severity }}
    告警详情:
    {{ $alert.Annotations.message }}{{ $alert.Annotations.description }}; {{$alert.Annotations.summary}}
    故障时间: {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
    恢复时间: {{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
    {{- if gt (len $alert.Labels.instance) 0 }}
    实例信息: {{ $alert.Labels.instance }}
    {{- end }}
    {{- if gt (len $alert.Labels.namespace) 0 }}
    命名空间: {{ $alert.Labels.namespace }}
    {{- end }}
    {{- if gt (len $alert.Labels.node) 0 }}
    节点信息: {{ $alert.Labels.node }}
    {{- end }}
    {{- if gt (len $alert.Labels.pod) 0 }}
    实例名称: {{ $alert.Labels.pod }}
    {{- end }}
    ===========END============
    {{- end }}
    {{- end }}
    {{- end }}
    {{- end }}
  alertmanager.yaml: |-
    "global":
      "resolve_timeout": "5m"
      smtp_from: "caijunxiancloud@163.com"
      smtp_smarthost: "smtp.163.com:465"
      smtp_hello: "163.com"
      smtp_auth_username: "caijunxiancloud@163.com"
      smtp_auth_password: "S...56fM"
      smtp_require_tls: false
      wechat_api_url: "https://qyapi.weixin.qq.com/cgi-bin/"
      wechat_api_corp_id: "ww8...c7c"
    templates:
    - '/etc/alertmanager/config/*.tmpl'
    "inhibit_rules":
    - "equal":
      - "namespace"
      - "alertname"
      "source_matchers":
      - "severity = critical"
      "target_matchers":
      - "severity =~ warning|info"
    - "equal":
      - "namespace"
      - "alertname"
      "source_matchers":
      - "severity = warning"
      "target_matchers":
      - "severity = info"
    - "equal":
      - "namespace"
      "source_matchers":
      - "alertname = InfoInhibitor"
      "target_matchers":
      - "severity = info"
    "receivers":
    - "name": "Default"
      "email_configs":
      - to: "jxcai@c7.icoremail.net"
        send_resolved: true
    - name: wechat
      wechat_configs:
      - send_resolved: true
        to_party: 1
        to_user: '@all'
        agent_id: 1000002
        api_secret: "58z...vHM1is"
        message: '{{ template "wechat.default.messages" . }}'
    - "name": "Watchdog"
    - "name": "Critical"
    - "name": "null"
    "route":
      "group_by":
      - "namespace"
      - "job"
      - "instance"
      - "alertname"
      "group_interval": "5m"
      "group_wait": "30s"
      "receiver": "Default"
      "repeat_interval": "12h"
      "routes":
      - "matchers":
        - "alertname = Watchdog"
        "receiver": "wechat"
      - "matchers":
        - "alertname = InfoInhibitor"
        "receiver": "null"
      - "matchers":
        - "severity = critical"
        "receiver": "Critical"
type: Opaque

上面的配置文件,修改了三处,添加了对应的模板文件

  wechat.tmpl: |-
    {{ define "wechat.default.messages" }}
    {{- if gt (len .Alerts.Firing) 0 -}}
    {{- range $index, $alert := .Alerts -}}
...省略部分输出...

指定了模板的位置

    templates:
    - '/etc/alertmanager/config/*.tmpl'

wechat应用该模板(注意:{{ template "wechat.default.message" . }}配置的 wechat.default.message,是模板文件define 定义的名称:{{ define "wechat.default.message" }},并非文件名称)

        api_secret: "58z...vHM1is"
        message: '{{ template "wechat.default.messages" . }}'
...省略部分输出...  

配置完成后,重启Alertmanager Secret文件,等待Web UI界面重新生成配置(大约需要5分钟,才能重新读取配置)

[root@master-01 ~]# kubectl replace -f kube-prometheus/manifests/alertmanager-secret.yaml secret/alertmanager-main replaced

企微此时告警模板

企微新告警

计划内维护暂停告警Silence

对于已经知晓的告警或者需要延后处理的告警,可以使用Silence功能,类似于icinga的dowmtime功能

silence

silence result

PrometheusRule

Prometheus 的告警机制主要依赖 规则评估 和 告警管理 两个部分:

  1. 规则评估 Prometheus 使用 告警规则(Alerting Rules) 来定义告警条件,这些规则通常配置在 Prometheus 的 rules.yml 文件中,或者通过 PrometheusRule 自定义资源定义(CRD)在 Kubernetes 环境中应用

  2. 告警管理 当 Prometheus 发现一个告警条件满足时:生成告警状态(Pending → Firing)。将告警信息发送到 Alertmanager。

PrometheusRule 是 Kubernetes 环境中的 自定义资源定义(CRD),用于在集群中定义 Prometheus 的告警规则。其作用:提供了一种将告警规则以 Kubernetes 资源形式管理的方式。集中化管理:与 Kubernetes 的声明式配置集成,方便版本控制和动态更新。在 Kubernetes 中,Prometheus 会自动发现集群中定义的 PrometheusRule 资源,并加载其中的告警规则。

查看默认配置的告警策略

[root@master-01 ~]# kubectl get prometheusrules -n monitoring
NAME                              AGE
alertmanager-main-rules           9d
grafana-rules                     9d
kube-prometheus-rules             9d
kube-state-metrics-rules          9d
kubernetes-monitoring-rules       9d
node-exporter-rules               9d
prometheus-k8s-prometheus-rules   9d
prometheus-operator-rules         9d

通过-oyaml 查看某个 rules 的详细配置

[root@master-01 ~]# kubectl get prometheusrules -n monitoring node-exporter-rules -oyaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
...省略部分输出...
spec:
  groups:
  - name: node-exporter
    rules:
    - alert: NodeFilesystemSpaceFillingUp
      annotations:
        description: Filesystem on {{ $labels.device }}, mounted on {{ $labels.mountpoint
          }}, at {{ $labels.instance }} has only {{ printf "%.2f" $value }}% available
          space left and is filling up.
        runbook_url: https://runbooks.prometheus-operator.dev/runbooks/node/nodefilesystemspacefillingup
        summary: Filesystem is predicted to run out of space within the next 24 hours.
      expr: |
        (
          node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 15
        and
          predict_linear(node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""}[6h], 24*60*60) < 0
        and
          node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0
        )
      for: 1h
      labels:
        severity: warning
...省略部分输出...
参数 解析
alert 告警策略的名称
annotations 告警注释信息
expr 告警表达式
for 评估等待时间,告警持续多久才会发送告警数据
labels 告警的标签,用于告警的路由

域名访问延迟告警

假设需要对域名访问延迟进行监控,访问延迟大于 0.1 秒进行告警,此时可以创建一个PrometheusRule 如下(注意:真实情况下,不需要将阈值设置如此敏感,此处只是为了实验展示效果)

[root@master-01 ~]# cat blackbox.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: blackbox
  namespace: monitoring
  labels:
    app.kubernetes.io/component: exporter
    app.kubernetes.io/name: blackbox-exporter
    prometheus: k8s
    role: alert-rules
spec:
  groups:
  - name: blackbox-exporter
    rules:
    - alert: DomainAccessDelayExceeds1s
      annotations:
        description: 域名:{{ $labels.instance }} 探测延迟大于 1 秒,当前延迟为:{{ $value }}
        summary: 域名探测,访问延迟超过 1 秒
      expr: sum(probe_http_duration_seconds{job=~"blackbox"}) by (instance) > 0.1
      for: 1m
      labels:
        severity: warning
        type: blackbox

创建资源

[root@master-01 ~]# kubectl create -f blackbox.yaml
prometheusrule.monitoring.coreos.com/blackbox created
[root@master-01 ~]# kubectl get -f blackbox.yaml
NAME       AGE
blackbox   39s

依次单击Prometheus UI界面上方导航栏→Status→Rules,找到配置的规则

rules

此时由于阈值设置为0.1秒,所以Prometheus的Alerts界面也会出现告警,Alertmanager的路由规则并没有针对黑盒监控的接受者,所以会匹配到Default的Receive,推送邮件通知

邮件通知

在本文内,只列举了一种告警的配置方法,但是在实例的应用场景当中,可能需要配置多种监控和告警指标,读者可以使用grafana的案例进行参考。

选择某个模板,单击Explore按钮

grafa explore

出现的界面即为采集数据的监控语句,通过对应的判断条件,比如大于等于某个阈值,即可修改为对应的监控条件

命令