最近在研究如何给应用添加合适的 Metrics,用来分析应用的使用情况以及调试,整体思路是使用 Prometheus 收集数据,Grafana 进行数据的展示。过程中发现了 node-exporter 项目,觉得可以直接拿来监控自己平时使用的 Linux 机器,就有了这篇文章。

整个系统使用了三个组件:

node-exporter:运行在主机上收集操作系统上各种数据的 Agent,Prometheus 中称为 exporter

Prometheus:开源的时序数据库,作为数据存储和分析的中心

Grafana:数据展示分析界面,提供各种强大的 Dashboard,可以从多个数据源读取数据,其中就包括 Prometheus

NOTE:所有的服务都是通过 Docker 启动的,需要安装 Docker 和 docker-compose,并熟悉它们的使用。

安装配置 PrometheusPrometheus 最早是 SoundCloud 开发的一款时序数据库,用来作为 Metrics 数据收集和存储,目前已经成为 CNCF 基金会下面的一个项目,也是 Kubernetes 官方推荐的 Metrics 收集和监控工具。

首先,我们创建一个 docker-compose.yml 文件,里面只包含 Prometheus 一个服务:

version: '2'
services:
prometheus:
image: prom/prometheus:v2.0.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- '9090:9090'
如果对 Docker 和 docker-compose 熟悉的话,上面的内容容易理解:

image 后面指定了使用的 Prometheus 容器镜像,该文件使用的是 v2.0.0 版本

volumes 把当前目录下面的 prometheus.yml 文件挂载到容器里,这样是因为后面会一直修改这个文件,利用 Volume 挂载的方式比较灵活

command 指定了 Prometheus 运行的命令行参数,这里只指定配置文件的位置,更多参数可以使用 --help 来查看

ports 把 Prometheus 服务监听的端口映射到主机上,这样可以直接访问主机端口使用它

其中比较重要的是 prometheus.yml 文件,它的内容如下:

global:
scrape_interval: 5s
external_labels:
monitor: 'my-monitor'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

这个配置文件一共分为两个部分:global 和 scrape_configs,前者是全局的配置,如果后面的任务没有对特定配置项进行覆盖,这里的选项会生效。这里有两个配置项,scrape_interval 表示 Prometheus Server 抓取的周期,如果太频繁会导致 Prometheus 压力比较大,如果太久,可能会导致某些关键数据漏掉,推荐根据每个任务的重要性和集群规模分别进行配置。

scrape_configs 配置了每个抓取任务,因此是一个列表,这里我们只有一个任务,那就是抓取 Prometheus 本身的 Metrics。配置里面最重要的是 static_configs.targets,表示要抓取任务的 HTTP 地址,默认会在 /metrics url 出进行抓取,比如这里就是 http://localhost:9090/。 这是 Prometheus 本身提供的监控数据,可以在浏览器中直接查看。

grafana X轴显示日期 grafana显示时间戳转换日期_Docker

每个数据都是有一个名字和一系列称为 Label 的键值对组成的,Prometheus 在抓取数据的时候还会自动添加上 instance(节点的 host:port 标识) 和 Job(任务名称) 两个 Label 作为任务之间的区分。

这些数据本身没有时间信息,当 Prometheus 抓取的时候会自动添加上当时的时间戳。此外这些数据在客户端会分成四种不同的类型:Counter、Gauge、Histogram 和 Summary。更多关于 Prometheus Metrics 数据类型的说明请查阅官方文档。

运行 docker-compose up -d 启动服务,然后在浏览器中打开 http://server-ip:9090/status 查看 Prometheus 运行的状态信息:

grafana X轴显示日期 grafana显示时间戳转换日期_grafana X轴显示日期_02

整个 Prometheus 体系的工作原理如下所示:

grafana X轴显示日期 grafana显示时间戳转换日期_Docker_03

Prometheus Server 位于中心,负责时序数据的收集、存储和查询

左边是数据来源,Prometheus 统一采用拉取的模式(pull mode)从兼容的 HTTP 接口处获取数据,数据源可以分为三种:

本身就暴露 Prometheus 可读取 Metrics 数据的或者专门为某个组件编写的 exporter,称为 Jobs 或者 Exporters,比如 node exporter,HAProxy、Nginx、MySQL 等服务的 exporter

