## 19.1 Prometheus

Prometheus 和 Grafana 是目前最流行的开源监控组合，前者负责数据采集与存储，后者负责数据可视化。

[Prometheus](https://prometheus.io/) 是一个开源的系统监控和报警工具包。它受 Google Borgmon 的启发，由 SoundCloud 在 2012 年创建。

### 19.1.1 架构简介

Prometheus 的主要组件包括：

* **Prometheus Server**：核心组件，负责收集和存储时间序列数据。
* **Exporters**：负责向 Prometheus 暴露监控数据 (如 Node Exporter，cAdvisor)。
* **Alertmanager**：处理报警发送。
* **Pushgateway**：用于支持短生命周期的 Job 推送数据。

### 19.1.2 快速部署

我们可以使用 Docker Compose 快速部署一套 Prometheus + Grafana 监控环境。

本节示例使用了：

* `node-exporter`：采集宿主机指标 (CPU、内存、磁盘、网络等)。
* `cAdvisor`：采集容器指标 (容器 CPU/内存/网络 IO、文件系统等)。

在生产环境中，建议将 Prometheus 的数据目录做持久化，并显式配置数据保留周期。

#### 1. 准备配置文件

创建 `prometheus.yml`：

```yaml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

rule_files:
  - /etc/prometheus/rules.yml
```

#### 2. 编写 Docker Compose 文件

创建 `compose.yaml` (或 `docker-compose.yml`)。下面示例使用的是相对较新的稳定版本。**镜像版本提示**：本示例中 Prometheus、Grafana、node-exporter、cAdvisor 的版本号仅为参考。生产环境部署前，请查阅以下官方资源确认最新推荐版本：
- [Prometheus 官方文档](https://prometheus.io/docs/prometheus/latest/installation/)
- [Grafana 官方发布](https://grafana.com/grafana/download)
- [node-exporter 发布页](https://github.com/prometheus/node_exporter/releases)
- [cAdvisor 发布页](https://github.com/google/cadvisor/releases)

```yaml
services:
  prometheus:
    image: prom/prometheus:v3.11.2
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./rules.yml:/etc/prometheus/rules.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --storage.tsdb.retention.time=15d
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:13.0.1
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    networks:
      - monitoring
    depends_on:
      - prometheus

  node-exporter:
    image: prom/node-exporter:v1.11.1
    ports:
      - "9100:9100"
    networks:
      - monitoring

  cadvisor:
    image: ghcr.io/google/cadvisor:v0.56.2
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    networks:
      - monitoring

networks:
  monitoring:

volumes:
  prometheus_data:
```

#### 3. 启动服务

```bash
$ docker compose up -d
```
启动后，访问以下地址：

* Prometheus: `http://localhost:9090`
* Grafana：`http://localhost:3000` (默认账号密码：admin/admin，首次登录后务必立即修改密码)

### 19.1.3 配置 Grafana 面板

1. 在 Grafana 中添加 Prometheus 数据源，URL 填写 `http://prometheus:9090`。
2. 导入现成的 Dashboard 模板，例如 [Node Exporter Full](https://grafana.com/grafana/dashboards/1860) (ID：1860) 和 [Docker Container](https://grafana.com/grafana/dashboards/193) (ID：193)。

这样，你就拥有了一个直观的容器监控大屏。

### 19.1.4 生产要点与告警闭环

完成部署后，建议补齐以下生产要点。

#### 指标采集的“最小闭环”

1. 在 Prometheus 页面打开 **Status -> Targets**，确认 `prometheus`、`node-exporter`、`cadvisor` 的 `State` 均为 `UP`。
2. 在 **Graph** 中尝试查询：

   * `up`
   * `rate(container_cpu_usage_seconds_total[5m])`

3. 在 Grafana Dashboard 中重点关注：

   * 宿主机 CPU/Load/内存/磁盘
   * 容器 CPU/内存使用率、容器重启次数

如果你发现“面板为空”，通常不是 Grafana 的问题，而是 Prometheus 没抓到数据或查询标签与 Dashboard 不匹配。

#### 常见问题排查

* **Target down**：检查容器网络是否互通，端口是否暴露到同一网络，以及 exporter 是否在容器内正常监听。
* **cAdvisor 无数据或报错**：确认挂载了 Docker 目录与宿主机的 `/sys`、`/var/run` 等路径，并确保宿主机上 Docker 运行正常。
* **指标缺失**：确认你的 Docker/内核版本与 cAdvisor 兼容；对于 containerd 等运行时，采集方式会不同。

#### 关键指标速查：节点/容器

在生产环境排障时，建议优先关注下面几类指标，并在 Grafana 面板中建立对应的常用视图。

* **节点 CPU 使用率**：`100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)`
* **节点内存使用率**：`(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100`
* **节点磁盘空间使用率**：`(1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"})) * 100`
* **容器 CPU**：`sum by (name) (rate(container_cpu_usage_seconds_total[5m]))`
* **容器内存**：`sum by (name) (container_memory_working_set_bytes)`

说明：不同版本的 cAdvisor/Docker 对 label 命名可能存在差异 (如 `name`、`container`、`container_name`)，如果查询为空，建议先用 `label_values(container_cpu_usage_seconds_total, __name__)` 或在 Prometheus 的图形界面查看可用 label。

#### Targets down 排错清单

当 **Status -> Targets** 出现 `DOWN` 时，建议按以下顺序排查：

1. **网络连通性**：Prometheus 容器是否能解析并访问目标 (同一 Docker network、DNS、端口)。
2. **端口/路径**：确认 exporter 监听端口与 Prometheus 配置一致；必要时在 Prometheus 容器内 `curl http://node-exporter:9100/metrics`。
3. **权限/挂载**：cAdvisor 需要访问宿主机 `/sys`、`/var/lib/docker` 等挂载路径，缺失会导致指标不全或报错。
4. **时间问题**：宿主机与容器时间偏差过大可能导致“数据看起来断档”，需要检查 NTP/时区配置。
5. **目标本身异常**：确认 exporter 容器是否在重启，查看 `docker logs`。

#### Alertmanager 告警建议

生产环境建议引入 Alertmanager 做告警聚合与路由，并在 Prometheus 中配置 `alerting` 与 `rule_files`。

为了保持“最小告警闭环”，建议至少覆盖两类告警：

* **采集链路告警**：例如 `up == 0`，用于发现 exporter 或网络故障。
* **资源风险告警**：例如节点磁盘空间不足，用于提前发现容量风险。

##### 1. 准备告警规则文件

创建 `rules.yml`：

```yaml
groups:
  - name: docker_practice
    rules:
      - alert: PrometheusTargetDown
        expr: up == 0
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Prometheus 抓取目标不可达"
          description: "Job={{ $labels.job }}, Instance={{ $labels.instance }}"

      - alert: HostDiskSpaceLow
        expr: |
          (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) < 0.10
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "磁盘可用空间不足"
          description: "Instance={{ $labels.instance }}, Mountpoint={{ $labels.mountpoint }}"
```
说明：这里的规则是“可用空间低于 10%”的阈值告警，并非“未来 24 小时写满”的预测。生产环境建议针对特定文件系统与挂载点做更精确的过滤。

##### 2. 配置 Prometheus 加载规则并接入 Alertmanager

修改 `prometheus.yml`，增加：

```yaml
rule_files:
  - /etc/prometheus/rules.yml

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]
```
并在 Compose 中挂载规则文件。

##### 3. 部署 Alertmanager

创建 `alertmanager.yml`：

```yaml
route:
  receiver: default

receivers:
  - name: default
    webhook_configs:
      - url: http://example.com/webhook
```
再在 `compose.yaml` 增加服务：

```yaml
  alertmanager:
    image: prom/alertmanager:v0.32.0
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "9093:9093"
    networks:
      - monitoring
```
生产环境中，建议将告警发送到可追踪的渠道 (如 IM 机器人、事件平台、工单系统)，并在告警中附带 Dashboard 链接与排障入口，避免告警成为噪声。

#### 建议的文件清单

为了避免示例难以复现，建议在同一目录下准备以下文件：

* `compose.yaml`：Prometheus、Grafana、exporters、Alertmanager 的部署文件
* `prometheus.yml`：Prometheus 抓取配置与告警配置
* `rules.yml`：告警规则
* `alertmanager.yml`：告警路由与接收器配置
