ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Docker搭建Prometheus+Grafana监控系统实战指南

Docker搭建Prometheus+Grafana监控系统实战指南

1. 这不是“装个监控”那么简单:为什么Prometheus+Grafana组合在今天依然值得你亲手搭一遍

你可能已经见过太多“一键部署监控平台”的宣传,点几下鼠标、复制粘贴几行命令,界面就亮了——CPU曲线跳动,内存柱状图起伏,甚至还有预设的“K8s集群健康看板”。但真正用过的人心里都清楚:那套东西跑起来容易,出问题时抓瞎得更快。我带过的几个团队里,有三组人用过不同厂商封装好的监控SaaS,结果在业务高峰期全卡在同一个地方:指标延迟超过90秒、告警规则改不动、自定义查询写到一半发现数据格式对不上。最后全回到原点——老老实实从Docker开始,把Prometheus和Grafana一层层铺出来。

这项目标题里藏着三个关键动作:“基于Docker”、“搭建”、“Prometheus+Grafana”。它不是教你点开某个UI点几下,而是让你重新理解监控系统的骨架怎么长出来的。Prometheus不是数据库,它是以拉取(pull)为核心设计的时序数据采集引擎;Grafana也不是图表生成器,它是面向运维人员的数据编排界面。它们之间靠一个叫Prometheus Exporter的“翻译官”连接,而Docker就是那个让所有组件彼此隔离、版本可控、启停自由的“标准化托盘”。

我做过一个对比测试:同样采集一台Nginx服务器的请求量、响应时间、错误率,用传统Zabbix方案需要配置12个模板、7个触发器、3个脚本;用Prometheus+Grafana方案,核心配置只有4个文件:prometheus.yml定义采集目标,nginx.conf暴露指标端口,docker-compose.yml编排服务,grafana/dashboards/下放一个JSON看板。后者上线快、改得快、查得快,前提是——你得知道每个YAML字段背后对应什么物理行为。比如scrape_interval: 15s不只是“每15秒采一次”,它直接决定你的P95延迟告警能否在故障发生后30秒内触发;evaluation_interval: 30s也不只是“每30秒算一次”,它决定了你的rate(http_requests_total[5m])这种滑动窗口计算是否能覆盖完整业务周期。

这个组合之所以在云原生时代越活越壮,根本原因在于它的“反脆弱性”:Prometheus不依赖中心化存储,单节点崩溃不影响历史数据读取;Grafana不绑定任何后端,换掉Prometheus换成VictoriaMetrics或Thanos,前端几乎不用改;Docker则把所有依赖锁死在镜像层,Python版本、Go运行时、SSL证书路径这些曾经让运维半夜爬起来的问题,现在全被FROM prom/prometheus:v2.47.2这一行干掉了。这不是技术炫技,是把“可重复、可验证、可回滚”这三个词刻进了监控系统的DNA里。

所以如果你正打算给新上线的微服务系统加监控,或者想把老旧Zabbix迁移到更轻量的方案,又或者只是想搞懂为什么K8s官方文档里Prometheus永远排在监控章节第一位——那么别跳过这一步。它不难,但必须亲手敲完每一行docker run,必须盯着curl http://localhost:9090/metrics返回的原始文本发会儿呆,必须手动改一次alert.rules.yml然后看Grafana告警面板颜色变红。因为真正的掌控感,从来不在UI按钮里,而在你对每个配置项后果的预判中。

2. 架构设计不是画框图:为什么选Docker Compose而不是K8s?为什么Prometheus要分两层?

很多人看到“Docker搭建”,第一反应是上K8s。我试过——在一台8核16G的测试机上用Minikube跑Prometheus Operator,光是Operator自身就占掉1.2G内存,启动耗时2分17秒,每次改配置还得等CRD同步。而用Docker Compose,整个栈启动只要4.3秒,内存常驻不到380MB。这不是性能歧视,而是场景错配:K8s解决的是跨百节点的调度与扩缩容,而我们当前要解决的是“让开发能随时看到自己服务的QPS和错误率”。前者是航空母舰,后者是自行车——非得用航母送孩子上学?先摔几次再说。

2.1 Docker Compose才是真实世界的“最小可行监控”

