【Linux 系统监控】Node Exporter + Prometheus + Grafana

Node Exporter + Prometheus + Grafana

本文档介绍如何在 Ubuntu 24.04 上安装 Node Exporter、Prometheus 和 Grafana。

软件 安装 说明
Node Exporter Github release 包 安装在宿主机上
Prometheus docker 安装 无宿主机依赖要求,用 docker 安装
Grafana docker 安装 无宿主机依赖要求,用 docker 安装

一、Node Exporter

Github node_exporter

(一)下载 release 包

bash 复制代码
wget https://github.com/prometheus/node_exporter/releases/download/v1.11.1/node_exporter-1.11.1.linux-amd64.tar.gz

(二)解压

bash 复制代码
tar -zxvf node_exporter-1.11.1.linux-amd64.tar.gz
bash 复制代码
# 目录中包含 node_exporter 可执行文件
node_exporter-1.11.1.linux-amd64$ ls
LICENSE  node_exporter  NOTICE

(三)移动专属目录

1. 创建专属目录

bash 复制代码
sudo mkdir /opt/node_exporter

2. 复制 node_exporter 可执行文件到专属目录

bash 复制代码
sudo cp ./node_exporter /opt/node_exporter/

3. 给 node_exporter 可执行文件添加执行权限

bash 复制代码
sudo chmod +x /opt/node_exporter/node_exporter

(四)配置 Systemd 服务

1. 创建 Systemd 服务文件

bash 复制代码
sudo nano /etc/systemd/system/node_exporter.service

写入以下内容(注意 ExecStart 的路径):

ini 复制代码
[Unit]
Description=Prometheus Node Exporter
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/opt/node_exporter/node_exporter

[Install]
WantedBy=multi-user.target

2. 创建专用 node_exporter 用户

创建用户
bash 复制代码
sudo useradd --no-create-home --shell /bin/false node_exporter

参数解释:

  • --no-create-home: 不创建用户家目录
  • --shell /bin/false: 将该用户的默认 Shell 设置为 /bin/false,防止用户登录
  • node_exporter: 用户名
读取和执行权限
bash 复制代码
sudo chown -R node_exporter:node_exporter /opt/node_exporter

(五)启动并验证服务

1. 重新加载 Systemd 配置

bash 复制代码
sudo systemctl daemon-reload

2. 启动服务并设置开机自启

bash 复制代码
sudo systemctl enable --now node_exporter

3. 检查运行状态

bash 复制代码
sudo systemctl status node_exporter

(六)验证数据

1. 在浏览器中验证(最直观)

打开浏览器(主机就可以,不需要虚拟机),在地址栏输入:

plaintext 复制代码
http://<您虚拟机的IP地址>:9100/metrics

2. 在终端中验证(最快)

在当前的终端中,执行以下命令:

bash 复制代码
curl -s http://localhost:9100/metrics | head -n 15

如果一切正常,会看到类似下面这样的文本输出,包含大量的 # HELP 和 node_ 开头的指标数据:

plaintext 复制代码
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.9215e-05
go_gc_duration_seconds{quantile="0.25"} 3.921e-05
go_gc_duration_seconds{quantile="0.5"} 8.7665e-05
go_gc_duration_seconds{quantile="0.75"} 0.000221364
go_gc_duration_seconds{quantile="1"} 0.000286378
go_gc_duration_seconds_sum 0.000653832
go_gc_duration_seconds_count 5
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# TYPE go_gc_gogc_percent gauge
go_gc_gogc_percent 100
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# TYPE go_gc_gomemlimit_bytes gauge
go_gc_gomemlimit_bytes 9.223372036854776e+18

二、docker & docker compose

Prometheus 和 Grafana 使用 docker 安装,这里介绍安装 docker 和 docker compose。

(一)安装必要依赖

bash 复制代码
sudo apt update
bash 复制代码
sudo apt install -y ca-certificates curl gnupg

(二)创建密钥环目录并添加 Docker 官方的 GPG 密钥(使用阿里云加速)

bash 复制代码
sudo install -m 0755 -d /etc/apt/keyrings
bash 复制代码
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
bash 复制代码
sudo chmod a+r /etc/apt/keyrings/docker.asc

(三)将 Docker 的 apt 仓库源添加到系统中

bash 复制代码
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

(四)再次更新 apt 索引,并安装 Docker 引擎及 Compose V2 插件

bash 复制代码
sudo apt update
bash 复制代码
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

(五)将当前用户加入 docker 组(免 sudo 执行 docker 命令)

bash 复制代码
sudo usermod -aG docker $USER

(六)验证安装

