多台服务器日志集中检索前,Promtail权限、网络与Loki标签如何确认?
我们先把现场还原成一条完整链路:每台业务服务器上的 Promtail 读取本机日志,通过网络把日志推送到 Loki,Grafana 再从 Loki 查询和展示。实施前真正需要确认的,不是三个组件能否分别启动,而是 Promtail 运行账户能否遍历并读取目标文件、源服务器能否访问 Loki 的正确 HTTP 地址,以及写入 Loki 的标签是否稳定、唯一且便于检索。
只要这三项通过,集中检索平台通常就具备了可验收的基础条件。反过来,如果文件权限、网络状态或标签设计没有先确认,后续看到“没有日志”“查询不到主机”或“Loki 负载异常”时,很难判断问题究竟出在采集端、传输链路还是查询条件。
先确定这次检查要验证什么
以一组应用日志为例,我们希望在多台服务器上统一采集:
/var/log/myapp/app.log/var/log/myapp/error.log
并在 Grafana 中使用类似下面的查询:
{job="app-file", env="prod", service="order-api", host="node-a"}
这条查询能够返回日志,需要同时满足以下条件:
| 检查项 | 必须确认的内容 | 不满足时的表现 |
|---|---|---|
| 日志文件 | 路径存在,文件会持续写入,轮转后新文件仍符合采集规则 | Promtail 正常运行但没有新日志 |
| 运行权限 | Promtail 账户可以进入父目录、读取文件,并写入 positions 文件 | 日志中出现 permission denied |
| 网络访问 | 源服务器可以解析 Loki 地址并访问正确端口、路径和认证入口 | 连接超时、拒绝连接、401 或 403 |
| 标签设计 | host、job、service 等标签值稳定且可区分 | 查询范围过大、主机无法区分或标签数量快速增长 |
| 时间信息 | 源服务器时间基本一致,日志时间格式和时区明确 | 日志出现在错误时间范围,甚至看起来像“丢失” |
这里的检查应先在一台服务器上完成,再复制到其他节点。不要一开始就在所有主机上同时修改配置,否则一个错误的标签或路径可能迅速产生大量无效数据。
第一步:确认 Promtail 实际使用的账户和路径
查看服务账户,不要凭经验判断。 Promtail 可能由 systemd、容器或其他进程管理器启动。以 systemd 为例,先查看服务定义:
systemctl cat promtail
systemctl show promtail -p User -p Group -p ExecStart
如果服务名不是 promtail,先用下面的命令查找实际服务名:
systemctl list-unit-files | grep -i promtail
重点看三项:
User和Group指向哪个账户;ExecStart使用的是哪份配置文件;positions文件和日志路径是否与当前主机实际目录一致。
有些环境没有显式设置 User,这时不能直接假设 Promtail 一定以 root 运行,应继续查看进程身份:
ps -eo user,group,pid,cmd | grep '[p]romtail'
如果使用容器运行,还要在容器内确认身份和挂载路径。宿主机存在 /var/log/myapp/app.log,并不代表容器内也能看到同一路径。
用目标账户测试目录遍历和文件读取。 Linux 文件读取不只是看文件本身的 r 权限。Promtail 还需要对路径上的每一级目录拥有执行权限,也就是能够“进入”这些目录。我们可以直接以服务账户测试:

