最近某测试环境要搭一套基础监控需要实时看到服务器的CPU、内存、磁盘和容器运行状态。考虑到机器上已经有Docker我没有在宿主机直接装Prometheus和Grafana进程而是决定使用Docker安装Grafana并配置Prometheus把整个监控栈容器化。整个过程比预想中顺畅但也没少踩坑数据源连不上、targets状态DOWN、容器重启以后配置丢失全都遇到过。这篇把完整的部署流程、配置细节和排查经验整理出来给正在用Docker搞监控的同学一个可以照抄的参考。哪怕之前完全没接触过Prometheus按步骤操作也能把监控面板跑起来。1. 项目概述与整体设计思路1.1 这套监控栈在解决什么问题监控需求听起来不复杂能看到一批服务器的CPU、内存、磁盘、网络流量以及容器本身是否健康。但真正落地时你会发现指标种类多、采集周期不一样、展示维度也不同自己从头写一套采集脚本加展示页面根本不现实。Prometheus负责拉取指标并存储Grafana负责把指标变成可视化图表这个组合是目前最成熟的开源方案之一。这套方案的核心机制是拉取模式。被监控对象比如Linux主机上运行一个exporterPrometheus按固定周期主动访问exporter暴露的HTTP接口把指标抓回来存进时序数据库Grafana再通过PromQL查询这些指标绘制图表。和推模式相比拉模式的好处是采集端不用关心数据往哪送Prometheus统一控制抓取目标和节奏出现问题也容易排查——直接看targets页面就知道哪个节点没连通。之所以用Docker部署而不是直接在宿主机装二进制我考虑的主要是三点一是可复现一套compose文件拿到任何一台装了Docker的机器上都能拉起来不用重复执行一堆安装步骤二是隔离Prometheus、Grafana的依赖不会污染宿主机环境卸载也干净三是版本控制镜像tag固定以后整栈版本一目了然升级也方便。当然容器化也有代价比如数据持久化需要专门管理volume网络模式也要做规划这些后面会说。1.2 核心组件分工与选型理由这套监控栈主要有三个容器prometheus、grafana、node-exporter分工很明确。Prometheus是数据中枢负责指标采集和存储。它本身不展示好看的图表但提供了强大的PromQL查询语言和告警规则引擎。Grafana则专注于可视化提供仪表盘、图表、告警通知等功能用户最终看到的所有面板都来自Grafana。node-exporter是Prometheus官方的主机指标采集器暴露Linux系统的标准指标比如CPU使用率、内存占用、磁盘读写、网络收发等。实际上我们不只监控宿主机还监控Prometheus自身的运行状态所以Prometheus的配置里会同时定义两个采集任务一个抓自己一个抓node-exporter。如果你还要监控MySQL、Redis或者Nginx套路是一样的——给目标组件安装对应的exporter然后往scrape_configs里加一个job就行。端口规划也要提前想好Prometheus默认端口9090Grafana默认端口3000node-exporter默认端口9100。在生产环境这些端口不建议直接暴露到公网Grafana前面最好加一层反向代理和登录认证。测试环境如果图省事用Docker映射端口直接访问也可以但至少Grafana的管理员密码要改掉。2. 环境准备与基础概念2.1 Docker环境准备部署之前先确认Docker环境可用。如果机器上还没装Docker安装后务必把当前用户加进docker用户组这样就不用每条命令都加sudo了。验证Docker是否正常的快速方法是跑一个测试容器docker version docker run --rm hello-worlddocker version能正常输出Client和Server两段信息说明Docker守护进程在工作。hello-world能打印出欢迎信息说明镜像下载和容器运行都没问题。Compose工具是第二个前提。新版Docker默认集成了docker composeV2版本中间有空格老版本可能需要单独安装docker-composeV1带横线。可以在部署前确认一下命令是否可用docker compose version如果提示找不到命令先去装好Compose插件。本文统一使用V2风格的docker compose命令如果你用的是V1把命令改成docker-compose效果一样。2.2 镜像与网络规划镜像tag的选择是新手容易忽略的环节。很多人喜欢写latest图省事但latest会随上游更新变化今天部署的和三个月后部署的可能完全不是一个版本升级带来的配置兼容问题会让你非常被动。我的习惯是固定到小版本。写这篇文章时我使用的是prom/prometheus:v2.47.0grafana/grafana:10.1.0prom/node-exporter:v1.6.0这三个tag都是当时经过验证的稳定版本。部署时你可以根据自己的需求选择更新的版本但原则是tag要固定不要写latest。网络方面我为这套监控单独创建了一个自定义bridge网络叫monitor-net。为什么要单独建网络而不是直接用默认网络因为容器之间需要相互访问在自定义网络里可以用服务名直接通信。比如Grafana要访问Prometheus的数据接口URL直接写http://prometheus:9090就够了Docker内置DNS会自动解析到这个容器的IP不用去查IP地址也不怕容器重建导致IP漂移。docker network create monitor-net这条命令执行后monitor-net这个网络会被后面的compose文件引用。如果你不预先创建compose里也可以用driver: bridge声明为内部网络但预先创建的好处是别的项目也能复用这个网络后续加新监控对象会更灵活。3. 核心配置与编排部署3.1 Prometheus配置文件详细解析Prometheus的配置核心就是一个YAML文件通常叫prometheus.yml。我会在宿主机上先建好一个目录比如/opt/monitor/prometheus把配置文件放在里面然后通过volume挂载到容器内。这样改配置不用进容器直接在宿主机改完再触发重载就行。最基础的配置文件长这样global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: node static_configs: - targets: [node-exporter:9100]这里有两个参数值得说明。scrape_interval决定Prometheus每隔多少秒抓一次指标15秒是官方推荐值对绝大多数场景够用。如果你有几百台机器或者指标量特别大可以适当调大到30秒甚至60秒减轻压力。evaluation_interval是告警规则的评估周期意思就是每隔多久检查一次告警条件是否满足默认15秒如果你不需要告警这个参数可以不管。第二个job里targets写的是node-exporter:9100而不是某个IP。这是在Docker自定义网络里通过服务名访问容器的正确写法。compose里定义的服务名叫node-exporterPrometheus容器在同一个网络中直接解析到这个服务名对应的容器IP。如果写成宿主机IP或localhost反而可能因为网络模式不一致而失败。还有一个参数建议加上就是数据保留时间。Prometheus默认保留15天数据想改的话在启动命令里加参数后面会讲到。配置好这个文件后可以先用promtool做一次校验避免格式错误导致容器起不来。不过如果你没装promtool直接启动后看日志也行Prometheus会在配置无效时打印具体错误行。3.2 docker-compose编排与关键参数说明配置文件准备好之后就是编排环节。完整的docker-compose.yml如下services: prometheus: image: prom/prometheus:v2.47.0 container_name: prometheus volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - --config.file/etc/prometheus/prometheus.yml - --storage.tsdb.path/prometheus - --storage.tsdb.retention.time15d ports: - 9090:9090 networks: - monitor-net restart: unless-stopped grafana: image: grafana/grafana:10.1.0 container_name: grafana environment: - GF_SECURITY_ADMIN_PASSWORDadmin123 volumes: - grafana_data:/var/lib/grafana ports: - 3000:3000 networks: - monitor-net restart: unless-stopped node-exporter: image: prom/node-exporter:v1.6.0 container_name: node-exporter volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - --path.procfs/host/proc - --path.sysfs/host/sys - --path.rootfs/rootfs ports: - 9100:9100 networks: - monitor-net restart: unless-stopped volumes: prometheus_data: grafana_data: networks: monitor-net: external: true逐个看重点。Prometheus这里有两个挂载。第一个是配置文件挂载:ro表示容器内只读防止容器误改。第二个是数据目录挂载Prometheus把时序数据写在容器里的/prometheus目录我们把它映射到名为prometheus_data的命名volume里这样容器删除重建后数据不丢。启动命令里有三个参数--config.file指定配置文件路径--storage.tsdb.path指定数据存储目录--storage.tsdb.retention.time15d控制数据保留时间。Grafana的环境变量里GF_SECURITY_ADMIN_PASSWORD设置的是管理员密码。默认用户名是admin这个变量会替换掉初始密码。生产环境务必设置一个强密码不要使用示例里的admin123。Grafana的数据也做了持久化它的插件、面板配置、数据源配置都存在/var/lib/grafana所以这个volume同样必不可少。node-exporter是监控宿主机的关键。如果你只是直接跑docker run prom/node-exporter而不做额外配置采集到的是容器自己的CPU和内存不是宿主机的。要让node-exporter采集宿主机指标必须把宿主机的/proc、/sys和根目录挂载进容器并通过三个路径参数告诉它去哪里读数据。这就是上面那段配置的意义。关于这一点多说几句容器内的/proc是容器视角的文件系统进程信息、CPU信息都是容器自身的挂载宿主机目录后再用--path.procfs/host/proc把读取路径指过去node-exporter才真正拿到宿主机指标。这个坑非常隐蔽很多人面板上看到有数据但数值明显不合理基本都是这里出错。restart: unless-stopped这个策略值得养成习惯。它保证宿主机重启或者Docker服务重启后容器能自动拉起来。相比always它多了一个条件——如果手动stop过容器就不会强行拉起这个语义更符合日常运维习惯。启动服务docker compose up -d-d参数表示后台运行。启动后确认一下状态docker compose ps docker compose logs -f prometheus看到日志里没有error级别的内容基本就成功一半了。接下来验证Prometheus本身curl http://localhost:9090/-/healthy返回Prometheus Server is Healthy说明服务正常。打开http://localhost:9090/targets如果prometheus和node两个job的状态都是UP采集链路就是通的。3.3 启动验证与数据检查targets页面显示UP只是第一步还得确认指标体系里真的有数据。在Prometheus自带的Graph页面上输入一个简单的表达式node_memory_Active_bytes点Execute如果能返回一批带时间戳的数值说明node-exporter的指标已经被正常抓取。同样的方法可以测试其他指标比如node_cpu_seconds_total。这里有个经验如果页面返回no data多数情况不是查询写错了而是targets状态根本没UP或者指标名打错了。Grafana的访问验证就简单了浏览器打开http://服务器IP:3000用admin和设置好的密码登录。第一次登录会看到欢迎页可以跳过初始配置直接进入主界面。到这一步整套监控栈已经跑起来了但离好看好用的面板还差最后一步——把数据源接入Grafana。4. Grafana配置与监控面板4.1 添加Prometheus数据源Grafana本身不存监控数据它只是数据可视化工具所以第一步是告诉Grafana去哪里查数据。进入页面后依次点击Configuration设置图标 -Data sources-Add data source选择Prometheus。这里会有一个让很多人困惑的配置项URL。在Grafana容器内不能填http://localhost:9090因为localhost指向的是Grafana容器自身而不是Prometheus。由于两个容器都在同一个monitor-net网络里正确写法是http://prometheus:9090。这和之前Prometheus里用node-exporter:9100是一样的道理都是利用Docker内置DNS进行服务名解析。下面几个字段按默认即可Access保持Server模式Scrape interval可以改成和Prometheus一致的15s。填完之后点击Save test如果出现绿色的Success提示说明数据源连通Grafana已经能正常查询Prometheus的数据了。如果提示失败优先检查两个容器是否在同一个网络、Prometheus的9090端口是否真的在监听。4.2 导入仪表盘与自定义面板数据源配置好以后可以直接从Grafana的模板库导入现成的仪表盘省去一个个画图板的功夫。进入Dashboards-New-Import在输入框填一个模板ID比较常用的是node_exporter面板ID1860。点击Load后会要求选择数据源选刚才创建的Prometheus点Import就能看到完整的Linux主机监控面板包含CPU、内存、磁盘、网络、负载等十几个图表。如果你需要自定义面板理解几个PromQL表达式就够了。CPU使用率的核心表达式是100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100含义是取过去5分钟内CPU空闲时间的平均变化速率用100减去它就是CPU使用率。内存使用率用(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100这两个表达式可以放在饼图或数字面板里直观展示资源健康度。磁盘使用率按挂载点分组来看100 - (node_filesystem_avail_bytes{fstype!~tmpfs|overlay} / node_filesystem_size_bytes{fstype!~tmpfs|overlay}) * 100这个表达式把伪文件系统排除掉只保留真实的磁盘分区。面板创建完成后别忘了给每个Panel设置合适的刷新周期。Grafana默认刷新是关闭的需要手动点击右上角的刷新按钮或者设置自动刷新间隔否则数据不会自动更新。一般配合Prometheus的15秒采集间隔设置30秒刷新就够了。5. 常见问题与排查技巧5.1 高频问题速查表部署过程中遇到的问题是固定的那几类我整理成一张表按症状排查效率很高症状常见原因排查方向docker compose up -d报端口冲突宿主机3000或9090端口被占用docker ps看哪些容器占用端口或改用其他宿主机端口如30001:3000Grafana数据源测试失败URL写成了localhost或IP错误改成http://prometheus:9090确认容器在同一网络Prometheus targets页显示DOWNexporter没启动或网络不通用docker compose ps看exporter状态curl localhost:9100/metrics手动验证面板有图但数据全为0node-exporter路径未指向宿主机检查--path.procfs/host/proc参数和挂载的/proc:/host/proc容器重启后Grafana配置丢失没挂载数据卷确认grafana_datavolume已挂载到/var/lib/grafana时间显示UTC容器默认时区非中国时区Grafana设置里改default_timezone为Asia/Shanghai5.2 几个值得记住的实操心得第一个心得是关于Prometheus配置修改后的重载。Prometheus支持热加载配置不需要重启容器。你在宿主机编辑好配置文件后执行curl -X POST http://localhost:9090/-/reload配置会平滑生效不会中断数据采集。但前提是配置文件确实发生了变化Prometheus内部会做校验内容没变的话不会真的重载。这个操作比docker compose restart prometheus温和得多日常调整采集目标时非常有用。第二个心得是不要图省事把配置文件目录挂载进去。我有一次图方便把整个./prometheus目录挂载成/etc/prometheus结果Prometheus启动后读取到的配置文件路径、规则文件路径都会发生变化而且目录里的子文件权限很容易出问题。更稳妥的方式是只挂载单个YAML文件像我在compose里写的那样路径对应关系一目了然。第三个心得是Grafana的数据源和仪表盘可以通过provisioning方式预先配置。如果你需要自动化部署多套环境可以准备一个/opt/monitor/grafana/provisioning目录在里面放数据源和仪表盘的YAML定义文件Grafana启动时会自动加载不用每次手动添加。这样整套监控栈从部署到可用能做到一条命令搞定。第四个心得是volume备份。命名volume的数据默认在/var/lib/docker/volumes下备份时直接打包对应目录即可。比如tar czf prometheus_data.tar.gz /var/lib/docker/volumes/monitor_prometheus_data/_data恢复时解压到同一路径再重启容器。对临时测试环境来说这个备份频率不用太高但如果上面有重要的历史指标建议纳入定期备份计划。5.3 数据保留与磁盘空间估算Prometheus的本地存储是磁盘大户这点要做好心理准备。数据保留时间、指标数量、抓取频率三者的乘积决定了占用空间。经验上一个采集频率15秒、暴露300个时间序列的标准主机节点一天大约产生100MB到200MB数据。如果机器上有几百个目标保留30天那就需要按GB级别预留磁盘。启动命令里我写的--storage.tsdb.retention.time15d就是测试环境下权衡之后选的——数据够用磁盘不会爆。如果磁盘实在紧张我建议优先降低抓取频率而不是缩短保留时间。把scrape_interval从15秒改成30秒数据量直接减半对绝大多数监控场景完全没影响。相对地retention.time如果设得太短出问题的时候查不到历史数据反而更被动。5.4 后续扩展方向加targets与告警这套架构搭完之后扩展监控对象非常轻松。比如要监控一台MySQL先在那台机器上部署mysqld-exporter然后把它的地址加进Prometheus配置的static_configs里再reload一下Grafana导入对应的MySQL面板即可。整个流程就是“加exporter - 加job - 刷面板”不用动Grafana本身。告警功能是Prometheus和Grafana双通道的。Prometheus原生支持告警规则但需要Alertmanager配合才能发通知Grafana 10以后也内置了告警能力可以直接在面板上配置阈值告警通过邮件、钉钉、Webhook等方式推送。我的建议是中小规模场景直接用Grafana告警就够了配置路径短、界面友好如果告警规则特别复杂、量很大再引入Alertmanager。这些都是在现有基础之上加配置的问题不需要重新选型。最后分享一个我一直在用的习惯我会把prometheus.yml、docker-compose.yml都放进同一个项目目录纳入版本管理。改配置、加target、更新版本全部通过提交记录可以追溯。这套监控栈跑了一个月中间换过两次机器每次都是把项目目录拷过去改一下网络然后docker compose up -d几分钟内整套监控恢复原样。容器化部署带来的迁移便利在这个场景下体现得特别明显。
阅读完成 · 觉得有帮助?