通过 push gateway 可以把原来 push 类型的数据转换成 pull 类型

其他 Prometheus Server

上面是目标自动发现机制。对于生产的很多情况,手动配置所有的 Metrics 来源可能会非常繁琐,所以 Prometheus 支持 DNS、Kubernetes、Consul 等服务发现机制来动态地获取目标源进行数据抓取

右下方是数据输出,一般是用来进行 UI 展示,可以使用 Grafana 等开源方案,也可以直接读取 Prometheus 的接口进行自主开发

右上方是告警部分,用户需要配置告警规则,一旦 alertManager 发现监控数据匹配告警规则,就把告警信息通过邮件、社交账号发送出去

使用 Node Exporter 收集监控数据虽然监控 Prometheus 服务自身是件有趣而且有用的事情,但是我们的目标是监控 linux 主机。因为 Prometheus 只能从 HTTP 接口的某个地址来拉取监控数据,因此需要一个工具把 Linux 提供的系统数据以 HTTP 服务的形式暴露出来。庆幸的是,Prometheus 官方社区有很多 Exporter,它们负责把某个组件或者系统的监控数据以 Prometheus 能理解的方式暴露出来,其中 Node Exporter 就是导出 Unix/Linux 系统监控数据的工具。

Grafana 主要是从 /proc 中读取 Linux 提供的各种数据,修改 docker-compose.yml 文件,添加上 node-exporter 相关的内容,node-exporter 默认会监听在 9100 端口:

version: '2'
services:
prometheus:
image: prom/prometheus:v2.0.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- '9090:9090'
node-exporter:
image: prom/node-exporter:v0.15.2
ports:
- '9100:9100'

为了让 Prometheus 收集 node-exporter 的内容,我们需要在配置文件中加上一个单独的任务:

global:
scrape_interval: 5s
external_labels:
monitor: 'my-monitor'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node resources'
scrape_interval: 10s
static_configs:
- targets:
- 'node-exporter:9100'

因为 docker-compose 会自动做服务到 IP 地址的解析,因此这里可以直接使用 node-exporter:9100 作为地址。

再次运行,确认 Prometheus 中 targets 列表中有 node-exporter。

安装配置 GrafanaPrometheus 自带的 Web 界面可以用来查询配置内容、监控节点是否运行正常,也可以用来查询某个 Metric 的数值,以及提供简单的图形化功能。但是它的图形化功能比较单一, 当有很多数据要同时进行展示时,就需要借助更强大的 Dashboard 工具,比如这里要介绍的 Grafana。

Grafana 是一款强大的 Dashboard 工具,界面设计很好看,功能强大,可配置性非常灵活。

同样,在 docker-compose.yml 文件中加入 Grafana 服务:

version: '2'
services:
prometheus:
image: prom/prometheus:v2.0.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- '9090:9090'
node-exporter:
image: prom/node-exporter:v0.15.2
ports:
- '9100:9100'
grafana:
image: grafana/grafana:4.6.2
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=pass
depends_on:
- prometheus
ports:
- '3000:3000'
volumes:
grafana_data: {}
prometheus_data: {}

这里使用 Docker 的 volumes 来保存 Grafana 和 Prometheus 运行过程中产生的数据来保证持久化,而且使用 GF_SECURITY_ADMIN_PASSWORD=pass 环境变量设置 admin 的密码。

docker-compose 运行之后,Grafana 会运行在 http://host-ip:3000 地址,使用浏览器打开会出现登陆页面,输入用户名和刚才配置的密码进入服务。

Grafana 本身只是一个 Dashboard,它可以从多个数据源(时序数据库)中获取数据进行展示,比如我们这里使用的 Prometheus。所以在正式配置界面之前,需要先添加数据源,点击 Grafana 左上角按钮找到 Data Sources 页面或者直接输入 http://host-ip:3000/datasources 地址,会进入对应页面。按照下面的内容进行填写,主要是 Type 要选择 Prometheus,URL 添加 Grafana 服务能访问的 Prometheus 地址(因为它们都是通过 docker-compose 运行的,所以这里可以直接使用名字来标识);Name 字段随便填写一个用来标记来源的名字即可。

grafana X轴显示日期 grafana显示时间戳转换日期_docker_04