bash 复制代码
sudo docker --version
bash 复制代码
# 注意:compose 后面是空格,不是连字符
sudo docker compose version

(七)让当前终端立刻生效 docker 组权限(这样后面敲命令就不用一直加 sudo 了)

bash 复制代码
newgrp docker

三、Prometheus

(一)创建目录结构与设置权限

1. 创建主目录和 Prometheus 的专属子目录(包含配置目录和数据目录)

bash 复制代码
sudo mkdir -p /opt/monitoring/prometheus/data

2. 给 Prometheus 的数据目录赋予正确的权限 (容器内是 nobody 用户,UID 65534)

bash 复制代码
sudo chown -R 65534:65534 /opt/monitoring/prometheus/data

3. 进入主工作目录

bash 复制代码
cd /opt/monitoring

(二)编写 Prometheus 配置文件

在 Prometheus 自己的目录下,创建它的配置文件:

bash 复制代码
sudo nano prometheus/prometheus.yml

粘贴以下内容,保存并退出

yaml 复制代码
global:
  scrape_interval: 15s

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

  - job_name: 'node_exporter'
    static_configs:
      # 使用魔法域名跨越网络访问宿主机上的 Node Exporter
      - targets: ['host.docker.internal:9100']

(三)编写 docker-compose.yml (仅包含 Prometheus)

在主目录(monitoring/)下,创建总控文件。注意看 volumes 里的路径,现在它们指向了子文件夹。

bash 复制代码
sudo nano docker-compose.yml

粘贴以下内容,保存并退出:

yaml 复制代码
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    volumes:
      # 注意这里的路径变化:指向了 prometheus 子文件夹
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus/data:/prometheus
    ports:
      - "9090:9090"
    # 核心魔法:让容器能通过 host.docker.internal 访问宿主机
    extra_hosts:
      - "host.docker.internal:host-gateway"

(四)启动 Prometheus

确保还在 monitoring/ 主目录下(也就是 docker-compose.yml 所在的目录),执行:

bash 复制代码
docker compose up -d

第一次运行会下载镜像,看到 Started 即可。

bash 复制代码
/opt/monitoring$ docker compose up -d
[+] up 13/13
 ✔ Image prom/prometheus:latest Pulled                         28.4s
 ✔ Network monitoring_default   Created                         0.8s
 ✔ Container prometheus         Started                        12.9s

(五)验证 Prometheus

确保 Prometheus 已经成功启动

打开浏览器,访问:http://<您的虚拟机IP>:9090/targets

验收标准:

  • 页面能正常打开。
  • 在 "Targets" 列表中,prometheus 状态是绿色的 UP。
  • 最重要的一点:node_exporter 状态也必须是绿色的 UP。
    (如果 node_exporter 是红色的 DOWN,通常是宿主机防火墙拦截了,请在终端执行 sudo ufw allow 9100/tcp 后刷新页面重试。)

四、Grafana

(一)创建目录结构与设置权限

1. 创建主目录和 Grafana 的专属子目录(用于持久化仪表盘/数据)

bash 复制代码
sudo mkdir -p /opt/monitoring/grafana

2. 给 Grafana 的数据目录赋予正确的权限

Grafana 容器内使用 grafana 用户 (UID 472)

bash 复制代码
sudo chown -R 472:472 /opt/monitoring/grafana

(二)编写 docker-compose.yml (追加 Grafana 服务)

打开 compose 文件

bash 复制代码
nano docker-compose.yml

在文件末尾(prometheus 服务后面)添加以下内容:

yaml 复制代码
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - ./grafana:/var/lib/grafana
    depends_on:
      - prometheus
    restart: unless-stopped

(三)启动 Grafana

确保还在 monitoring/ 主目录下(也就是 docker-compose.yml 所在的目录),执行:

bash 复制代码
docker compose up -d

第一次运行会下载镜像,看到 Started 即可。

bash 复制代码
/opt/monitoring$ docker compose up -d
[+] up 14/14
 ✔ Image grafana/grafana:latest Pulled                 158.7s
 ✔ Container prometheus         Running                  0.0s
 ✔ Container grafana            Started                  7.4s

(四)验证 Grafana

打开浏览器,访问:http://<您的虚拟机IP>:3000

验收标准:

  • 页面能正常打开。
  • 登录时,用户名是 admin,密码是admin。

五、Grafana 配置 Prometheus 数据源

1. 点击 Connections ➡️ Add new conncetion ➡️ Prometheus

2. 点击 Add new data source

3. 填写相关数据信息

精简配置:

配置项 当前错误值 正确值 为什么?
Prometheus server URL http://localhost:9090 http://prometheus:9090 ✅ Docker Compose 服务名自动解析为容器 IP
Authentication method No Authentication 保持默认 ✅ 我们没设置 Prometheus 认证
Scrape interval 15s 保持默认 ✅ 与 Prometheus 配置一致

4. 点击 Save & Test

六、Grafana 配置 Dashboards 仪表盘

Grafana dashboards 上有很多可用的仪表盘。在导入界面也有链接可跳转找到心仪的仪表盘。

1. 点击 Dashboards ➡️ New ➡️ Import dashboard

2. 导入 1860 仪表盘

3. 点击 Import

4. 确认并保存(如需 Edit)

如果需要编辑仪表盘,点击 Edit 按钮,进入编辑模式,修改完成后点击 Save 保存。


有关问题

(一)镜像下载网络问题

1. 问题现象

bash 复制代码
/opt/monitoring$ docker compose up -d
[+] up 1/1
 ✘ Image prom/prometheus:latest Error failed to resolve reference "docker.io/prom/prometheus:latest": failed to do request: Head "https://registry-1.docker.io/v2/prom/prometheus/manifests/latest": dial tcp 108.160.172.232:443: connect: connection refused           21.3s
Error response from daemon: failed to resolve reference "docker.io/prom/prometheus:latest": failed to do request: Head "https://registry-1.docker.io/v2/prom/prometheus/manifests/latest": dial tcp 108.160.172.232:443: connect: connection refused

2. 问题原因

典型的网络问题 !错误信息里的 connection refused 和访问 registry-1.docker.io 失败,表明您的虚拟机当前无法直接连接到 Docker Hub 的官方服务器 (这是国内网络环境的常见限制)。

需要给 Docker 配置一个国内镜像加速器 ,让它从国内的代理节点下载镜像。

或者给 Docker 配置代理软件,让它通过代理下载镜像。

3. 解决方法

这里通过配置代理软件来解决。我的代理软件运行在 Windows 宿主机

第一步:创建 Docker 的 systemd 代理配置

在终端执行以下命令,直接通过 echo 把配置写入文件

1. 创建存放 Docker 服务覆盖配置的目录
bash 复制代码
sudo mkdir -p /etc/systemd/system/docker.service.d
2. 将代理配置写入文件 (直接使用 Windows IP 和 代理端口)
bash 复制代码
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<-'EOF'
[Service]
Environment="HTTP_PROXY=http://192.168.1.13:7890"
Environment="HTTPS_PROXY=http://192.168.1.13:7890"
Environment="NO_PROXY=localhost,127.0.0.0/8,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12"
EOF

💡 注意:NO_PROXY 里的 192.168.0.0/16 很重要,它确保了以后 Grafana 容器通过局域网 IP 连接 Prometheus 容器时,不会傻傻地去绕一圈 Windows 代理,而是直接在内网通信。

第二步:重载配置并重启 Docker
bash 复制代码
sudo systemctl daemon-reload
bash 复制代码
sudo systemctl restart docker
第三步:验证代理是否配置成功

执行以下命令检查 Docker 是否已经吃到了代理环境变量:

bash 复制代码
sudo systemctl show --property=Environment docker

(二)docker & docker compose

Docker 是什么?做什么用的?

Docker 是一个开源的应用容器引擎,它是整个容器化生态的"底座"。

做什么用?

它允许开发者把应用程序以及它运行所需的所有依赖(代码、运行环境、系统工具、数据库驱动等)打包成一个轻量级、可移植的 "镜像(Image)" 。这个镜像可以运行在任何安装了 Docker 的机器上运行,运行起来的实例叫做 "容器(Container)"

解决的核心痛点

彻底消灭了"这段代码在我的电脑上明明能跑,怎么到你那里就报错了"的环境不一致问题。

Docker Compose 是什么?做什么用的?

Docker Compose 是建立在 Docker 之上的一个多容器编排工具

做什么用?

在实际开发中,一个完整的项目往往不止一个服务。比如一个典型的Web应用可能包含:前端 Nginx + 后端 Node.js/Java + MySQL 数据库 + Redis 缓存。如果用纯 Docker,需要手动敲4条 docker run 命令,还要手动配置它们之间的网络互通和启动顺序,非常繁琐且容易出错。

解决的核心痛点

它允许你通过一个 YAML 格式的配置文件(通常叫 docker-compose.yml),把整个项目的所有服务、网络、数据卷一次性定义好,然后一键启动/停止整个项目集群。

