# 17.8 Prometheus 监控部署

Prometheus 是一个开源的系统监控和告警工具包，本节将介绍如何在 FreeBSD 上部署 Prometheus 监控系统。

## 框架

Prometheus 监控部署框架如图所示。

![框架](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-2b9e9e52d66c611038001966436315eb4f008c2f%2Fprometheus.png?alt=media)

说明：

* Prometheus 是整个监控系统的中心
* Grafana 用于将监控数据可视化显示
* Exporter 用于数据采集；Prometheus 支持多种 Exporter，可使用 `pkg search -D prometheus` 查找
* Alertmanager 用于处理告警信息
* Prometheus 可以配置多种远程存储

> **注意**
>
> Prometheus、Grafana、Exporter、Alertmanager 等组件可以分别部署在不同的设备或操作系统上。Exporter 应安装在被监控的节点上。以下示例中，Prometheus、Grafana、Alertmanager 安装在同一台机器上，Exporter 根据需要单独部署。

此外，如果遇到服务启动问题，可先查看 `/var/log/daemon.log`。Prometheus 配置文件大部分采用 YAML 格式，请注意缩进。对于 Prometheus 配置文件，可使用 `promtool check` 命令检查配置文件是否正确。

## 安装基本工具

了解完框架后，需要安装 Prometheus 监控系统的基本组件。

### 安装 prometheus

使用 pkg 包管理器安装 Prometheus 是最快捷的方式，执行以下命令即可完成安装。

```sh
# pkg install prometheus
```

或者使用 Ports 方式安装 Prometheus，需要先进入对应的目录再执行编译安装命令。

```sh
# cd /usr/ports/net-mgmt/prometheus2/ 
# make install clean
```

#### 服务项

设置 Prometheus 服务开机自启并启动服务：

```sh
# service prometheus enable   # 将 Prometheus 服务加入系统启动项
# service prometheus start    # 启动 Prometheus 服务
```

### 安装 grafana

使用 pkg 包管理器安装 Grafana 是最快捷的方式，执行以下命令即可完成安装：

```sh
# pkg install grafana
```

或者使用 Ports 方式安装 Grafana，需要先进入对应目录再执行编译安装命令。

```sh
# cd /usr/ports/www/grafana/ 
# make install clean
```

#### 服务项

设置 Grafana 服务开机自启并启动服务：

```sh
# service grafana enable   # 将 Grafana 服务加入系统启动项
# service grafana start    # 启动 Grafana 服务
```

### 安装 node\_exporter

使用 pkg 包管理器安装 Node Exporter 是最快捷的方式，执行以下命令即可完成安装：

```sh
# pkg install node_exporter
```

或者使用 Ports 方式安装 Node Exporter，需要先进入对应目录再执行编译安装命令。

```sh
# cd /usr/ports/sysutils/node_exporter
# make install clean
```

#### 服务项

设置 Node Exporter 服务开机自启并启动服务：

```sh
# service node_exporter enable   # 将 Node Exporter 服务加入系统启动项
# service node_exporter start    # 启动 Node Exporter 服务
```

## 配置

目录结构：

```sh
/
├── usr
│   └── local
│       └── etc
│           ├── prometheus.yml                 # Prometheus 主配置文件
│           ├── prometheus_webconfig.yml       # Prometheus Web 认证配置文件
│           ├── node_exporter_webconfig.yml    # Node Exporter Web 认证配置文件
│           └── prometheus
│               └── alert.rules.yml           # Prometheus 告警规则文件
└── var
    └── log
        └── daemon.log                         # 系统守护进程日志
```

### prometheus

Prometheus 的主要配置文件为 `/usr/local/etc/prometheus.yml`，内容如下：

```yml
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
```

`scrape_configs` 用于配置采集数据的目标节点，这里默认的 `targets: ["localhost:9090"]` 指 Prometheus 服务本身。

现在增加用于监控主机信息的 `node_exporter`，在 `scrape_configs` 下写入如下：

```yml
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "node_exporter_local"
    static_configs:
      - targets: ["localhost:9100"]
```

重启 Prometheus。

```sh
# service prometheus restart
```

这样就向 Prometheus 增加了一个新的监控节点，任务名为 `node_exporter_local`。`[]` 中可添加多个主机。

Prometheus 提供 Web 界面（默认端口：9090），可查看监控目标信息如下：

![监控目标](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-4ba4a74265afe516336fab43d27082b17b1abb01%2Fprometheus_target.png?alt=media)

Graph 页面：可以查看各项监控指标，支持表达式。

![空闲内存示例](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-74230964eb73530ac93b86b4cc9bbb94f8d0db6d%2Fprometheus_example_node_memory_free.png?alt=media)

熟悉界面后会发现，直接查看数据或 Panel 并不方便。此时可使用 Grafana 以更友好的方式展示数据。