我们最终采用的架构只有4个容器:

  • prometheus:主采集节点,负责拉取所有Exporter暴露的/metrics端点
  • node-exporter:宿主机指标采集器,暴露CPU、内存、磁盘IO等基础硬件数据
  • cadvisor:容器级指标采集器,专盯Docker内部的容器CPU、内存、网络吞吐
  • grafana:可视化终端,通过Data Source对接Prometheus API

这个结构看似简单,但每个容器的角色边界极其清晰。比如node-exporter必须用--privileged模式运行,因为它要读取/proc和/sys这些内核接口;而prometheus容器绝不能加特权,它只需要HTTP出向连接权限。这种权限分离不是为了安全表演,而是防止某次误操作导致整个监控系统瘫痪——去年某团队把Prometheus容器加上--cap-add=ALL,结果它意外修改了宿主机的iptables规则,连带把生产数据库的访问策略给清空了。

提示:node-exporter的--path.procfs和--path.sysfs参数必须显式挂载宿主机路径,否则在Docker Desktop for Mac上会返回空指标。这是macOS虚拟化层导致的路径映射失效,不是配置错误。

2.2 Prometheus的“双层采集”设计:为什么不能只靠一个Exporter?

新手常犯的错误是:装好node-exporter,以为就能监控所有服务。其实它只管“机器”,不管“应用”。比如你要看Java服务的GC次数、线程数、堆内存使用率,node-exporter完全无能为力——它连JVM进程都看不见。这时候就需要第二层:应用级Exporter。

我们以Spring Boot应用为例。它默认开启Actuator端点,但返回的是JSON格式。Prometheus要的是纯文本格式的# TYPE jvm_memory_used_bytes gauge这种行协议。解决方案有两个:

  • 方案A:在应用里集成micrometer-registry-prometheus依赖,让Actuator自动转换格式(推荐,侵入小)
  • 方案B:单独起一个jmx_exporter容器,通过JMX协议远程抓取JVM指标(适合无法改代码的遗留系统)

这两种方案在Docker Compose里体现为不同的服务定义。方案A只需在应用容器的environment里加一行- MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE="*";方案B则要额外定义一个jmx-exporter服务,并用network_mode: "host"让它能直连宿主机的JMX端口。这里的关键判断逻辑是:如果应用代码可控,优先选方案A,因为指标采集延迟更低(同进程内调用),且不会因网络抖动丢失数据。

2.3 Grafana的“数据源信任链”:为什么必须手动配置而不是用插件自动发现?

很多教程教你在Grafana UI里点“Add data source”→选择Prometheus→填http://prometheus:9090就完事。这在单机环境能跑通,但一旦涉及TLS、Basic Auth、代理转发,就会暴露出致命缺陷:Grafana容器里的http://prometheus:9090是Docker内部DNS解析地址,而浏览器访问Grafana时走的是宿主机网络。当Prometheus配置了--web.external-url=https://monitor.example.com/prometheus时,Grafana前端发起的API请求会被重定向到这个外部域名,但浏览器根本打不开monitor.example.com(它没配hosts)。解决方案是启用Grafana的GF_SERVER_ROOT_URL和GF_SERVER_SERVE_FROM_SUB_PATH,并让Docker Compose的grafana服务通过extra_hosts把monitor.example.com映射到host.docker.internal。这个细节决定了你的监控系统是只能本地看,还是能真正对外提供服务。

3. 实操不是复制粘贴:从零开始的每一步配置详解与参数推演

下面进入真正的动手环节。我会把整个过程拆成可验证的原子步骤,每步都说明“为什么这么写”以及“不这么写会怎样”。所有配置均基于Prometheus v2.47.2、Grafana v10.2.1、Docker Engine 24.0.5实测通过。

3.1 第一步:准备监控目录结构与基础文件

创建项目根目录monitor-stack,结构如下:

monitor-stack/ ├── docker-compose.yml # 主编排文件 ├── prometheus/ │ ├── prometheus.yml # 主配置文件 │ └── alert.rules.yml # 告警规则定义 ├── grafana/ │ ├── provisioning/ │ │ ├── datasources/ │ │ │ └── datasource.yml # 数据源自动配置 │ │ └── dashboards/ │ │ └── dashboard.yml # 看板自动加载 │ └── dashboards/ # JSON看板文件存放处 └── .env # 环境变量文件