namei -l /var/log/myapp/app.log
sudo -u promtail -- test -r /var/log/myapp/app.log && echo "file-readable"
sudo -u promtail -- test -x /var/log && echo "log-dir-traversable"
sudo -u promtail -- find /var/log/myapp -maxdepth 1 -type f -name '*.log' -print
如果服务账户不是 promtail,将命令中的账户替换为前面查到的实际账户。判断时,test -r 失败表示文件本身不可读,或上级目录无法遍历;test -x 失败表示目录权限不足,即使文件显示为可读也无法访问;find 找不到文件,可能是目录权限、文件名匹配规则或路径配置错误。若 namei -l 显示某一级目录没有执行权限,应只调整对应目录的访问策略,不要直接对整个 /var/log 递归放开权限。
如果系统启用了访问控制列表,还要补充查看 ACL:
getfacl /var/log/myapp/app.log
getfacl /var/log/myapp
对于启用 SELinux 的系统,可以确认当前状态和近期拒绝记录:
getenforce
ls -Zd /var/log/myapp /var/log/myapp/app.log
sudo ausearch -m AVC -ts recent | tail -n 20
遇到 SELinux 拒绝时,应按照现有安全策略为目录和服务配置正确的访问上下文,不要为了验证方便直接关闭 SELinux。临时关闭安全控制可能掩盖真正的权限问题,也会扩大影响范围。
检查 positions 文件的写权限。 Promtail 需要记录已经读取到的位置,否则进程重启或主机恢复后,可能出现重复采集或采集位置异常。配置中常见的路径如下:
positions:
filename: /var/lib/promtail/positions.yaml
检查目录和文件权限:
sudo -u promtail -- test -w /var/lib/promtail && echo "positions-dir-writable"
sudo -u promtail -- test -w /var/lib/promtail/positions.yaml && echo "positions-file-writable"
如果目录不存在,创建目录前应先确认服务账户、所属组和现有目录状态。下面的操作只针对新的 positions 目录,不会修改日志目录,也不会修改日志文件:
sudo install -d -o promtail -g promtail -m 0750 /var/lib/promtail
执行前应确认:
promtail是实际运行账户;- 该路径没有保存其他程序的重要文件;
- 变更范围仅为
/var/lib/promtail; - 已记录原有目录的所有者和权限,必要时可恢复;
- 不使用
chmod -R 777或对整个日志目录递归改权。
如果配置错误需要回滚,应先停止或重启对应节点上的 Promtail,恢复备份配置,再检查目录权限。不要删除现有 positions 文件来“解决重复日志”,因为这会改变采集起点,影响范围可能覆盖整个日志目录。
第二步:验证轮转、软链接和时间条件
检查 glob 是否覆盖真实文件。 配置中常见写法如下:
__path__: /var/log/myapp/*.log
这只匹配当前目录下符合条件的文件,不一定覆盖子目录、软链接或特殊命名的轮转文件。可以在目标账户下检查:
sudo -u promtail -- find /var/log/myapp -maxdepth 1 -type f -name '*.log' -printf '%f %s bytes\n'
如果业务日志实际写入的是 /data/myapp/logs/,而配置仍指向 /var/log/myapp/,Promtail 不会因为服务正常就自动发现新路径。
检查轮转后的权限和所有者。 日志轮转常见的风险是:当前文件可读,但轮转后由 logrotate 创建的新文件权限不同。可以先进行无修改的配置检查:
sudo logrotate -d /etc/logrotate.conf
重点观察轮转配置中的新文件创建模式、所属用户和用户组、是否使用压缩、是否通过软链接指向实际日志,以及应用是继续写入原文件还是重新打开新文件。
不要直接用强制轮转命令验证生产日志。更稳妥的方式是先在测试目录验证,或安排低风险时间窗口进行一次受控轮转。验收时应至少覆盖“当前文件持续写入”和“轮转后新文件继续采集”两个状态。
如果日志被写入 journald,而不是普通文件,就不能仅靠 static_configs 和 path 读取。此时需要采用对应的 journal 采集配置,并确认服务账户对 journal 数据的读取权限。文件采集和 journal 采集是两条不同路径,不应混用检查结论。
确认时间和时区。 在每台源服务器上查看时间同步状态:
timedatectl status
date '+%F %T %z'
我们不必要求所有服务器显示完全相同的秒数,但至少应明确时区,并保证系统时间处于可接受范围。若 Promtail 解析应用日志中的时间字段,日志格式、时区和时间戳精度也要一致;否则日志可能已经写入 Loki,却落在 Grafana 当前查询时间范围之外。
第三步:从源服务器验证到 Loki 的网络链路
网络检查应从低风险的 DNS 和 HTTP 访问开始,不要一上来修改防火墙规则。
确认域名、端口和入口路径。 假设 Loki 地址是 loki.internal.example,监听端口为 3100,先检查解析:
getent ahosts loki.internal.example
然后从每台部署 Promtail 的服务器访问 Loki 的就绪接口:
curl -sS -D- \
--connect-timeout 5 \
--max-time 10 \
http://loki.internal.example:3100/ready
通常可以这样判断:
- 返回 HTTP 200,并出现
ready:Loki 当前能够接受就绪检查; Connection refused:目标地址可达,但端口没有服务监听,或监听地址不对;Connection timed out:路由、防火墙、安全组或中间网络策略需要检查;- 401 或 403:网络已到达认证入口,但需要补充认证信息;
- 404:访问路径、端口或前置入口可能不是 Loki 的实际 API;
- 5xx:入口可达,但 Loki 或其后端状态异常。
/ready 是健康检查接口,不要用对 /loki/api/v1/push 发 GET 请求的结果判断推送是否正常。推送接口主要接受 POST,请求方法不正确时返回 405 并不代表网络故障。
用实际配置中的 URL 做一次检查。 Promtail 的客户端配置至少要明确完整 URL:
clients:
- url: http://loki.internal.example:3100/loki/api/v1/push
如果环境使用 HTTPS 或认证,还要确认协议、证书信任、认证头和租户信息与 Loki 端设置一致。不要只测试 http://loki.internal.example:3100,然后在配置中填写另一条路径或另一个域名。
源服务器到 Loki 通常只需要允许出站访问,Loki 不需要主动连接回每台源服务器。Grafana 到 Loki 则是另一条查询链路。这样可以分别定位问题:

- Promtail 能访问 Loki,但 Grafana 查不到:优先看标签、租户和 Grafana 数据源;
- Grafana 能访问 Loki,但 Promtail 访问失败:优先看源服务器到 Loki 的网络;
- 两边都无法访问:先检查 Loki 监听状态和入口配置。
如果需要调整防火墙或安全组,应先备份现有规则,且只放行源服务器网段到 Loki 实际端口。变更前记录原规则,变更后用 curl /ready 和实际采集验证;回滚时恢复原规则,不要用“允许全部来源”的临时规则代替排查。
估算日志流量,避免把网络问题误判成采集问题。 以 20 台服务器、每台平均产生 2 MB/分钟的原始日志为例:
- 汇总速率:20 × 2 MB/分钟 = 40 MB/分钟;
- 换算为比特:40 × 8 = 320 Mb/分钟;
- 换算为秒:320 ÷ 60 ≈ 5.33 Mbps。
这是压缩、协议开销和突发流量之前的原始估算,不是链路实测值。实际验收还应观察业务高峰期的瞬时增长,并确认 Loki 侧的写入限制、认证入口和存储配置不会因为突发流量返回 429 或 5xx。
第四步:设计并验证 Loki 标签
标签应该表达稳定的检索维度。 Loki 标签会参与日志流的组织和索引。一个标签组合的值越多,产生的日志流越多,查询和写入压力也可能随之上升。因此,标签应优先选择数量有限、含义稳定的字段。
| 标签 | 推荐含义 | 适用条件 |
|---|---|---|
host | 采集节点的稳定名称 | 每台服务器必须唯一,不能所有节点都写成同一个值 |
env | prod、test 等环境 | 环境数量有限,命名统一 |
service | 应用或服务名称 | 同一服务在多台主机上保持一致 |
job | 一类采集任务 | 例如 app-file、nginx-access |
level | 日志级别 | 只有 info、warn、error 等有限值时适合 |
不建议把请求 ID、Trace ID、用户 ID、订单号、完整 URL 或带参数的 URL、原始错误信息、精确时间戳,以及每次发布都变化的临时实例标识直接做成标签。这些字段更适合作为日志正文或结构化字段,在查询时使用行过滤或解析条件。比如先用稳定标签缩小范围,再过滤正文:
{job="app-file", env="prod", service="order-api"} |= "timeout"
每台服务器的 host 标签必须不同。 下面是一份适合单台主机的基础配置。部署到其他节点时,至少要修改 host,并确认 path 和 positions 路径真实存在:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://loki.internal.example:3100/loki/api/v1/push
scrape_configs:
- job_name: app-file
static_configs:
- targets:
- localhost
labels:
job: app-file
env: prod
service: order-api
host: node-a
__path__: /var/log/myapp/*.log
这里的 path 是采集匹配规则,不应被当成普通业务标签使用。host: node-a 只是示例值;在第二台服务器上应改成实际且唯一的主机标识,例如 node-b。
如果日志是 JSON,可以只把有限集合的字段提升为标签,例如日志级别。请求 ID、用户 ID 等高变化字段仍保留在正文中,不要为了方便检索而全部标签化。
先验证配置,再启动服务。 修改配置前先保留副本,并确认只影响当前节点:
sudo cp -a /etc/promtail/config.yml /etc/promtail/config.yml.bak
部分 Promtail 版本支持配置语法检查:
promtail -config.file=/etc/promtail/config.yml -check-syntax
如果当前版本不支持该参数,应先查看帮助信息:
promtail -help | grep -E 'check|config'
语法检查通过后,再重启当前节点上的 Promtail:
sudo systemctl restart promtail
sudo systemctl status promtail --no-pager
回滚时恢复备份文件并再次重启:
sudo cp -a /etc/promtail/config.yml.bak /etc/promtail/config.yml
sudo systemctl restart promtail
这个回滚只针对 Promtail 配置,不会删除 Loki 中已经写入的日志,也不会自动恢复错误标签产生的历史数据。
第五步:做一次端到端验收
配置和网络都通过后,我们按照“源文件—Promtail—Loki—Grafana”的顺序验收,不要只看服务状态为 active。
先看 Promtail 是否真正读取到了文件。
journalctl -u promtail --since "10 minutes ago" --no-pager
重点搜索以下线索:permission denied 时回到目录、文件和 SELinux 权限检查;connection refused、timeout 时回到 DNS、端口和网络策略;出现 401、403 时检查认证和租户信息;没有报错但没有日志时,检查 glob、positions、文件是否持续写入和时间范围。
“Promtail 没有报错”只能说明进程可能正常,并不能证明日志已经到达 Loki。
在 Loki API 中按标签查询。 可以从一台能够访问 Loki 的服务器执行查询。下面的查询会返回最近匹配到的日志流:
LOKI_URL='http://loki.internal.example:3100'
curl -G -sS "${LOKI_URL}/loki/api/v1/query_range" \
--data-urlencode 'query={job="app-file",env="prod",service="order-api",host="node-a"}' \
--data-urlencode 'limit=20'
如果返回数据,说明至少完成了从标签写入到查询的闭环。如果返回空结果,按以下顺序检查:
- 查询的
host是否与配置中的值完全一致; - Grafana 或 API 查询的时间范围是否覆盖日志写入时间;
- 是否连接到了正确的 Loki 租户;
/loki/api/v1/labels是否能看到预期标签;- Promtail 是否实际读取了目标文件。
也可以先查看标签名:
curl -sS "${LOKI_URL}/loki/api/v1/labels"
标签名存在但查询不到数据,通常是标签值、时间范围或租户不一致;标签名本身也不存在,则优先检查 Promtail 是否成功推送。
在 Grafana 中验证可用查询。 Grafana Explore 中先使用稳定标签查询:
{job="app-file", env="prod", service="order-api", host="node-a"}
确认结果后,再增加正文过滤:
{job="app-file", env="prod", service="order-api"} |= "error"
最后用另一台服务器执行同样的查询,只改变 host 值。如果 node-a 能查到、node-b 查不到,应比较两台主机的运行账户、日志路径、网络地址和 Promtail 配置,而不是立即修改 Loki 查询语句。
常见失败现象与处理方向
| 现象 | 优先判断 | 处理方向 |
|---|---|---|
| 服务 active,但没有任何日志 | 文件路径或 glob 不匹配 | 以 Promtail 账户执行 find 和 test -r |
| 报目录权限错误 | 缺少父目录执行权限 | 用 namei -l 逐级检查,不要递归放开权限 |
能访问 /ready,但推送返回 401/403 | 认证或租户不匹配 | 核对客户端 URL、认证头和租户设置 |
| 连接超时 | 网络策略或路由问题 | 从源服务器测试解析、端口和 HTTP 入口 |
| 标签 API 没有预期标签 | 没有成功写入或查错租户 | 查看 Promtail 日志和 Loki 接收端日志 |
| 日志写入了但 Grafana 查不到 | 标签选择器或时间范围错误 | 先用 /labels 和宽时间范围确认 |
| 轮转后日志消失 | 新文件权限或路径不匹配 | 检查轮转创建规则和 path |
| 同一条日志重复出现 | 多个采集器或 positions 异常 | 确认同一文件只有一个采集任务负责 |
回到这次验收,哪些条件可以作为上线门槛
我们可以把上线前的判断收敛成四个问题:
- Promtail 运行账户能否读取每一个目标文件,并能写入 positions 文件?
- 源服务器能否访问 Loki 的准确 URL,认证和租户是否与服务端一致?
- 每台主机的
host是否唯一,job、service、env是否保持统一? - 经过轮转、重启和 Grafana 查询后,日志仍能按主机和服务稳定检索?
四项都通过,再批量部署到其他服务器,问题范围会明显收窄。需要特别注意的是,集中采集只能处理 Promtail 实际能够读取到的日志;历史文件是否补采、压缩轮转文件是否纳入范围、journal 日志是否单独配置,都必须在本次验收中明确。标签也不应随着临时排障不断增加,而应保留少量稳定维度,把高变化信息放在日志正文中。这样搭建出的 Promtail、Loki、Grafana 平台,才更适合长期进行跨服务器集中检索。