### grafana

在浏览器中打开 Grafana 的 Web 页面（默认端口为 `3000`），默认用户名为 `admin`，密码为 `admin`。

如下图所示，可切换为中文界面：

![grafana 切换中文界面](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-1f635be7c426342e8f46692b46026b0dd13334a2%2Fgrafana_setting_zh_language.png?alt=media)

先新建与 prometheus 的连接

![连接 prometheus 1](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-d7d00102a6e8d0547efd5da124a6590e82fe7d16%2Fgrafana_connect_prometheus_1.png?alt=media)

![连接 prometheus 2](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-4b8914e95a09a561496cca98ad71f5594efcd5cd%2Fgrafana_connect_prometheus_2.png?alt=media)

![连接 prometheus 3](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-a77e734a88db56400764ad335ddf8cb70238b266%2Fgrafana_connect_prometheus_3.png?alt=media)

用已创建的连接建立仪表板 (导入预设仪表板)

![建仪表盘 1](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-4863032101b35afd78c64243b08cfa44bd41c26f%2Fgrafana_dashboard_create_1.png?alt=media)

![建仪表盘 2](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-9d94fa0b535613bb59f8345dfa1927897293e841%2Fgrafana_dashboard_create_2.png?alt=media)

![建仪表盘 3](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-2d6b946b3b7c291673ced74c8b250dca676ddaeb%2Fgrafana_dashboard_create_3.png?alt=media)

![建仪表盘 4](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-baff1af1c855b8c04447c95ea8970dc1374d3dc0%2Fgrafana_dashboard_create_4.png?alt=media)

![建仪表盘 5](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-92017104f9ce38cfbb2ce0b444459071736e5f0c%2Fgrafana_dashboard_create_5.png?alt=media)

## 安全认证

默认情况下，只有登录 Grafana 需要密码。各组件之间以 HTTP 连接，例如可通过访问 `http://ip:9100/` 直接获取 Node Exporter 的监控数据，Prometheus 可通过 `http://ip:9090/` 直接访问。

在生产环境中直接暴露这些信息存在安全风险，因此需要进行安全认证。

### 基本认证

#### prometheus 的 basic\_auth

* 编辑 `/usr/local/etc/prometheus_webconfig.yml`，格式如下

```yml
basic_auth_users:
  prometheususer: $2a$10$mxpc1PdYgOwvGepNtCuBKO6RXVUzLDg8feOvuz6szOsBa9M28ECfe
```

第二行中，冒号前为用户名，冒号后为密码的 bcrypt 哈希值——此处使用 sttr 工具生成，也可使用其他工具。假设密码为 `prometheuspassword`：

```sh
# pkg install sttr
$ sttr bcrypt prometheuspassword
$2a$10$mxpc1PdYgOwvGepNtCuBKO6RXVUzLDg8feOvuz6szOsBa9M28ECfe%
```

这里的 `%` 是终端在未换行时显示的输出符号，可忽略。

* 编辑 `/usr/local/etc/prometheus.yml` 文件，在 prometheus 的配置下加入下面三行：

```yml
    basic_auth:
      username: prometheususer
      password: prometheuspassword
```

请注意缩进，完整示例如下：

```yml
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
    basic_auth:
      username: prometheususer
      password: prometheuspassword

  - job_name: "node_exporter_local"
    static_configs:
      - targets: ["localhost:9100"]
```

* 修改 prometheus 启动配置，并重启

```sh
# sysrc prometheus_args="--web.config.file='/usr/local/etc/prometheus_webconfig.yml'"  # 设置 Prometheus 启动参数，指定 Web 配置文件
# service prometheus restart   # 重启 Prometheus 服务以应用配置
```

访问 `http://ip:9090/` 时，Prometheus 会要求先登录：

![登录 prometheus](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-819592220fe9b47b38c53e4880b05495bb5cd328%2Fprometheus_basic_auth_login.png?alt=media)

相应的 Grafana 在连接数据源时要设置相应认证信息

#### exporter 的 basic\_auth

下面以 node\_exporter 为例

* 编辑 `/usr/local/etc/node_exporter_webconfig.yml`，格式如下

```yml
basic_auth_users:
  node_exporter_user: $2a$10$XoJoz.x.m9FTEbaTF3hBsehE9C8zCWjCQUHkSL0Isk53UnUTjR4hi
```

* 修改 node\_exporter 启动配置，并重启服务

```sh
# sysrc node_exporter_args="--web.config.file='/usr/local/etc/node_exporter_webconfig.yml'"
# service node_exporter restart
```

* 编辑 `/usr/local/etc/prometheus.yml`，如下：

```yml
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
    basic_auth:
      username: tome
      password: jake

  - job_name: "node_exporter_local"
    static_configs:
      - targets: ["localhost:9100"]
    basic_auth:
      username: node_exporter_user
      password: node_exporter_password
```