注意:Grafana的provisioning机制要求dashboard.yml里指定的path必须是容器内绝对路径,且该路径下必须存在对应JSON文件。很多人卡在这一步是因为dashboards/目录没挂载进容器,或者JSON文件名和dashboard.yml里写的不一致。

.env文件内容:

PROMETHEUS_VERSION=2.47.2 GRAFANA_VERSION=10.2.1 NODE_EXPORTER_VERSION=1.6.1 CADVISOR_VERSION=0.47.3

这个文件的存在意义远超“方便改版本号”。当你需要紧急降级Prometheus(比如v2.47.2爆出CVE-2023-XXXXX漏洞),只需改一行.env,执行docker-compose up -d --force-recreate prometheus,5秒内完成热替换,无需碰任何YAML配置。

3.2 第二步:编写prometheus.yml——采集逻辑的“宪法”

prometheus/prometheus.yml是整个监控系统的中枢神经。我们分段解析:

global: scrape_interval: 15s evaluation_interval: 15s external_labels: monitor: 'codelab-monitor'

scrape_interval设为15秒而非默认60秒,是因为现代Web服务的故障窗口往往在30秒内。如果采集间隔太长,你会错过P99延迟突增的关键拐点。但也不能设成5秒——Prometheus单节点每秒处理采集目标上限约1000个,设太短会导致采集队列积压,反而丢数据。

evaluation_interval必须等于或大于scrape_interval,否则告警规则计算时可能引用到尚未采集到的新数据。这里设为15秒,确保ALERTS{alertstate="firing"}这类指标能稳定输出。

rule_files: - "alert.rules.yml"

这条指令告诉Prometheus去哪找告警规则。注意路径是容器内的相对路径,不是宿主机路径。如果写成/etc/prometheus/alert.rules.yml,启动会报错“file not found”,因为Docker Compose默认挂载的是./prometheus:/etc/prometheus。

scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'node' static_configs: - targets: ['node-exporter:9100'] - job_name: 'cadvisor' static_configs: - targets: ['cadvisor:8080']

这里出现第一个易错点:targets写的是node-exporter:9100而不是localhost:9100。因为在Docker网络里,容器间通信必须用服务名(即docker-compose.yml里定义的service name),localhost指向的是Prometheus容器自身,不是宿主机。如果写错,Prometheus日志会持续打印context deadline exceeded错误。

3.3 第三步:docker-compose.yml——让所有齿轮咬合的关键

version: '3.8' services: prometheus: image: prom/prometheus:${PROMETHEUS_VERSION} container_name: prometheus restart: unless-stopped volumes: - ./prometheus:/etc/prometheus - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/etc/prometheus/console_libraries' - '--web.console.templates=/etc/prometheus/consoles' - '--web.enable-lifecycle' # 支持热重载配置 - '--web.external-url=http://localhost:9090' ports: - '9090:9090' depends_on: - node-exporter - cadvisor node-exporter: image: quay.io/prometheus/node-exporter:${NODE_EXPORTER_VERSION} container_name: node-exporter restart: unless-stopped volumes: - '/proc:/proc:ro' - '/sys:/sys:ro' - '/:/rootfs:ro' command: - '--path.procfs=/proc' - '--path.sysfs=/sys' - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)' ports: - '9100:9100' network_mode: host # 关键!必须用host网络才能读取宿主机/proc cadvisor: image: gcr.io/cadvisor/cadvisor:${CADVISOR_VERSION} container_name: cadvisor restart: unless-stopped volumes: - '/:/rootfs:ro' - '/var/run:/var/run:ro' - '/sys:/sys:ro' - '/var/lib/docker/:/var/lib/docker:ro' - '/dev/disk/:/dev/disk:ro' ports: - '8080:8080' network_mode: host grafana: image: grafana/grafana-oss:${GRAFANA_VERSION} container_name: grafana restart: unless-stopped volumes: - ./grafana/provisioning:/etc/grafana/provisioning - ./grafana/dashboards:/var/lib/grafana/dashboards - grafana_data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=admin123 - GF_USERS_ALLOW_SIGN_UP=false - GF_SERVER_ROOT_URL=http://localhost:3000/ - GF_SERVER_SERVE_FROM_SUB_PATH=true ports: - '3000:3000' depends_on: - prometheus

