ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Prometheus入门实战:从Pull模型到Docker部署与告警配置

Prometheus入门实战:从Pull模型到Docker部署与告警配置 说实话Prometheus这个名字看起来有点唬人但一旦用起来你就会发现它的设计思路非常清晰所有被监控的对象不管是服务器、容器还是应用只需要暴露一个HTTP接口Prometheus定期来拉数据就行。这种Pull模式让监控系统的部署和维护都简单了一个量级。我最早接触监控系统的时候被Zabbix的配置折腾得够呛后来换成Prometheus第一感觉是“原来监控可以这么清爽”。这篇文章是Prometheus入门的第一篇我会从一个实战的角度把监控体系从零搭起来包括为什么选它、核心概念、如何用Docker部署、怎么接Grafana可视化、以及如何配置Alertmanager告警。无论你是后端开发、运维工程师还是想为自己的小项目加一道护栏的个人开发者这篇内容都能帮你把Prometheus的骨架先立起来。1. 为什么监控最终会选Prometheus从被动救火到主动预警1.1 传统监控方案的痛点先聊聊传统监控方案的痛点。我最早接触的是Nagios和Zabbix它们的设计思路是“主动探测 告警触发”。Zabbix会定时去查一个目标服务是否存活端口通不通或者主动执行一些自定义脚本来收集数据。这套体系在服务器数量不多、业务比较单一的时候完全够用问题在于每个监控项都需要手工配置服务器一多配置文件就变得像意大利面。采集端和被采集端强耦合。Zabbix的agent和server之间走的是私有协议想扩展新类型的监控要么装插件要么自己写脚本维护成本高。数据存储和查询能力偏弱。Zabbix数据模型是面向设备而非面向指标的想要回答“昨天下午三点那段时间所有服务器的CPU平均使用率是多少”这类问题写查询能写到怀疑人生。Prometheus的诞生背景正好是容器和微服务开始爆发的年代。每个服务都是动态的、生命周期很短传统的“设备树”监控模型根本跟不上。Prometheus选择了完全不同的路线指标由被监控方主动暴露通过一个简单的HTTP端点通常是/metrics。Prometheus服务端按期拉取也就是scrape这种方式叫Pull模型。所有数据以时间序列time series的形式存储每条序列由指标名加一组标签唯一定义。这种设计带来的直接好处是新增一个监控目标只需要让它在/metrics输出标准格式的文本然后在Prometheus的配置里加一行job定义即可不需要在被监控方安装任何agent。容器漂移到哪台机器Consul或Kubernetes服务发现就能自动告诉Prometheus去哪拉数据。1.2 Pull模型为什么比Push更稳刚开始接触时我有个疑问为什么不用Push毕竟很多监控系统都是被监控方主动上报的。后来想明白了Pull模型有两个隐藏优势。一是天然的健康探测。scrape这个动作本身就带有了对目标服务的健康检查意味。拉不到数据说明目标挂了或网络不通监控系统第一时间就能感知。如果所有数据都是主动推过来的那“没有消息”到底是“一切正常”还是“上报端挂了”很难区分。二是解耦了数据格式。Push模型要求每个被监控方知道监控系统的地址和协议Pull模型则把这个责任全部转移到监控端。被监控方只需要把/metrics打开无论是新开发的Go应用还是现有的Node.js服务都只要用官方或社区的client库暴露指标即可。当然Pull模型也不是银弹。对于短期任务、批处理任务这类生命周期很短的程序可能程序执行完了指标还没来得及被拉走所以Prometheus官方也提供了Pushgateway作为补充用来接收一次性的任务数据。入门阶段大家先把Pull模型吃透就行Pushgateway属于后话。1.3 什么时候适合Prometheus什么时候别硬上选型这件事说白了就是要知道工具的边界。Prometheus的边界很清晰——它是为指标监控而生的不是为日志也不是为链路追踪而生的。日志用Loki或ELK链路追踪用Jaeger或SkyWalking指标监控用Prometheus各司其职才是健康的组合。适合Prometheus的场景服务器和中间件的基础监控CPU、内存、磁盘、Redis、MySQL等。微服务、容器的监控特别是已经上了Kubernetes的环境。应用层的业务指标监控比如QPS、延迟、错误率。不适合的场景需要精确计费、对账的日志类数据。Prometheus不适合做明细日志存储它的强项是聚合指标不是保存原始事件。超长时间跨度的全量历史数据。哪怕把数据转存到对象存储查询体验也一般。需要非常强的事务一致性、多维关系查询的数据那是SQL和大数据分析的事情。2. 从零到一用Docker把Prometheus跑起来2.1 环境准备与目录规划我默认你有一台Linux服务器至少2核4G内存。其实Prometheus本身很轻单机跑不占多少资源真正的内存消耗来自数据积累量采集的目标越多保存周期越长内存和磁盘都会吃紧。入门阶段2G内存完全够用。我建议先把目录规划好后面扩展Alertmanager和Grafana的时候会很顺。我的习惯是mkdir -p /opt/monitor/prometheus mkdir -p /opt/monitor/prometheus/data mkdir -p /opt/monitor/grafana mkdir -p /opt/monitor/alertmanager所有监控组件的配置和数据都放在/opt/monitor下面统一管理。以后要备份直接打包整个目录就行。Docker的容器卷也用宿主机的这个目录方便改配置、看数据。在组件的编排方式上我建议直接用docker compose而不是一个一个docker run。因为Prometheus、Grafana、Alertmanager三个容器之间有关联用compose管理起来清晰得多后续升级某个组件也只需要改一行image版本号。2.2 写一份最简的prometheus.ymlPrometheus的核心配置就是一个YAML文件默认叫prometheus.yml。我最简的配置如下global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: dev-local scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]这里解释几个关键字段scrape_interval多久拉取一次目标数据默认15秒。生产环境根据数据的重要程度和采集压力调整5s、15s、30s都比较常见。evaluation_interval多久计算一次告警规则。这个参数后期接Alertmanager的时候很关键如果设成1分钟那就有最多1分钟的告警延迟。scrape_configs定义从哪些目标采集数据。targets就是被采集端的地址和端口。第一份配置里targets填的是localhost:9090也就是监控Prometheus自身。这个自监控能力非常适合用来验证采集链路是否正常。关于external_labels可能有人一开始不理解。它是给所有序列附加上的全局标签。比如上面标了cluster: dev-local将来如果你有多套Prometheus部署导入同一套Grafana面板或写跨集群查询时这个标签会帮你区分数据来源。设置好这个后续做多集群统一监控会省很多事。2.3 启动容器并验证服务docker-compose.yml示例services: prometheus: image: prom/prometheus:v2.54.0 container_name: prometheus restart: always volumes: - /opt/monitor/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - /opt/monitor/prometheus/data:/prometheus command: - --config.file/etc/prometheus/prometheus.yml - --storage.tsdb.retention.time30d ports: - 9090:9090启动命令docker compose up -d prometheus启动之后浏览器访问http://服务器IP:9090看到的就是Prometheus自带的Web界面。界面上有Graph、Status - Targets、Status - Configuration等入口。大多数人入门第一步容易卡在验证上。这里我给一个非常实用的方法Graph页面的查询框里输入up点击Execute。up这个指标是由Prometheus在拉取目标时自动生成的拉取成功值就是1失败就是0。如果查询结果里有一行up{instancelocalhost:9090, jobprometheus}且值为1说明整个链路已经通了。这个小验证我强烈建议养成习惯之后每接入一个新Exporter都用up来确认它是否被正常拉取。判断一个采集目标是否在线看up是最快的。3. 看懂数据模型指标、标签和时间序列3.1 一条时序数据长什么样Prometheus里所有指标本质上都是时间序列。一个序列的完整标识由三部分组成指标名比如http_requests_total、node_cpu_seconds_total。标签一组key/value比如methodGET、instance10.0.0.1:9100。时间戳毫秒精度的时间点。每次抓取指标的值和当前时间戳会被追加到对应的序列里。查询的时候带上标签过滤器就能看到某条序列的历史数据。比如http_requests_total这个指标加上methodGET和instanceweb-01这两个标签后实际上就是一整条独立的序列它记录着web-01这台机器上GET请求的累计次数。理解序列是理解PromQL的钥匙。很多人在写查询的时候一脸懵就是因为没有意识到Prometheus的存储模型是按序列组织的而不是按“指标名-时间-值”这种平面表格组织的。3.2 四种指标类型Counter、Gauge、Histogram、Summary这是入门阶段必须背下来的内容我一个个说Counter计数器只增不减代表累积值。典型例子是请求总量、已处理的任务数。注意Counter的值通常只增不减如果你重启了一下进程值可能会从0重新开始所以查询时经常会配合rate()或irate()函数看它的变化速率。Gauge仪表盘可增可减代表当前状态。典型例子是当前内存使用量、CPU使用率、在线人数。Histogram直方图用来观测值分布。比如请求耗时的P50、P99。它会在服务端预先算好几个分桶的计数比如请求耗时在0.1s内的有多少、0.5s内的有多少。Summary摘要和Histogram类似也用于分布统计但分位数是在客户端计算的。入门阶段先记住Counter和Gauge的区别就够了Histogram和Summary在接入应用监控时会遇到到时候再深入。关于Counter要用rate()我多说一句。有人直接查询http_requests_total的结果发现它是一个不断上升的曲线误以为这就是QPS。其实不对你可以把它看成“总里程表”。要看QPS就得看一分钟内的增长率也就是rate(http_requests_total[1m])。这个细节新手很容易看错但它却是应用监控里最核心的用法。3.3 标签的威力查询和聚合的地基标签是Prometheus最强大的设计。同一个指标名加上不同的标签就是不同的序列。反过来看标签也允许你把多维数据压缩在同一个指标名里。举个例子node_cpu_seconds_total这个指标它会带一个cpu标签cpu0、cpu1等同时还有一个mode标签表示CPU的工作模式比如idle、user、system。所以如果你想知道整个主机的CPU使用率就得先把所有cpu、所有mode的数值先汇总再与总和做对比。标签带来多维查询能力的同时也带来一个风险高基数列。如果某个指标的标签值组合特别多比如把用户ID、订单ID放进标签序列数量会爆炸Prometheus的内存和磁盘会直接受不了。这是生产环境最常踩的坑之一。设计指标时标签只适合放低基数维度方法名、状态码、机房、实例名就很好用户ID、IP这种高基数维度的数据想都不要想。4. 接入两个Exporter先让机器把话说出来4.1 Node Exporter主机指标的标准答案监控一台Linux服务器最容易上手的Exporter就是Node Exporter。它会收集内核暴露的各类统计信息并转换为Prometheus的指标格式。部署Node Exporter的方式也很多我倾向于直接用Docker下面是docker-compose配置node-exporter: image: prom/node-exporter:v1.7.0 container_name: node-exporter restart: always network_mode: host command: - --path.rootfs/host volumes: - /:/host:ro,rslave这里有个关键点通常node_exporter可以直接用端口映射到9100端口的容器方式但收集磁盘和网络指标时容器和宿主机看到的文件系统可能不一致。上面的配置把宿主机的根目录以只读方式挂载进容器再通过--path.rootfs/host让node_exporter基于这个根文件系统采集这样就能拿到准确的磁盘使用率和网络状态。之后在prometheus.yml里增加一个job- job_name: node-exporter static_configs: - targets: [你的宿主机IP:9100]同样用up查询来验证。如果看到node_exporter对应的up指标值为1那么主机层面的监控就完成了。node_exporter默认暴露的指标有上千个包括CPU、内存、磁盘、网络、文件系统够用了。4.2 cAdvisor容器资源监控的黄金搭档如果你的服务是跑在Docker容器里的那cAdvisor几乎是绕不开的。它可以采集每个容器的CPU、内存、网络、磁盘IO等指标并暴露在8080端口的/metrics上。cAdvisor在GitHub上已经不单独维护了但在compose模式下配合Prometheus用依然是最常见的方案。cAdvisor的docker-compose配置cadvisor: image: gcr.io/cadvisor/cadvisor:v0.49.1 container_name: cadvisor restart: always ports: - 8080:8080 volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro - /dev/disk/:/dev/disk:ro启动后在prometheus.yml里加一个job- job_name: cadvisor static_configs: - targets: [你的宿主机IP:8080]cAdvisor暴露的指标很多入门阶段我建议先关注container_cpu_usage_seconds_totalCPU累积使用时间。container_memory_usage_bytes内存使用量。container_network_receive_bytes_total/container_network_transmit_bytes_total网络收发字节数。有了Node Exporter和cAdvisor主机层和容器层的数据就都有了。做监控最有成就感的一刻就是数据从无到有的那一刻你会发现很多“灵异事件”其实都可以用数据解释。4.3 配置采集目标静态与动态之间上面的配置都是静态targets写法适合固定IP的场景。但生产环境里服务节点会动态扩容和缩容再用static_configs就不现实了。Prometheus支持的服务发现机制很多包括Consul、Kubernetes、DNS还有云厂商的服务发现。入门阶段咱们先把static_configs和file_sd_configs弄明白就足够了。file_sd_configs是文件服务发现你可以维护一个JSON或YAML文件里面写targets列表Prometheus会周期性地重新读取这个文件。需要加节点时就改文件不需要重启Prometheus。这个方案是小团队过渡到完整服务发现之前非常实用的中间态。- job_name: node-exporter file_sd_configs: - files: - /etc/prometheus/targets/node-exporter.yml refresh_interval: 30s对应的targets文件内容大概是这样- targets: - 10.0.0.11:9100 - 10.0.0.12:9100这样就不需要每次加服务器都去改主配置了。5. 把Grafana请进来数据要好看更要看得懂5.1 启动Grafana并接入Prometheus数据源Prometheus自带的UI只适合做临时查询不适合做持续观察的大屏。可视化这层活儿通常交给Grafana。启动Grafana的compose配置grafana: image: grafana/grafana:11.0.0 container_name: grafana restart: always ports: - 3000:3000 environment: - GF_SECURITY_ADMIN_USERadmin - GF_SECURITY_ADMIN_PASSWORDadmin123 volumes: - /opt/monitor/grafana:/var/lib/grafana启动后用浏览器打开3000端口默认账号admin/admin123登录后第一件事就是添加数据源。选择Prometheus类型URL填http://你的宿主机IP:9090Access选Server。这里有个细节Grafana是服务端去访问Prometheus所以URL不能用localhost:9090否则它访问的是Grafana容器自己会直接报错。5.2 导入现成Dashboard模板的注意事项Grafana最爽的一点是社区有海量的Dashboard模板。在Grafana官网的Dashboard市场搜索node exporter或cAdvisor能找到下载次数极高的模板直接导入即可。导入的时候有几点要注意模板需要的数据源名称必须跟你实际的数据源名称一致。如果模板默认要求Prometheus数据源叫Prometheus而你本地建的是prometheus面板上的所有图表都会显示No data。模板里用到的变量比如node的instance、job底层都是一些PromQL查询。导入后最好逐个面板看一下查询语句确认它引用的是哪个Exporter的指标防止把cAdvisor的模板套在Node Exporter数据上。下载模板前先看它的Panel数量和数据指标集。有些模板特别花哨几十个面板但你的数据源里可能根本没有对应指标导入后全是空面板反而扰乱视线。我个人的建议是入门阶段不用追求大而全的模板找一个精简的Node Exporter模板加上自己的数据源改一改即可。监控这一行少即是多看得过来比看得全面更重要。5.3 自己画第一张面板如果完全自己画也很简单。在Grafana里新建Dashboard添加Panel输入PromQL表达式CPU使用率百分比100 - avg(rate(node_cpu_seconds_total{modeidle}[5m]) * 100) by (instance)内存使用率100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)磁盘使用率100 - (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100保存之后你会看到一条实时更新的曲线。这就是监控的快乐。很多时候最复杂的系统问题其实在曲线图上都会露出一条异常尾巴前提是你要先把图挂起来。6. 告警这环不能少Alertmanager从部署到第一条告警6.1 把Alertmanager部署起来监控如果没有告警就只是事后诸葛亮。Prometheus负责“发现异常”Alertmanager负责“把异常告诉人”。部署Alertmanager的compose配置alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager restart: always ports: - 9093:9093 volumes: - /opt/monitor/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml command: - --config.file/etc/alertmanager/alertmanager.yml - --storage.path/alertmanagerAlertmanager的核心配置是把收到的告警路由给不同的接收者。最简配置如下route: group_by: [alertname] group_wait: 10s group_interval: 2m repeat_interval: 4h receiver: default receivers: - name: default email_configs: - to: opsexample.com from: alertexample.com smarthost: smtp.example.com:587 auth_username: alertexample.com auth_password: password然后在prometheus.yml里加上Alertmanager的地址alerting: alertmanagers: - static_configs: - targets: [你的宿主机IP:9093]6.2 写第一条告警规则告警规则放在Prometheus里用一个独立的rules.yml文件并在prometheus.yml里引用rule_files: - /etc/prometheus/rules.ymlrules.yml最简内容groups: - name: host.rules rules: - alert: HostHighCpuLoad expr: 100 - (avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100) 80 for: 5m labels: severity: warning annotations: summary: Instance {{ $labels.instance }} CPU usage high这段规则的含义是如果CPU使用率超过80%并且持续5分钟就触发HostHighCpuLoad告警。Prometheus每隔evaluation_interval秒会去评估一次规则。如果这个条件一直为真经过for指定的持续时间后告警状态就从Pending变为Firing。只有Firing的告警才会被推送到Alertmanager。6.3 测试告警链路验证告警链路完不完整最直接的方法是把阈值临时调低比如改成大于1然后观察Prometheus的Alerts页面里规则应该很快变成Pending然后变成Firing。Alertmanager的9093端口页面能看到收到的告警。如果配置了邮件接收者邮箱里会收到通知。测试完成后一定要把阈值改回来。我见过有人临时测完忘改阈值结果整个群刷了一整晚报警消息的事故。告警优化方面入门阶段还不用太深入。你只需要知道Alertmanager里有分组、抑制和静默三大机制即可。分组就是把同一时间相似的告警合并成一条抑制是一条高等级告警可以屏蔽相关的低等级告警静默则是运维人员主动屏蔽某条告警。这三样等告警多了以后自然就知道怎么玩了。7. 入门阶段必须知道的几个坑和排查路径7.1 target拉取失败最经典的现象是Status - Targets页面里某个target显示DOWN或者up查询出来的值是0。排查顺序如下先确认被采集端的HTTP接口是否可访问。在宿主机上用curl访问一下目标的/metrics。如果打不开问题在被采集端。确认Prometheus容器能访问到目标地址。由于Prometheus是容器它访问宿主机IP:9100和访问localhost:9100结果完全不同。localhost在容器里指的是容器自己不是宿主机。如果目标正常了等下一个scrape周期再刷新Targets页面应该就变UP了。7.2 配置改了却不生效改完prometheus.yml之后需要重新加载配置。两种方式一种是给Prometheus进程发SIGHUP信号另一种是通过web接口/-/reload。如果是docker compose直接docker exec prometheus kill -HUP 1最方便否则就docker restart prometheus。这里要注意在配置里增加target后重启没问题但频繁重启不是好习惯线上环境建议用/-/reload平滑加载。7.3 数据不显示如果Grafana面板显示No data先别怀疑PromQL写错了。检查顺序是Prometheus的Graph页面里直接执行同样的PromQL看有没有数据。如果有数据确认Grafana的数据源URL填的是不是Prometheus的地址以及数据源类型是否选对了。如果Prometheus页面也没有数据用up看目标有没有在线再看指标名是否拼写正确。这套排查顺序我百试百灵几乎能覆盖90%以上的“数据不显示”问题。7.4 内存和磁盘的长期维护Prometheus的tsdb存储数据会同时占用内存和磁盘。入门阶段如果没有及时的清理策略数据文件可能会越滚越大。compose里我通常加一条--storage.tsdb.retention.time30d来控制保存周期。再配合定期备份/opt/monitor/prometheus/data目录基本不会再被磁盘打爆。最后分享一个我自己的习惯每次刚部署完一组监控组件我会把Grafana面板截图保存下来标上日期。过了一两周再对比往往能发现一些意想不到的趋势变化。监控这东西数据越积越有价值坚持看曲线比临时排障有用得多。这一篇先把骨架搭起来下一篇再深入PromQL的进阶用法和常见告警阈值设计。
返回列表