两者关系

  1. 依赖关系:Docker Compose 是 Docker 的补充和高级封装。没有 Docker,Docker Compose 就无法工作(Compose 底层调用的依然是 Docker 的 API 来创建和管理容器)。
  2. 分工明确
    • Docker 负责"制造和管理单个集装箱"(构建镜像、运行单个容器)。
    • Docker Compose 负责"编排一堆集装箱"(管理多个容器组成的微服务架构)。

核心区别对比

对比维度 Docker Docker Compose
管理对象 单个容器 / 镜像 多个容器组成的应用服务栈
配置文件 Dockerfile(用于定义如何构建单个镜像) compose.yaml(用于定义如何编排多个容器)
启动命令 docker run [一长串参数] [镜像名] docker compose up(自动读取配置,一键启动)
网络管理 需要手动创建网络、配置容器互联 自动为项目创建一个隔离的默认网络,容器间可通过服务名直接互相访问
依赖与顺序 难以控制多个容器的启动先后顺序 支持配置 depends_on,确保数据库等基础服务先于应用服务启动
适用场景 运行单一服务(如单纯跑个 MySQL 或 Nginx 测试) 运行完整的本地开发环境、微服务架构、CI/CD 自动化测试环境

补充说明:命令的演进

网上资料,可能会有两种写法: docker-composedocker compose带横杠空格隔开

  • 过去(V1 版本): docker-compose 是一个用 Python 写的独立脚本需要额外单独安装,命令带横杠。目前已被官方废弃。
  • 现在(V2 版本): docker compose 是用 Go 语言重写的,已经作为原生插件直接集成到了 Docker CLI 中。只要安装了较新的 Docker,就自带这个命令(中间是空格)。

(三)Node Exporter 监控问题

node exporter 如果使用 docker 镜像安装启动,则 node exporter 的监控对象,取决于启动 Docker 容器时的配置方式

简答来说:

  • 如果直接启动(不做特殊配置):它监控的只是 Docker 容器自身 的信息(这通常毫无意义)。
  • 如果做了正确配置:它监控的就是 宿主机 的信息。

为什么默认监控的是 Docker 容器自身?

Node Exporter 采集系统指标(如 CPU、内存、磁盘、网络)的原理,是读取 Linux 系统的虚拟文件系统(主要是 /proc/sys)。

由于 Docker 容器具有 命名空间隔离(Namespace) 特性,容器内部有自己独立的 /proc/sys。如果你只是简单地运行 docker run prom/node-exporter,它读取到的仅仅是这个容器内部的资源使用情况,而不是宿主机的。

如何让 Docker 版 Node Exporter 监控宿主机?

为了让容器内的 Node Exporter 看到宿主机的真实数据,需要在启动时做三件事:

  1. 挂载宿主机的目录到容器内。
  2. 共享网络和 PID 命名空间,让容器能看到宿主机的网络接口和进程。
  3. 通过启动参数告诉 Node Exporter 去读取挂载进来的宿主机路径。
方式一:使用 docker run 命令
bash 复制代码
docker run -d \
  --name node_exporter \
  --restart=unless-stopped \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  -v "/proc:/host/proc:ro" \
  -v "/sys:/host/sys:ro" \
  prom/node-exporter:latest \
  --path.rootfs=/host \
  --path.procfs=/host/proc \
  --path.sysfs=/host/sys
方式二:使用 docker-compose.yml
yaml 复制代码
version: '3.8'
services:
  node_exporter:
    image: prom/node-exporter:latest
    container_name: node_exporter
    restart: unless-stopped
    network_mode: host
    pid: host
    volumes:
      - /:/host:ro,rslave
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
    command:
      - '--path.rootfs=/host'
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'

关键参数原理解析

参数 作用解释
--net="host" 共享网络命名空间 。让 Node Exporter 能采集到宿主机真实的网卡信息(如 eth0bond0)和网络流量,而不是容器虚拟的 eth0
--pid="host" 共享 PID 命名空间。让 Node Exporter 能看到宿主机上所有的进程信息,从而正确统计系统负载(load average)和进程状态。
-v "/proc:/host/proc:ro" 将宿主机的 /proc(包含 CPU、内存、负载等内核信息)以只读方式挂载到容器的 /host/proc
-v "/sys:/host/sys:ro" 将宿主机的 /sys(包含硬件设备、内核模块等信息)以只读方式挂载到容器的 /host/sys
-v "/:/host:ro,rslave" 将宿主机的根目录挂载进去,主要用于采集磁盘/文件系统 的使用情况(如 /dev/sda1 挂载在 / 上的空间使用率)。rslave 确保宿主机后续的挂载事件能传播到容器内。
--path.rootfs=/host 告诉 Node Exporter 程序:"宿主机的根文件系统在 /host 目录下,请去那里读取磁盘信息"。