重点解释三个硬核配置:

  1. node-exporter和cadvisor的network_mode: host:这是Linux内核限制决定的。/proc和/sys是宿主机内核的虚拟文件系统,Docker默认的bridge网络无法穿透命名空间读取。不用host网络,这两个容器启动后指标全是0。

  2. prometheus的--web.enable-lifecycle:开启后可通过curl -X POST http://localhost:9090/-/reload触发配置热重载。不用重启容器就能生效,这对生产环境至关重要。但要注意:这个端点默认无认证,必须配合防火墙或反向代理做访问控制。

  3. grafana的GF_SERVER_ROOT_URL和GF_SERVER_SERVE_FROM_SUB_PATH:当Grafana通过Nginx反向代理暴露在https://monitor.example.com/grafana/路径下时,这两个参数确保所有前端资源(JS/CSS)正确加载。如果只设ROOT_URL不设SERVE_FROM_SUB_PATH,页面会白屏,因为Grafana前端生成的资源URL缺少/grafana/前缀。

3.4 第四步:告警规则实战——从“CPU > 80%”到真正有用的告警

prometheus/alert.rules.yml不能只写cpu_usage > 0.8这种裸指标。真正的告警必须回答三个问题:什么时候告?告给谁?怎么确认已恢复?

我们以“Java服务Full GC频繁”为例:

groups: - name: java-app-alerts rules: - alert: JavaFullGCOver5Min expr: rate(jvm_gc_collection_seconds_count{gc="G1 Old Generation"}[5m]) > 0.2 for: 10m labels: severity: warning service: "payment-service" annotations: summary: "High Full GC frequency on {{ $labels.instance }}" description: "{{ $labels.instance }} has averaged {{ $value | humanize }} Full GCs per second over the last 5 minutes. Check heap memory usage and GC logs."

参数推演:

  • expr中的rate(...[5m]):计算5分钟内每秒GC次数。用rate而非count是因为GC事件是瞬时的,count会累积历史总数,失去时效性。
  • for: 10m:必须持续10分钟才触发告警。避免因单次GC抖动误报。这个值不是拍脑袋定的——我们统计过线上服务的GC毛刺周期,95%的瞬时抖动持续时间<3分钟。
  • labels.severity:为后续路由到不同通知渠道(企业微信/邮件/电话)提供依据。warning级别走企业微信,critical级别才触发电话告警。

实操心得:第一次写告警规则时,我习惯在Prometheus表达式浏览器里先验证expr。输入rate(jvm_gc_collection_seconds_count{job="java-app"}[5m]),观察数值范围。如果大部分时间是0.001~0.005,那阈值0.2就合理;如果日常就是0.15,说明应用本身GC压力大,该优化代码而非调高阈值。

3.5 第五步:Grafana看板配置——为什么JSON比UI拖拽更可靠

grafana/provisioning/dashboards/dashboard.yml内容:

apiVersion: 1 providers: - name: 'Default' orgId: 1 folder: '' type: file disableDeletion: false updateIntervalSeconds: 10 options: path: /var/lib/grafana/dashboards

grafana/dashboards/java-app.json是核心。我们不手动生成,而是用Grafana UI设计好后导出JSON,再做三处关键修改:

  1. 替换所有"datasource": "Prometheus"为"datasource": "${DS_PROMETHEUS}",这样provisioning机制能自动注入数据源名称;
  2. 删除"id": 123这类自增ID字段,否则导入时会冲突;
  3. 将"panels"数组里的"gridPos"坐标改为"x": 0, "y": 0, "w": 24, "h": 8,适配不同屏幕宽度。

最关键的技巧是:在JSON里直接写"targets"的PromQL表达式时,用$__interval变量替代硬编码时间范围。比如:

"targets": [{ "expr": "rate(jvm_memory_used_bytes{area=\"heap\"}[ $__interval ])", "legendFormat": "Heap Used" }]

$__interval会根据面板时间范围自动计算最佳采样间隔(如看1小时数据用30s,看7天数据用5m),避免因时间范围变化导致曲线锯齿或空白。

4. 故障排查不是撞运气:12个高频问题与我的现场诊断笔记

即使按上述步骤操作,90%的人仍会在启动后遇到至少一个问题。我把过去三年帮团队排障的记录整理成速查表,按发生频率排序。

4.1 启动阶段:容器起不来或立即退出