重启 prometheus

```sh
# service prometheus restart
```

### CA 证书认证

对安全要求很高的情况下，还可以使用 CA 证书认证方式加强安全，但这不是每个 exporter 都支持的认证方式。

以下仍以 Node Exporter 为例，假设其节点 IP 为 10.0.55.1。

#### 生成证书

```sh
# 生成 CA 私钥
$ openssl genpkey -algorithm RSA -out ca.key
# 生成 CA 证书
$ openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -subj "/CN=my-ca"
```

#### 生成 prometheus 端证书

```sh
# 生成 Prometheus 客户端私钥
$ openssl genpkey -algorithm RSA -out prometheus.key
# 生成客户端证书请求
$ openssl req -new -key prometheus.key -out prometheus.csr -subj "/CN=prometheus-client"
# 使用 CA 对客户端证书请求进行签名
$ openssl x509 -req -in prometheus.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out prometheus.crt -days 3650
```

#### 生成 node\_exporter 端证书

1. 创建一个 OpenSSL 配置文件，以便在生成证书时指定 SAN（Subject Alternative Name）。

创建一个文件，比如叫 san.cnf，内容如下。

```ini
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no

[ req_distinguished_name ]
CN = node-exporter-server

[ v3_ca ]
# 添加 SAN 字段
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = node-exporter-server.example.com  # 如果你有域名，添加它
IP.1 = 10.0.55.1  # 如果你用的是 IP 地址，添加它
```

2. 生成证书请求时使用 SAN 配置

使用这个配置文件来生成证书签名请求（CSR）和证书。

```sh
# 首先，生成私钥
$ openssl genpkey -algorithm RSA -out node_exporter.key
# 然后，生成带有 SAN 字段的 CSR。
$ openssl req -new -key node_exporter.key -out node_exporter.csr -config san.cnf
# 用 CA 签署证书
$ openssl x509 -req -in node_exporter.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out node_exporter.crt -days 3650 -extensions v3_ca -extfile san.cnf
```

指定 SAN（Subject Alternative Name）非常重要，否则可能无法访问。也可以在 Prometheus 中配置忽略证书验证，但这和安全相悖，所以这里不再提及。

#### 配置 prometheus 和 node\_exporter

编辑 `/usr/local/etc/node_exporter_webconfig.yml` 文件，如下：

```yml
tls_server_config:
  cert_file: /path/to/node_exporter.crt
  key_file: /path/to/node_exporter.key
  client_ca_file: /path/to/ca.crt
  client_auth_type: "RequireAndVerifyClientCert"
```

最后一句最重要，只有这个选项才是安全的。

修改 `/usr/local/etc/prometheus.yml` 文件如下：

```yml
  - job_name: "node_exporter_local"
    static_configs:
      - targets: ["10.0.55.1:9100"]
    scheme: 'https'
    tls_config:
      cert_file: '/path/to/prometheus.crt'
      key_file: '/path/to/prometheus.key'
      ca_file: '/path/to/ca.crt'
```