然后创建一个 Dashboard,并里面添加 Graph(为了简单,我用了 test dashboard 这个名字),在 Graph 中添加一个 panel,我们用这个 panel 展示系统的 load 数据。编辑 panel 数据,选择 data source 为之前添加的 Prometheus,然后填写 query,系统 node 比较简单,一共是 node_load1、node_load5 和 node_load15,分别是系统最近一分钟、五分钟和十五分钟的 load 数值。输入完成后点击输入框之外,Grafana 会自动更新上面的图表:

grafana X轴显示日期 grafana显示时间戳转换日期_grafana X轴显示日期_05

类似的,可以添加其他的 panel,展示系统方方面的监控数据,比如 CPU、memory、IO、网络等。Grafana 更多配置可以参考官方文档,选择合适的图表来展示想要的结果。

手动通过界面对 Grafana 可以很灵活地创建出很强大的图表,但是这无疑会耗费很多时间(想想,每次搭建 Grafana 都要重新做一遍),而且 node exporter 这种监控数据是通用的,如果所有人都手动创建一遍无疑是很多重复工作。为此,Grafana 支持导入和导出配置,并且提供官方社区供大家分享 Dashboard 配置。

每个 Dashboard 都有一个编号,比如编号 22 的 Dashboard 就是专门为 node-exporter 设计的展示图表。在 Grafana 中点击导入 Dashboard,添加编号选择数据源,就能得到已经配置完整的图表:

grafana X轴显示日期 grafana显示时间戳转换日期_数据_06

如果对 Dashboard 有什么不满,可以直接在页面进行添加和编辑,然后可以导出 json 文件,以便重复使用。

配置告警通过 Grafana 图表我们可以知道系统各种指标随着时间的变化,方便轻松判断系统某个资源是否异常。但是我们不能一直盯着 Dashboard,还需要系统发生异常的时候能立即通过邮件或者其他方式通知我们,这就是告警的功能。

Prometheus 提供用户可以自己配置的告警规则,在处理 Metrics 数据的时候,如果发现某个规则被触发,就执行对应的告警动作,通过发邮件或者其他方式通知用户。

对于我们的单节点主机来说,可以定义两个简单的告警规则:当主机 download 掉,或者 CPU load 持续过高一段时间就发送告警。对此,需要新建一个 alert.rules 文件,用来保存告警规则,按照需求对应的内容如下:

➜  monitor git:(master) ✗ cat alert.rules
groups:
- name: node-alert
rules:
- alert: service_down
expr: up == 0
for: 2m
- alert: high_load
expr: node_load1 > 0.5
for: 5m
在启动 Prometheus 服务的时候把告警规则文件 mount 到 Pod 中,如下添加一个 volume:
➜  monitor git:(master) ✗ cat docker-compose.yml
version: '2'
services:
prometheus:
image: prom/prometheus:v2.0.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./alert.rules:/etc/prometheus/alert.rules
......
然后,告知 promethues 加载这些规则:
➜ monitor git:(master) ✗ cat prometheus.yml
......
rule_files:
- 'alert.rules'}}}

为了验证告警规则是否生效,可以把 node-exporter 服务停掉:

docker-compose stop node-exporter

在 Prometheus 的告警页面(alert)查看告警:

grafana X轴显示日期 grafana显示时间戳转换日期_linux ip rule 持久化_07

类似地,可以运行一些消耗 CPU 资源的服务来触发系统 load 过高的告警规则,比如运行下面这个 Docker 容器(一直 while 循环霸占 CPU 资源可以轻松把 CPU load 提到很高):

docker run --rm -it busybox sh -c "while true; do :; done"

Prometheus 还提供了 Alertmanager 可以自动化根据告警规则触发对应的动作,一般是各种方式通知用户和管理员,这里就不再介绍了。

总结本文中使用的完整配置文件放到了 GitHub 上,可以作为参考。

需要注意的是,这只是一个本地的 test 环境,不能直接在生产上使用。首先我们没有配置安全访问,所有的服务都是 HTTP;其次 docker-compose 运行的话,所有的服务都是在同一台机器上,无法做到分布式监控和高可用。

如果想在生产中使用 Prometheus 和 Grafana,请参考官方文档。