先想清楚要它回答什么问题
很多人装监控的路径是:听说 Prometheus 是标配 → 拉一套 compose → 打开 Grafana 看见曲线 → 结束。半年后磁盘满了,翻看板才发现那条曲线三天前就开始往上爬,只是没人看。
监控真正要回答的是三个问题,按优先级排:服务还活着吗、资源够用到什么时候、刚才那十分钟发生了什么。第一个问题用一个指标就能答,第二个需要预测,第三个才轮到看板和留存。
所以下面这套栈很小:Prometheus 存时序、node_exporter 采主机、cAdvisor 采容器、Alertmanager 负责把「有事」推到你手机上、Grafana 只在你要查历史时才打开。
compose:四个服务加一个看板
services:
prometheus:
image: prom/prometheus:v3.15.1
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=30d
- --web.enable-lifecycle
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./rules:/etc/prometheus/rules:ro
- prom-data:/prometheus
ports:
- "127.0.0.1:9090:9090"
restart: unless-stopped
node-exporter:
image: prom/node-exporter:v1.12.1
command:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host/root
- --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|run|host)(/.+|)$$
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/host/root:ro,rslave
pid: host
restart: unless-stopped
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.60.6
privileged: true
devices:
- /dev/kmsg
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
restart: unless-stopped
alertmanager:
image: prom/alertmanager:v0.34.1
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports:
- "127.0.0.1:9093:9093"
restart: unless-stopped
volumes:
prom-data:
两个端口都绑在 127.0.0.1,这是故意的:Prometheus 的接口默认没有认证,暴露到公网等于把主机名、容器名、内网拓扑一起送出去。要看,就走 SSH 隧道或者塞进反向代理加一道登录。
注意 node-exporter 那行 mount-points-exclude 里的 $$——compose 会把它解析成单个 $,正好是正则里的行尾锚点。写成 $ 会被 compose 当成变量插值,报一个很难看懂的错。
prometheus.yml:只抓三个目标
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- /etc/prometheus/rules/*.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
scrape_configs:
- job_name: node
static_configs:
- targets: ['node-exporter:9100']
- job_name: cadvisor
static_configs:
- targets: ['cadvisor:8080']
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
先把 Prometheus 自己也抓上。它挂掉的时候,你至少还有它自己的 up 归零的痕迹——虽然这条曲线也没人看了。真正的保险在下一步。
告警规则:四条就够开工
groups:
- name: host-basics
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 抓不到了"
description: "job={{ $labels.job }} 已持续 2 分钟无响应"
- alert: DiskWillFillIn4Hours
expr: |
predict_linear(
node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"}[6h], 4*3600
) < 0
for: 1h
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} {{ $labels.mountpoint }} 预计 4 小时内写满"
- alert: MemoryPressure
expr: |
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.10
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} 可用内存低于 10%"
- alert: ContainerMemoryNearLimit
expr: |
container_memory_working_set_bytes{name!=""}
/ container_spec_memory_limit_bytes{name!=""} > 0.9
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.name }} 内存逼近上限,随时可能被 OOM"
四条规则分别对应三种死法:服务没了、磁盘满了、内存爆了。predict_linear 那条是整套里最值钱的——它不看当前百分比,而是拿最近 6 小时的斜率往后推 4 小时,能提前半天给你留出挪数据的时间。刚重启或刚清理过的机器斜率是负的,不会误报。
第四条要注意 name!=""。cAdvisor 会把 cgroup 层级里的每一层都报出来,不过滤的话父 cgroup 没有 limit,除出来是 NaN,图上会出现一堆断点。
Alertmanager:把「响」送到人手上
route:
receiver: default
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: default
webhook_configs:
- url: 'http://your-notifier:8080/hook'
send_resolved: true
没有现成的通知服务,就用 webhook 转发到自己的脚本、钉钉/飞书机器人或者 Telegram——格式各家不同,Alertmanager 只负责把 JSON 推出去。改完先校验再重启:
amtool check-config /etc/alertmanager/alertmanager.yml
docker compose restart alertmanager
repeat_interval: 4h 是个平衡点。设太短,一个没修的告警每十分钟响一次,三天后你就开始无视它;设太长,真忘了修的时候没人提醒。group_wait 则是给同一批故障的告警留一个合并窗口,避免磁盘满的时候收到十条消息。
Grafana:只做数据源,不做入口
# /etc/grafana/provisioning/datasources/prom.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
数据源用文件声明,别在界面里手点——重装一次就丢的配置,等于没有配置。看板同理,导出的 JSON 放进 provisioning 目录,跟 compose 一起进 git。
Grafana 的定位要摆正:它是「事后查证」的工具,不是告警通道。真出事的时候,人不会盯着看板,只会看手机。
四个坑,踩过都记得
- node-exporter 挂载不全。只挂
/proc不挂/host/root,文件系统指标全是容器自己的 overlay,看着永远不满;pid: host不加,进程数指标也不对。 - cAdvisor 在 cgroup v2 上不全。要新版本,还要
privileged: true和/dev/kmsg。跑在 macOS 的 Docker Desktop 上更别指望,那边根本没有真正的 cgroup。 - 时序数据的磁盘账。15 秒抓一次、几百个序列,一天大约几百 MB。30 天保留意味着几十 G。估算方法:序列数 × 抓取频率 × 保留天数,宁可按两倍留余量。
- 时间不同步。Prometheus 靠时间戳对齐,宿主机的 NTP 漂了几十秒,图上就会出现阶梯状断点,排查半天以为是采集丢了。
先让 up == 0 响起来
这套栈最容易走偏的地方,是把时间花在挑看板主题上。四条规则里有三条可以慢慢调,唯独 InstanceDown 应该第一天就通——它不关心你用什么仪表盘,只回答一个最原始的问题:东西还活着吗。
顺序建议是这样:先让 up == 0 真的能推到你手机上(拿 docker compose stop node-exporter 试一次,看两分钟内有没有收到),再补磁盘预测,最后才折腾看板和留存策略。反过来做,通常的结局是一套漂漂亮亮的仪表盘,配一个从来没响过的告警通道。










暂无评论内容