【前情提要】
node_exporter 装好了,机器的“体检报告”能看了。老周说:“现在装 Prometheus,让它去取报告。”小林打开 Prometheus 官网,准备下载。但他不知道,prometheus.yml 的 YAML 缩进、scrape_configs 的配置、up 指标的验证,每一个都可能让他折腾。
一、Prometheus 是“每天去体检的人”
早上到工位,小林打开浏览器,访问 http://localhost:9100/metrics,看着满屏的指标。
老周走过来:“看得挺起劲啊。”
“周哥,这些指标是挺好,但我总不能每次都手动 curl 吧?而且我关了浏览器,这些数据就没了。”
“所以你要装 Prometheus。”老周说,“node_exporter 是体检医生,它把报告放在桌上。Prometheus 是那个每天准时去取报告的人。它把报告存起来,你随时能查历史。”
“那它多久取一次?”
“默认 15 秒。”老周说,“你配好之后,它每 15 秒去 9100 端口拉一次数据,存到自己的数据库里。”
“那它存哪?”
“本地磁盘。”老周说,“默认存 15 天。超过 15 天的数据,自动删除。你也可以配更长,但数据量会大。”
小林点点头,打开 Prometheus 官网。
二、安装 Prometheus
“Ubuntu 上装 Prometheus,跟 node_exporter 一样,有两种方式。”老周说,“apt 和二进制。”
“apt 简单,用 apt。”
“这次我建议你用二进制。”老周说。
“为啥?”
“因为 apt 源里的 Prometheus 版本可能比较旧,而 Prometheus 更新快。而且 apt 装的 Prometheus 配置文件路径和服务名,跟官方文档有时候对不上。你以后工作中,Prometheus 基本都是二进制部署。”老周说,“正好练一下。”
小林打开 Prometheus 官网的下载页面,找到 Linux ARM64 版本。
“先看架构。”
uname -m
输出:
aarch64
“下 ARM64 的。”老周说。
小林下载:
wget https://github.com/prometheus/prometheus/releases/download/v2.x.x/prometheus-2.x.x.linux-arm64.tar.gz
解压:
tar -xzvf prometheus-2.x.x.linux-arm64.tar.gz
进入目录:
cd prometheus-2.x.x.linux-arm64
ls
输出:
console_libraries/
consoles/
LICENSE
NOTICE
prometheus
promtool
prometheus.yml
“看到了吗?”老周说,“prometheus 是主程序,promtool 是配置检查工具,prometheus.yml 是配置文件。就这三个你要关心的。”
“那 console_libraries 和 consoles 呢?”
“内置的 Web 控制台,基本不用管。你以后用 Grafana 展示,不用 Prometheus 自带的。”
“那我把它们放哪?”
“标准做法:程序放 /usr/local/bin/,配置放 /etc/prometheus/,数据放 /var/lib/prometheus/。”
小林照做:
sudo mv prometheus promtool /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo mv prometheus.yml /etc/prometheus/
sudo mv consoles console_libraries /etc/prometheus/
“验证一下。”
prometheus --version
输出:
prometheus, version 2.x.x (branch: HEAD, revision: ...)
build user: root@...
build date: ...
go version: go1.x.x
platform: linux/arm64
“成了。”小林说。
三、prometheus.yml:配置文件
“现在看配置文件。”老周说。
cat /etc/prometheus/prometheus.yml
输出:
# my global config
global:
scrape_interval: 15s
evaluation_interval: 15s
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
“这是默认配置。”老周说,“它只监控自己。你现在要加一个目标:node_exporter。”
“怎么加?”
“在 scrape_configs 下面加一段。”
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "node"
static_configs:
- targets: ["localhost:9100"]
“一行一行解释。”老周说。
job_name:任务名。你可以随便起,但要有意义。prometheus表示监控自己,node表示监控节点。static_configs:静态配置。表示目标列表是写死的。targets:目标列表。localhost:9100就是node_exporter。
“那如果我有十台机器呢?”
“targets 里写十行。”
targets: ["192.168.1.101:9100", "192.168.1.102:9100", "192.168.1.103:9100"]
“但这样管理麻烦。”老周说,“Prometheus 支持服务发现,可以自动发现目标。但你现在入门,用静态配置就够了。”
“那 scrape_interval 呢?”
“全局的采集间隔,默认 15 秒。你也可以在 job_name 下面单独配,覆盖全局。”
- job_name: "node"
scrape_interval: 30s
static_configs:
- targets: ["localhost:9100"]
“这样 node 任务每 30 秒采集一次,其他任务还是 15 秒。”
小林记下:
global.scrape_interval:全局采集间隔scrape_configs:采集目标列表job_name:任务名static_configs.targets:静态目标列表- 每个
job可以覆盖全局scrape_interval
四、YAML 缩进:Prometheus 的“第一坑”
“现在保存,启动。”老周说。
小林用 nano 编辑:
sudo nano /etc/prometheus/prometheus.yml
加完 node 任务,保存,退出。
“启动之前,先检查配置。”老周说,“用 promtool。”
promtool check config /etc/prometheus/prometheus.yml
输出:
Checking /etc/prometheus/prometheus.yml
SUCCESS: 1 rule files found
“等等,1 个规则文件?我没配规则文件啊。”小林说。
“它把默认的算进去了。没事,SUCCESS 就是通过。”老周说,“如果你缩进写错了,它会报错。”
小林故意把 targets 那行少缩进两个空格:
scrape_configs:
- job_name: "node"
static_configs:
- targets: ["localhost:9100"]
再次检查:
promtool check config /etc/prometheus/prometheus.yml
输出:
Checking /etc/prometheus/prometheus.yml
FAILED: cannot unmarshal config: yaml: line 20: did not find expected key
“看到了吗?”老周说,“YAML 对缩进极其敏感。- targets 和 static_configs 必须对齐,或者缩进两个空格。你少一个空格,它就报错。”
小林改回来:
scrape_configs:
- job_name: "node"
static_configs:
- targets: ["localhost:9100"]
再次检查:
promtool check config /etc/prometheus/prometheus.yml
输出:
SUCCESS
“记住,”老周说,“YAML 只用空格,不用 Tab。同一层级缩进必须一致。- 和上一行的键要对齐,或者多缩进两个空格。 你以后写 YAML,先 promtool check,再启动。”
小林在笔记本上写下:
- YAML 缩进用空格,不用 Tab
- 同一层级缩进一致
-列表项和父键对齐,或多缩进- 改完配置先
promtool check config
五、启动 Prometheus
“配置没问题,现在启动。”老周说。
“怎么启动?systemd?”
“对。但二进制安装的话,systemd 服务文件要自己写。”老周说,“我教你写一个。”
sudo nano /etc/systemd/system/prometheus.service
写入:
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
[Install]
WantedBy=multi-user.target
“这段啥意思?”小林问。
“ExecStart 是启动命令。--config.file 指定配置文件,--storage.tsdb.path 指定数据目录,--web.console.* 指定控制台模板。”老周说,“你以后改配置,改这几个参数就行。”
“那 User=prometheus 是啥?”
“哦,我忘了,得先创建 prometheus 用户。”
sudo useradd --no-create-home --shell /bin/false prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
“现在启动。”
sudo systemctl daemon-reload
sudo systemctl start prometheus
sudo systemctl status prometheus
输出:
● prometheus.service - Prometheus
Loaded: loaded (/etc/systemd/system/prometheus.service; disabled; vendor preset: enabled)
Active: active (running) since ...
“active (running),成了。”小林说。
“设个开机自启。”
sudo systemctl enable prometheus
“现在验证端口。”
sudo ss -lntp | grep 9090
输出:
LISTEN 0 4096 *:9090 *:* users:(("prometheus",pid=5678,fd=7))
“9090 端口在监听。”老周说,“打开浏览器,访问 http://localhost:9090。”
小林在 Ubuntu 浏览器里打开。Prometheus 的 Web UI 出现了,顶部是查询框,下面是菜单。
“这就是 Prometheus 的界面。”老周说,“你以后配 Grafana,数据源就是它。”
六、验证 up 指标
“现在验证最重要的一件事。”老周说,“Prometheus 到底有没有拉到数据。”
“怎么看?”
“在查询框里输入 up,点 Execute。”
小林输入 up,回车。
输出:
up{instance="localhost:9090", job="prometheus"} 1
up{instance="localhost:9100", job="node"} 1
“看到了吗?”老周说,“两条 up,都是 1。1 表示目标在线,0 表示目标离线。”
“那如果 node_exporter 挂了,会怎样?”
“你试试。”老周说。
小林停掉 node_exporter:
sudo systemctl stop prometheus-node-exporter
等 15 秒,刷新 Prometheus 页面,再次查询 up。
输出:
up{instance="localhost:9090", job="prometheus"} 1
up{instance="localhost:9100", job="node"} 0
“看到了吧?node 的 up 变成 0 了。”老周说,“这就是 Prometheus 的‘目标存活检测’。你以后配告警,第一件事就是配 up == 0。”
“那它怎么知道目标挂了?”
“拉取失败。”老周说,“Prometheus 每 15 秒去 9100 拉一次,拉不到就标记为 0。连续失败几次,up 一直是 0。”
小林重新启动 node_exporter:
sudo systemctl start prometheus-node-exporter
再等 15 秒,查询 up,node 变回 1。
“这就是监控的基本闭环。”老周说,“Prometheus 拉数据,up 告诉你目标在不在,up == 0 触发告警。”
小林记下:
up指标:1在线,0离线up{job="node"}:查看node任务的目标状态up == 0:目标离线,是告警的基础
七、排错挑战:Prometheus 启动失败
下午,小林想改一下 prometheus.yml,把 scrape_interval 从 15 秒改成 10 秒。
他改完保存,重启:
sudo systemctl restart prometheus
输出:
Job for prometheus.service failed because the control process exited with error code.
See "systemctl status prometheus.service" and "journalctl -xe" for details.
“啥?”小林懵了。
他检查状态:
sudo systemctl status prometheus
输出:
● prometheus.service - Prometheus
Active: failed (Result: exit-code)
“启动失败了。”小林说。
“看日志。”
sudo journalctl -u prometheus -n 20
输出:
level=error msg="Error loading config" err="yaml: line 8: did not find expected key"
“YAML 第 8 行。”老周说,“你改了啥?”
小林打开配置:
sudo nano /etc/prometheus/prometheus.yml
看第 8 行:
global:
scrape_interval: 10s
evaluation_interval: 15s
“evaluation_interval 多了一个空格。”小林说。
“对。”老周说,“scrape_interval 和 evaluation_interval 是同层级,缩进必须一样。你多了一个空格,YAML 解析失败,Prometheus 启动失败。”
小林改回来:
global:
scrape_interval: 10s
evaluation_interval: 15s
“记住,改配置前先 promtool check。”
promtool check config /etc/prometheus/prometheus.yml
输出:
SUCCESS
sudo systemctl restart prometheus
sudo systemctl status prometheus
输出:
Active: active (running)
“回来了。”小林松了口气。
排错思路总结:
- Prometheus 启动失败,先看
systemctl status prometheus。 - 如果
failed,看journalctl -u prometheus -n 20。 - 日志显示
Error loading config,说明 YAML 写错了。 - 用
promtool check config /etc/prometheus/prometheus.yml定位错误行。 - 修正缩进,再
promtool check,通过后restart。 - 永远先
promtool check,再restart。
“记住,”老周说,“YAML 是 Prometheus 最常见的坑。 你以后写配置,眼睛盯着缩进,别用 Tab,改完先 promtool check。这三条做到,能少 90% 的启动失败。”
八、练习
- 练习一:用二进制方式安装 Prometheus,创建 systemd 服务,启动并验证
9090端口监听。在浏览器访问http://localhost:9090,确认 Web UI 正常显示。 - 练习二:修改
prometheus.yml,添加node任务,目标为localhost:9100。用promtool check config检查通过后,重启 Prometheus。在 Web UI 查询up,确认两个目标都是1。 - 练习三:停掉
node_exporter,等待 15 秒,查询up{job="node"},确认值为0。重新启动node_exporter,再次查询,确认恢复为1。
参考答案
练习一:
wget https://github.com/prometheus/prometheus/releases/download/v2.x.x/prometheus-2.x.x.linux-arm64.tar.gz
tar -xzvf prometheus-2.x.x.linux-arm64.tar.gz
cd prometheus-2.x.x.linux-arm64
sudo mv prometheus promtool /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo mv prometheus.yml /etc/prometheus/
sudo mv consoles console_libraries /etc/prometheus/
sudo useradd --no-create-home --shell /bin/false prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
sudo nano /etc/systemd/system/prometheus.service
服务文件内容参考正文。
sudo systemctl daemon-reload
sudo systemctl start prometheus
sudo systemctl enable prometheus
sudo systemctl status prometheus
sudo ss -lntp | grep 9090
浏览器访问 http://localhost:9090。
练习二:
sudo nano /etc/prometheus/prometheus.yml
添加:
- job_name: "node"
static_configs:
- targets: ["localhost:9100"]
promtool check config /etc/prometheus/prometheus.yml
sudo systemctl restart prometheus
Web UI 查询 up,输出:
up{instance="localhost:9090", job="prometheus"} 1
up{instance="localhost:9100", job="node"} 1
练习三:
sudo systemctl stop prometheus-node-exporter
# 等 15 秒
Web UI 查询 up{job="node"},输出 0。
sudo systemctl start prometheus-node-exporter
# 等 15 秒
Web UI 再次查询,输出 1。
九、下集预告
Prometheus 装好了,up 指标也会看了。老周说:“现在你能看到数据了,但 PromQL 才是你真正要学的。没有 PromQL,你只能看 up。”小林打开 Prometheus 查询框,准备学 PromQL。但他不知道,rate()、sum by()、avg by(),每一个函数都有讲究。
下一集:《PromQL 入门:用“查询语言”问机器问题》