这两个文件在 [基本认证](#基本认证) 中已经提及，用法相同。

请注意密钥和证书文件的存放位置及权限设置，应只赋予最低访问权限。

重启 prometheus 和 node\_exporter 即可。

## pushgateway

上述介绍均为 Pull 方式，由 Prometheus 从各个 Exporter 拉取数据；Pushgateway 则允许监测点主动推送数据到 Pushgateway，再由 Prometheus 从 Pushgateway 拉取数据，适用于临时任务和批量任务的监控场景。

1. 安装 pushgateway

```sh
# pkg install pushgateway
# service pushgateway enable
# service pushgateway start
```

2. 在 prometheus 中配置 pushgateway

编辑 `/usr/local/etc/prometheus.yml` 文件，增加如下内容：

```yml
  - job_name: "pushgateway"
    static_configs:
      - targets: ["localhost:9091"]
```

3. 临时任务举例

假设有一个查看僵尸进程的管理脚本，如下：

```sh
num=$(ps aux |awk 'NR>1 {print $8}'|grep Z|wc -l)
echo "process_zombie $num"|curl --data-binary @- http://10.0.55.1:9091/metrics/job/check_processes
```

第一行用于检查僵尸进程数量，第二行将僵尸进程计数发送到 Pushgateway。注意发送的数据每行必须以换行符 `\n` 结尾。

## 告警

Prometheus 的告警依赖 Alertmanager 组件。此处示例以 Jail Exporter 为例（安装配置较为简单，参见上文），同时需要在 `/boot/loader.conf` 文件中写入 `kern.racct.enable=1` 以开启系统记账功能。

1. 使用 pkg 安装：

```sh
# pkg install alertmanager
```

2. 配置 alertmanager 告警路由规则

这里只展示简单的 email 方式，alertmanager 也支持其他方式通知。

```yml
global:
  smtp_smarthost: 'smtp.sina.com:25'
  smtp_from: 'xxxxx@sina.com'
  smtp_auth_username: 'xxxxx'
  smtp_auth_password: 'xxxxxxxxxxxxxxx'
templates:
  - '/etc/alertmanager/template/*.tmpl'
route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 3h
  receiver: safreya

  routes:
    - matchers:
        - alertname=~"jail"
      receiver: xxxxx
      routes:
        - matchers:
            - severity="critical"
          receiver: xxxxx

receivers:
  - name: 'xxxxx'
    email_configs:
      - to: 'xxxxx@qq.com'
```

其中 global 指定全局配置，这里指定了 smtp 服务。route 指定发送路由规则。receivers 指定接收者信息。

3. 配置告警规则

编写规则文件，如 `/usr/local/etc/prometheus/alert.rules.yml` 文件：

```yml
groups:
- name: jails-alerts
  rules:
  - alert: jail_down
    expr: absent(jail_id{name="dox"})
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "jail dox is down"
      description: "jail dox is down"
```

`alert` 指定告警的名字。 `expr` 指定告警触发条件表达式，这里使用 `absent(jail_id{name="dox"})` 表示当名为 dox 的 jail 的指标（jail\_id）不存在时触发告警。 `for` 指触发告警的等待时间，此处为 5 分钟。如果在 5 分钟内问题得到解决，则不会发送告警。

4. 在 prometheus 配置文件中引入规则文件，并连接 alertmanager

```yml
# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - 10.0.55.1:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"
  - "/usr/local/etc/prometheus/alert.rules.yml"
```

5. 重启 prometheus 和 alertmanager

```sh
service prometheus restart
service alertmanager restart
```

6. 测试

关闭 jail 以触发规则：

```sh
# jail -r dox
```

5 分钟后发送告警邮件。

再开启 jail。

```sh
# jail -c dox
```

告警规则重置为非活跃状态。

## 远程存储

prometheus 的数据支持远程存储。下面以 InfluxDB 为例。

1. 请读者参考本书其他章节，自行安装配置 InfluxDB。

请注意 InfluxDB 的服务名是 `influxd`。

出于安全考量，应该修改 `/usr/local/etc/influxd.conf`，在 http 段开启 http 认证：

```ini
[http]
auth-enabled = true
```

2. 创建 InfluxDB 用户和数据库

用 `influx` 进入命令行客户端

```sql
create database "prometheus"
create user prometheus with password '123'
grant read on prometheus to prometheus
grant write on prometheus to prometheus
```

重启 InfluxDB 即可。

3. 配置 prometheus

编辑 `/usr/local/etc/prometheus.yml`

```yml
remote_write:
  - url: "http://10.0.55.1:8086/api/v1/prom/write?db=prometheus&u=prometheus&p=123"
remote_read:
  - url: "http://10.0.55.1:8086/api/v1/prom/read?db=prometheus&u=prometheus&p=123"
```

FreeBSD Ports 中的 InfluxDB 为 v1 版本，请使用 v1 API 进行配置。

重启 prometheus 服务即可。

4. 验证

可使用 `influx` 命令查询数据库中的数据指标：

```sql
use prometheus   -- 切换到 Prometheus 数据库
select * from jail_id   -- 查询 jail_id 表中的所有记录
1739497283285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497298285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497298285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497313285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497313285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497328285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497328285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497343285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497343285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497358285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497358285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
1739497373285000000 jail_id  192.168.0.100:9452 jail_exporter dox        4
1739497373285000000 jail_id  192.168.0.100:9452 jail_exporter prometheus 1
```

## 参考文献

* Prometheus. exporter 配置参考\[EB/OL]. \[2026-03-25]. <https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md>. 提供 Exporter 安全认证与 TLS 配置的完整说明。
* Prometheus. prometheus 配置参考\[EB/OL]. \[2026-03-25]. <https://github.com/prometheus/prometheus/blob/main/docs/configuration/configuration.md>. 详述 Prometheus 主配置文件的完整参数集
* Prometheus. 远程存储相关\[EB/OL]. \[2026-03-25]. <https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage>. 介绍 Prometheus 远程读写接口及集成方案
* Prometheus. alertmanager 配置参考\[EB/OL]. \[2026-03-25]. <https://prometheus.io/docs/alerting/latest/configuration/>. 告警路由与通知渠道的完整配置指南

## 课后习题

1. 查找 Prometheus 源码中的 scrape\_configs 模块，修改采集间隔从默认的 15 秒改为 60 秒，同时禁用远程存储功能，重启服务后对比两种配置的内存占用和网络流量。
2. 重构 Prometheus 的简体中文翻译，贡献至上游。
3. 将目前不兼容 FreeBSD 的组件完全适配，并将其制作成 Podman 容器。