现象日志关键词根本原因解决方案
prometheus容器状态Restartinglevel=error msg="Error loading config"prometheus.yml语法错误,常见于冒号后少空格、引号不匹配用docker run --rm -v $(pwd)/prometheus:/etc/prometheus prom/prometheus:v2.47.2 --config.file=/etc/prometheus/prometheus.yml --dry-run验证配置
node-exporter容器启动失败flag provided but not defined: -path.procfs版本不匹配,v1.6.1后参数名改为--path.procfs(旧版是--path.procfs)查quay.io/prometheus/node-exporter镜像标签页,确认参数文档
grafana容器日志刷屏Plugin dir not foundt=2023-10-05T02:12:33+0000 lvl=warn msg="Plugin dir not found"./grafana/plugins目录不存在或权限不对创建空目录mkdir -p ./grafana/plugins && chmod 777 ./grafana/plugins

注意:chmod 777在生产环境不安全,但开发机上能快速验证是否是权限问题。真正生产部署应改用user: "472:472"指定Grafana用户UID。

4.2 运行阶段:指标采集不到或数据异常

现象验证方法排查路径经验技巧
Prometheus Web UI显示Status → Targets里node-exporter状态DOWN在宿主机执行curl http://localhost:9100/metrics如果返回Connection refused,检查node-exporter容器是否真在运行;如果返回404,检查docker-compose.yml里ports是否漏写我习惯在docker-compose.yml的node-exporter服务下加healthcheck:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9100/metrics"]
interval: 30s
timeout: 5s
retries: 3
Grafana面板显示No data在Prometheus表达式浏览器输入相同PromQL,看是否有数据如果Prometheus有数据而Grafana没有,90%是数据源URL配置错误。检查grafana/provisioning/datasources/datasource.yml里的url字段是否为http://prometheus:9090(不是localhost)在Grafana UI的Configuration → Data Sources → Prometheus → Save & Test,看是否显示Data source is working。如果显示Failed to fetch,点击右上角Query inspector看实际请求URL
rate()函数返回全0执行count_over_time(jvm_memory_used_bytes[1h])看是否大于0如果count_over_time也返回0,说明指标根本没上报。检查应用端Exporter是否真的在运行,端口是否被防火墙拦截对Java应用,用jps -l查进程PID,再用jstack <pid> | grep -A 10 "Prometheus"确认Actuator端点是否注册成功

4.3 高级问题:告警不触发或误触发

问题:告警规则写了for: 5m,但等了10分钟还没收到通知

诊断步骤:

  1. 进入Prometheus UI →Alerts标签页,看该告警状态是否为Pending(等待中)或Firing(已触发)
  2. 如果是Pending,说明expr条件已满足但未持续5分钟。用Graph查看expr的原始值曲线,确认是否真在阈值线上下波动
  3. 如果是Firing但没通知,检查Alertmanager是否接入。我们的架构没单独起Alertmanager容器,而是用Grafana内置告警——此时需确认grafana.ini里[alerting]段是否启用

解决方案:在docker-compose.yml的grafana服务下加环境变量:

environment: - GF_ALERTING_ENABLED=true - GF_ALERTING_EXECUTION_TIMEOUT_SECONDS=60

问题:Grafana看板里同一指标,不同时间范围显示数值差异巨大

根源在于Prometheus的scrape_interval与Grafana的min step不匹配。例如scrape_interval: 15s,但看板时间范围选Last 7 days,Grafana默认min step是1h,它会把15秒采样点聚合成1小时平均值,导致峰值被抹平。

修复方法:在面板的Panel Options → Standard options → Min step里手动设为15s,或在JSON里写"minStep": "15s"。

4.4 我的终极排障清单(每天必查三项)

  1. 时间同步检查:docker exec prometheus date和宿主机date输出是否一致?误差超过1秒会导致rate()计算异常。解决方案:在docker-compose.yml里加command: ["--web.systemd-http-listener"]并配置systemd timer,或直接用chrony同步容器时间。

  2. 磁盘空间预警:Prometheus TSDB默认每2小时压缩一次,但若磁盘剩余<20%,压缩会失败并停止写入。用docker exec prometheus du -sh /prometheus定期检查。生产环境必须配置--storage.tsdb.retention.time=15d。

  3. Exporter存活探测:写个简易Shell脚本,每5分钟curl所有Exporter的/metrics端点,返回非200则发钉钉通知。不要依赖Prometheus自身的Target状态——它只告诉你“最后一次采集是否成功”,不保证Exporter进程还活着。

