ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

日志散在多台服务器怎么查?用 Promtail + Loki + Grafana 搭一套集中检索平台

日志散在多台服务器怎么查?用 Promtail + Loki + Grafana 搭一套集中检索平台 前言应用出错时我最怕的不是看到一条报错而是明知道异常发生了却不知道该去哪台机器、哪个目录找它。登录服务器、翻server.log、对照时间再切到另一套服务继续查日志越分散定位问题花的时间就越多。Promtail、Loki 和 Grafana 这套 PLG 组合适合解决的正是把日志采集、存储和查询分成三个明确的环节Promtail 盯住文件并发送日志Loki 按标签组织日志流Grafana 则提供查询与展示入口。它不等于把所有日志都建成全文索引查问题时要先选对标签再用 LogQL 缩小范围。比如半夜收到一个接口报错我希望先按应用名找到对应日志流再对照异常时间和请求内容而不是在几台机器之间反复切换、凭印象猜测。这篇我会沿着两条路线实际梳理先看 CentOS 7 下分别部署二进制程序的方式再看使用 Docker Compose 一起启动三个组件的方法。后一条路线还会从test.log开始写入测试消息接着验证 JSON 日志、Nginx 和认证日志的查询最后用 cpolar 把 Grafana 的3000页面提供给异地浏览器。两条路线的端口、版本和存储目录并不相同不能互相照搬尤其是权限、匿名访问和数据持久化我更愿意在上线前逐项确认而不是只看到容器运行就算完成。一、先认清三个组件的分工如果只是偶尔登录一台服务器看一份日志直接用命令行通常足够当应用、容器和主机越来越多分散的文件才开始影响排障。PLG 的请求方向是Promtail 读取日志 → 推送给 Loki → Grafana 查询 Loki不是 Grafana 直接扫描各台机器的文件。Promtail 可以按文件路径采集并添加job、host等标签Loki 主要索引标签、保存日志内容Grafana 使用 LogQL 按标签、关键词或解析后的字段筛选。需要接入指标或链路追踪时再分别连接相应的数据源不能把这份日志部署直接等同于完整三件套可观测平台。例如{jobapp} | error用于筛选包含错误关键词的应用日志{jobnginx} |~ 404|500用于匹配状态码文本rate({jobapi}[5m])则可统计指定时间窗口的日志速率。对比需要全文索引的方案这种标签优先的检索方式适合明确知道服务名、来源或环境的排障实际资源开销仍取决于日志量、标签基数和部署规模。二、CentOS 7先分开安装三个组件这条路线需要 root 或 sudo 权限并且机器能够下载软件包。文中的防火墙示例同时给出了关闭服务和按端口开放两种思路实际长期运行时应优先确认需要开放的端口而不是把关闭防火墙当成监控系统的前提。尤其需要区分 Loki 的二进制端口8094、Promtail 的9080与 Grafana 的3000开头提及的3100是后面 Docker 方案使用的 Loki 端口。systemctl stop firewalld systemctl disable firewalld# 或使用 iptables/firewalld 开放端口准备 wget、tar、curl、vim 和网络工具再创建可选的 Loki 专用账号yum update-yyuminstall-ywgettarcurlvimnet-toolsuseradd-r-s/sbin/nologin loki先运行 Loki接收日志并保存到磁盘安装说明文字提到v3.0.0但实际下载命令指向的是v1.5.0。应当以真正下载并运行的二进制为准不要把后面的 Docker2.9.10配置当作同一版本使用。执行以下命令前还应确认/app/loki目录已经存在它在命令中被直接cd进入并没有先创建。cd/app/lokicurl-O-Lhttps://github.com/grafana/loki/releases/download/v1.5.0/loki-linux-amd64.zip解压命令使用unzip而前面的基础安装清单没有包含它若提示命令不存在需要先在系统环境中准备该工具。unziploki-linux-amd64.zip日志块和索引分别放在/data/loki/chunks、/data/loki/index这部分是二进制方案的本地存储位置mkdir/data/lokimkdir/data/loki/{chunks,index}编辑config.yamlviconfig.yamlauth_enabled:falseserver: http_listen_port:8094ingester: lifecycler: address:192.168.42.140#日志服务器ip即本机地址ring: kvstore: store: inmemory replication_factor:1final_sleep: 0s chunk_idle_period: 5m chunk_retain_period: 30s schema_config: configs: - from:2024-04-01 store: boltdb object_store: filesystem schema: v11 index: prefix: index_ period: 168h#每张表的时间范围7天storage_config: boltdb: directory: /data/loki/index#索引文件存储地址filesystem: directory: /data/loki/chunks#块存储地址limits_config: enforce_metric_name:falsereject_old_samples:truereject_old_samples_max_age: 168h chunk_store_config: max_look_back_period: 168h table_manager: retention_deletes_enabled:trueretention_period: 168h#表的保留期7天这份配置关闭了 Loki 内置认证在192.168.42.140所在服务器使用单副本 ring将 HTTP 入口设为8094并设置了七天相关的保留参数。由于配置包含旧版存储 schema应该配合实际下载的二进制核对适用性不要简单替换成较新版本后继续照抄。auth_enabled: false也意味着不能直接把 Loki 接口当作已完成授权保护的公网服务。随后创建启动和停止脚本前者后台执行二进制并记录 pid后者根据 pid 停止进程。原有kill -9属于强制结束命令运行前要核对 pid 文件确实属于对应 Loki 进程。vistart.sh#!/bin/bashnohup./loki-linux-amd64-config.file./config.yaml./server.log21echo$!pidvishutdown.sh#!/bin/bashkill-9catpidecho关闭成功!脚本准备好以后启动并查看输出日志如果没有收到 Promtail 的数据先确认 Loki 自身能稳定启动再继续查采集端。shstart.shtail-200fserver.log再安装 Grafana给日志提供查询界面这里又给出了一组关闭 firewalld 和 SELinux 的命令属于对主机安全机制的明显放宽。它们按技术示例保留但不能据此理解为 Grafana 必须在关闭这些防护后才能工作。systemctl stop firewalld systemctl disable firewalld setenforce0sed-is/SELINUXenforcing/SELINUXdisabled/g/etc/selinux/config安装方式按照系统包形式分别列出真正使用 CentOS 的演示选的是 RPM 命令。不要在同一台机器上把下面不同平台的安装方式依次执行。Ubuntu / Debiansudoapt-getinstall-yadduser libfontconfig1 muslwgethttps://dl.grafana.com/enterprise/release/grafana-enterprise_12.1.0_amd64.debsudodpkg-igrafana-enterprise_12.1.0_amd64.debStandalone Linux Binarieswgethttps://dl.grafana.com/enterprise/release/grafana-enterprise-12.1.0.linux-amd64.tar.gztar-zxvfgrafana-enterprise-12.1.0.linux-amd64.tar.gzRed Hat / CentOS / RHEL / Fedorasudoyuminstall-yhttps://dl.grafana.com/enterprise/release/grafana-enterprise-12.1.0-1.x86_64.rpmOpenSUSE / SUSEwgethttps://dl.grafana.com/enterprise/release/grafana-enterprise-12.1.0-1.x86_64.rpmsudorpm-Uvhgrafana-enterprise-12.1.0-1.x86_64.rpm本次 CentOS 使用的命令再次列出sudoyuminstall-yhttps://dl.grafana.com/enterprise/release/grafana-enterprise-12.1.0-1.x86_64.rpm安装 Grafana Enterprise12.1.0后启动服务并设置开机自启再查看版本号systemctl restart grafana-server systemctlenablegrafana-servergrafana-cli-version浏览器访问服务器的3000端口。代码框里的ip:3000是访问地址示意不是要在 shell 中执行的命令。ip:3000首次登录使用示例账号admin/admin进入后按页面提示修改密码这也是后面考虑远程开放前必须完成的基础动作。最后安装 Promtail把目标日志送到 Loki采集端放在/app/promtail实际下载也是v1.5.0与前面的二进制 Loki 路线相对应。路径需要先存在再下载、解压并创建配置文件。cd/app/promtailcurl-O-Lhttps://github.com/grafana/loki/releases/download/v1.5.0/promtail-linux-amd64.zipunzippromtail-linux-amd64.zipvipromtail.yamlserver: http_listen_port:9080grpc_listen_port:0positions: filename: ./positions.yaml clients: - url: http://192.168.42.140:8094/loki/api/v1/push#日志服务器loki地址和端口scrape_configs:#ucenter1- job_name: zcbackend-172.29.21.22-1 static_configs: - targets: -192.168.42.140 - labels: job: zcbachend-172.29.21.22-1 host:192.168.42.140 __path__: /jiuqi/zichan/zichanyitihuazhenghexiangmu-8084/backend/server.log#本机日志路径这份配置把日志发送到http://192.168.42.140:8094/loki/api/v1/push读取的具体文件是/jiuqi/zichan/zichanyitihuazhenghexiangmu-8084/backend/server.log并设置job、host等标签。这个路径和 IP 代表演示环境迁移到自己的机器时必须与真实日志路径对应。配置里的static_configs列表和标签缩进也需要按实际 YAML 结构核对如果 Promtail 不启动优先检查配置解析报错。positions.yaml用于记录读取位置它的路径在此处是相对路径。同样创建启动脚本和关闭脚本启动后查看日志。这里展示了创建shutdown.sh的命令及截图但没有给出它的具体内容不能默认它已经和 Loki 的停止脚本完全一致。vistart.sh#!/bin/bashnohup./promtail-linux-amd64-config.file./promtail.yaml./server.log21echo$!pidvishutdown.shshstart.shtail-200fserver.log到这里二进制部署的三层职责就明确了Promtail 读文件Loki 在8094接收Grafana 在3000展示。接下来是另一套完整 Docker 路线不应在现有服务还占用相同端口时直接叠加运行。三、Docker Compose把 PLG 放到同一网络如果更希望用统一的配置管理组件可以选择 Docker 方案。先检查 Dockerdocker--version创建项目目录的示例里实际创建的是/docker/do但权限命令操作的却是/do。这是两个不同路径不应直接理解为创建目录后已经正确授权而且递归777会让目录对所有用户开放长期部署需要更明确地控制权限。mkdir-p/docker/dochmod-R777/do准备 Loki 与 Promtail 的配置文件下面的命令一次写入两个配置。此时 Loki 使用3100Promtail 通过 Docker 网络里的http://loki:3100/loki/api/v1/push发送日志采集范围包括/var/log/*.log与/var/log/test.log。这些值专属于 Docker 路线不能和上面的8094配置混用。mkdir-p/docker/do/loki# 创建配置文件cat/docker/do/loki/config.ymlEOF auth_enabled:falseserver: http_listen_port:3100common: path_prefix: /tmp/loki storage: filesystem: directory: /tmp/loki/chunks replication_factor:1ring: kvstore: store: inmemory schema_config: configs: - from:2020-10-24 store: boltdb-shipper object_store: filesystem schema: v11 index: prefix: index_ period: 24h EOF# 创建目录mkdir-p/docker/do/promtail# 创建配置文件# 创建配置文件cat/docker/do/promtail/config.ymlEOF server: http_listen_port:9080grpc_listen_port:0positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: system static_configs: - targets: - localhost labels: job: varlogs __path__: /var/log/*.log - job_name:teststatic_configs: - targets: - localhost labels: job:test__path__: /var/log/test.log EOF这段 shell 使用 here-document 写文件实际粘贴执行时需要特别检查EOF结束符是否独占一行、前面没有多余缩进否则可能导致文件写入没有如预期结束。还有一个更容易忽略的地方Loki 数据在配置中位于/tmp/loki但后面的 Compose 没有为它挂载宿主机持久化目录。不能仅凭容器运行就认定日志和索引在容器重建后还会保存。编辑docker-compose.ymlvidocker-compose.ymlversion:3networks: loki: services: loki: image: grafana/loki:2.9.10 ports: -3100:3100volumes: - ./loki/config.yml:/etc/loki/config.yml# 挂载配置command:-config.file/etc/loki/config.yml# 路径匹配networks: - loki promtail: image: grafana/promtail:2.9.10 volumes: - /var/log:/var/log - ./promtail/config.yml:/etc/promtail/config.yml# 挂载配置command:-config.file/etc/promtail/config.yml# 路径匹配networks: - loki user:root# 关键避免权限问题grafana: environment: -GF_PATHS_PROVISIONING/etc/grafana/provisioning -GF_AUTH_ANONYMOUS_ENABLEDtrue -GF_AUTH_ANONYMOUS_ORG_ROLEAdmin entrypoint: -sh--euc-|mkdir-p/etc/grafana/provisioning/datasourcescatEOF/etc/grafana/provisioning/datasources/ds.yaml apiVersion:1datasources: - name: Loki type: loki access: proxy orgId:1url: http://loki:3100 basicAuth:falseisDefault:trueversion:1editable:falseEOF /run.sh image: grafana/grafana:latest ports: -3000:3000networks: - lokiDocker 镜像这里明确是grafana/loki:2.9.10和grafana/promtail:2.9.10与前面下载的v1.5.0不同Grafana 则使用grafana/grafana:latest。Compose 里还通过初始化文件让 Grafana 自动添加名为 Loki 的数据源指向 Docker 网络中的http://loki:3100。但这份 Grafana 环境变量同时设置GF_AUTH_ANONYMOUS_ENABLEDtrue和GF_AUTH_ANONYMOUS_ORG_ROLEAdmin匿名访问者可能获得管理员权限。它可以作为需要重点检查的演示配置却不适合原样配合公网隧道长期开放。Promtail 使用user: root读取主机/var/log也应结合实际日志权限评估。启动后先看容器是否能够运行docker-composeup-d四、从测试日志验证不只看页面是否打开进入 Grafana查看 Loki 数据源、连接测试和 Explore。Compose 中已经包含自动添加数据源的配置界面中的“添加数据源”步骤可用于核对连接不必把两个动作理解成必须重复操作。先向/var/log/test.log写一行测试消息。Docker 的 Promtail 已把主机/var/log挂进容器因此这份日志有明确的采集路径。echoTest log entry at$(date)/var/log/test.log然后调用 Loki 查询接口curl-ghttp://localhost:3100/loki/api/v1/query?query{jobtest}limit5如果响应的values数组出现刚写入的日志就比“Loki 页面可以访问”更能说明文件 → Promtail → Loki已经打通。再进入 Grafana Explore选择 Loki 数据源并运行下面的 LogQL{jobtest}此时完整链路才变成日志文件 → Promtail → Loki → Grafana。如果 Loki API 有数据而 Explore 没显示就该检查 Grafana 的数据源及查询如果 API 也没有数据先查 Promtail 采集路径、发送端地址和 positions 文件。五、加入 JSON、Nginx 和认证日志基础链路跑通以后再模拟更接近真实应用的日志。先创建/var/log/app.json里面分别放入登录成功、数据库超时、限流三条 JSON 日志ts、level、status、path等字段都保留在日志内容中。# 模拟一个 Web 服务日志cat/var/log/app.jsonEOF {level:info,ts:2026-06-04T12:00:00Z,msg:User login,user_id:1001,ip:192.168.1.10,method:POST,path:/login,status:200} {level:error,ts:2026-06-04T12:01:05Z,msg:DB timeout,user_id:1002,ip:192.168.1.11,method:GET,path:/profile,status:500,error:context deadline exceeded} {level:warn,ts:2026-06-04T12:02:30Z,msg:Rate limit hit,user_id:1003,ip:192.168.1.12,method:POST,path:/api/v1/send,status:429} EOF更新 Promtail 的配置让它除了测试日志还收集app.jsonserver: http_listen_port:9080grpc_listen_port:0positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name:teststatic_configs: - targets: - localhost labels: job:test__path__: /var/log/test.log - job_name: app-json pipeline_stages: - json: expressions: level: level msg: msg static_configs: - targets: - localhost labels: job: app __path__: /var/log/app.json这里的pipeline_stages只从 JSON 中提取level和msg。代码没有labels阶段更没有把status配成 Loki 索引标签因此不能把它写成“level、status 已经都成为标签”。后面的 LogQL| json是查询时解析日志内容和写入时建立标签也不是同一个动作。修改配置后重启 Promtaildocker-composerestart promtail在 Explore 中先按错误级别筛选再按 HTTP 状态码筛选{jobapp}|json|levelerror{jobapp}|json|status500还可以用原示例统计请求量sumby(path)(count_over_time({jobapp}[5m]))这里需要注意sum by (path)想按path分组得先确认这个字段是否被解析成可供聚合的标签配置示例本身没有完成该步骤。因此不能根据这一条查询就断言已实现正确的逐路径统计。再模拟 Nginx 访问日志与认证日志# 模拟 nginx 日志echo192.168.1.10 - - [04/Jun/2026:12:10:00 0000] GET /api/v1/data HTTP/1.1 200 1024/var/log/nginx-access.log# 模拟 auth 服务日志echo$(date-Iseconds)[AUTH] User 1001 logged in from 192.168.1.10/var/log/auth.log把它们和原来的测试、应用 JSON 日志一起纳入 Promtail 配置server: http_listen_port:9080grpc_listen_port:0positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name:teststatic_configs: - targets:[localhost]labels: job:test__path__: /var/log/test.log - job_name: app-json pipeline_stages: - json: expressions: level: level msg: msg static_configs:# ← 必须在这里- targets:[localhost]labels: job: app __path__: /var/log/app.json - job_name: nginx static_configs: - targets:[localhost]labels: job: nginx __path__: /var/log/nginx-access.log - job_name: auth static_configs: - targets:[localhost]labels: job: auth __path__: /var/log/auth.log新的标签包括job: test、job: app、job: nginx、job: auth。重启采集端后可以在 Grafana 中切换不同 job根据时间关联认证日志和 Nginx 访问记录。这样做只证明不同来源能进入同一查询入口不等于应用之间已经自动完成链路追踪。六、异地查看日志只为 Grafana 配公网入口本地查询确认以后若需要在另一处网络查看面板可以用 cpolar 映射 Grafana 的3000。这条隧道解决的是浏览器到 Grafana 的网络入口日志依然由 Promtail 采集并送到 Loki不会因为建立公网地址而改由 cpolar 采集。尤其在开放之前应先收紧上面 Docker 配置中的匿名管理员权限并确认登录凭据和访问范围。先安装 cpolar 并查看服务状态sudocurlhttps://get.cpolar.sh|shsudosystemctl status cpolar通过服务器 IP 加9200进入 cpolar 管理界面。示例文字显示的是192.168.42.101:9200所附 Markdown 链接实际指向localhost:9200/使用时按访问设备所在网络选择能到达的地址。进入隧道管理 → 创建隧道填写隧道名称grafana、HTTP、本地地址3000、随机域名、地区China Top。这里的3000是 Grafana不是 Loki 的3100更不是二进制路线的8094。进入在线隧道列表复制生成的公网地址用其他电脑或移动设备测试随机地址能打开 Grafana 后如果需要相对固定的远程入口再到预留页面选择保留二级子域名地区china top本例名称为grafana3。名称具有唯一性以自己账号实际预留成功的结果为准。回到隧道列表编辑grafana把域名类型切换为二级子域名Sub Domain填入刚保留的名称地区选China Top然后更新。再使用固定地址从外部访问公网页面能打开只说明网络入口有效。最后还应登录 Grafana、选择 Loki 数据源、按job查到真实日志才算跨网络查看的使用链路完整。固定域名不意味着主机永远在线也不能代替 Grafana 的身份验证和权限控制。总结把 PLG 当成三个独立职责排障就更有次序Promtail 负责找到文件并推送Loki 负责保存和按标签组织日志流Grafana 负责查询与展示。对我来说真正值得确认的是一条测试日志是否先出现在 Loki API再出现在 Grafana Explore随后才是 JSON 字段过滤、多日志源查询和远程访问。二进制和 Compose 都能表达这套结构但配置不能混搭。v1.5.0与2.9.10、8094与3100、本地数据目录与未持久化的/tmp/loki以及匿名管理员配置都需要按所选路线逐项核对。cpolar 让远程浏览器能打开 Grafana却不替日志系统存储、检索或加固权限把本地链路和公网访问分开处理后面扩展告警或多台服务器时才有稳定的基础。
返回列表