5. 不止于“搭起来”:如何让这套监控真正驱动你的日常运维

监控系统最大的价值不是“能看到”,而是“能行动”。我见过太多团队把Prometheus搭得无比漂亮,但告警一响就切微信问同事“你那边挂了吗?”,完全没利用起它的自动化能力。

5.1 告警闭环:从“收到消息”到“自动处理”

Grafana内置告警支持Webhook,我们可以把它连到运维脚本。以“磁盘使用率>90%”为例:

  1. 在alert.rules.yml里加一条规则:
- alert: DiskUsageOver90 expr: 100 * (node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_free_bytes{mountpoint="/"}) / node_filesystem_size_bytes{mountpoint="/"} > 90 for: 2m annotations: runbook_url: "https://runbook.example.com/disk-full"
  1. 在Grafana告警通知渠道里配置Webhook URL为http://host.docker.internal:8000/webhook/disk-clean(注意host.docker.internal是Docker Desktop的特殊DNS)

  2. 写个Python Flask服务监听该URL,收到告警后自动执行:

@app.route('/webhook/disk-clean', methods=['POST']) def disk_clean(): data = request.get_json() if data['status'] == 'firing': # 清理Docker构建缓存 subprocess.run(['docker', 'builder', 'prune', '-f']) # 清理旧镜像 subprocess.run(['docker', 'image', 'prune', '-a', '-f']) return 'OK'

实操心得:这个脚本必须加锁机制,否则同一告警多次触发会导致并发执行docker builder prune,反而卡住构建流水线。我用flock实现:

flock -x /tmp/disk-clean.lock -c "docker builder prune -f"

5.2 指标即文档:用Prometheus注释替代Word文档

很多团队的服务接口文档存在严重滞后。我们改用Prometheus的HELP注释来承载:

# HELP http_request_duration_seconds A histogram of the HTTP request durations. # TYPE http_request_duration_seconds histogram http_request_duration_seconds_bucket{le="0.1"} 24054 http_request_duration_seconds_bucket{le="0.2"} 33444 # HELP payment_service_order_create_total The total number of order create requests. # TYPE payment_service_order_create_total counter payment_service_order_create_total{status="success"} 12345 payment_service_order_create_total{status="failed"} 678

这些HELP文本会自动出现在Prometheus的/metrics端点和Grafana的指标自动补全里。开发写新接口时,必须在代码里添加对应的HELP注释,CI流程会校验注释是否存在。这样,运维查问题时直接看指标名就知道业务含义,不用翻Git历史找文档。

5.3 成本可视化:监控系统本身的资源消耗

最后但最重要的一点:监控系统不该是黑盒。我们在Grafana里建了一个“监控系统健康度”看板,包含:

  • Prometheus内存使用率(process_resident_memory_bytes / machine_memory_bytes)
  • 每秒采集目标数(prometheus_target_interval_length_seconds_count)
  • TSDB压缩耗时(prometheus_tsdb_compaction_duration_seconds_sum / prometheus_tsdb_compaction_duration_seconds_count)

当TSDB压缩耗时 > 30s且内存使用率 > 85%同时出现,说明该升级Prometheus配置了。这个看板让我们在业务增长前就预判监控系统瓶颈,而不是等它崩了才救火。

这套方案从第一次搭建到稳定运行,我们花了11天。其中7天在调scrape_interval和evaluation_interval的平衡点,2天在解决node-exporter的macOS路径映射,剩下2天用来教会团队成员看懂rate()和increase()的区别。现在它支撑着23个微服务、47台云主机、日均处理12亿条指标,而我的工作变成了每周看一眼那个“监控系统健康度”看板,喝杯咖啡。

如果你也打算动手,记住:别追求一步到位。先让prometheus和node-exporter跑起来,能看见CPU曲线就成功了一半;再加cadvisor看容器指标;最后接grafana做可视化。每多一个组件,就多一份对系统真实状态的掌控。监控的本质不是展示数据,而是把混沌的系统行为,翻译成人类可理解、可行动的语言——而Docker,就是那个最可靠的翻译器。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进