上一篇 下一篇 分享链接 返回 返回顶部

香港CN2线路不稳定排查时,如何检查监控日志权限与服务身份

发布人:Minchunlin 发布时间:2026-09-30 20:30 阅读量:4
香港CN2线路不稳定排查时,如何检查监控日志权限与服务身份

当访问香港CN2线路上的服务出现间歇性超时、连接时好时坏,而监控面板又存在数据空洞、日志延迟或告警时,问题不一定发生在线路本身。监控进程无法读取目标日志、无法写入状态目录、轮转后失去新日志权限,或者服务实际运行用户与预期不一致,都可能把“观测中断”误判为“线路不稳定”。

排查“香港CN2线路不稳定是什么原因,该怎么排查”时,建议按照低风险到高风险的顺序进行:先用独立探测确认故障是否真实存在,再核对监控服务身份和日志来源,随后逐级检查用户、用户组、目录遍历权限、文件读写权限、日志轮转以及systemd安全限制,最后才进行最小范围的权限修复。每次修改后,都要以监控用户身份复测,不能只用root查看结果。

先确认:线路波动还是监控观测中断

权限问题通常不会直接造成网络链路丢包,但会造成以下几类假象:

  • 监控服务本身仍显示运行中,但无法读取目标日志,导致图表停止更新。
  • 监控日志只记录到某个时间点,之后出现空白,面板可能被解释为超时或无响应。
  • 日志轮转后,新文件由不同用户或用户组创建,监控服务突然失去读取权限。
  • 服务可以启动,却无法写入状态目录、临时目录或检查点文件,随后反复重启。
  • root查看日志正常,但以监控服务身份执行相同操作失败。

先记录故障发生时间、目标地址、监控服务名称以及监控日志最后一条记录的时间。以下命令适用于使用systemd的Linux服务器,命令本身为只读检查:

date -Is
systemctl list-units --type=service --state=running --no-pager

如果服务提供可访问的业务端口,可以在服务器或授权的探测主机上进行低频、受控的连接测试:

ping -c 20 -i 0.2 <目标地址>

如果目标是HTTP服务,也可以使用:

curl --connect-timeout 5 --max-time 10 -sS -o /dev/null \
  -w 'time_connect=%{time_connect} time_starttransfer=%{time_starttransfer} http_code=%{http_code}\n' \
  https://<目标域名或地址>/

ping存在丢包而业务请求正常时,不能直接判定线路故障,因为ICMP和业务流量的处理方式可能不同。反过来,如果业务请求确实超时,但监控日志在同一时刻停止更新,应先处理监控权限和服务身份,避免把日志缺失当成网络证据。

可以用下面的结果快速分支:

观察结果更可能的含义下一步
独立请求异常,监控日志持续写入故障可能真实存在,监控权限不是首要原因保留监控证据,转入线路和目标服务的独立排查
独立请求正常,监控日志停止更新监控进程、日志读取或状态写入存在问题检查服务身份和文件权限
root能读日志,监控用户不能读用户、用户组、ACL或目录遍历权限不匹配按路径逐级检查权限
当前日志可读,轮转后的日志不可读日志轮转创建文件时的属主、属组或模式不正确检查轮转规则和新旧文件权限
文件权限看起来正常,但服务仍报拒绝访问systemd沙箱、SELinux或AppArmor等额外控制生效查看拒绝记录和服务限制

第一步:确认监控服务到底使用哪个身份

不要根据配置文件中的用户名猜测运行身份。systemd服务可能通过User=、Group=、SupplementaryGroups=、DynamicUser=或启动脚本改变实际身份,主进程和子进程也可能不同。

先定义需要检查的服务单元名称。下面的<监控服务>.service必须替换为实际服务名:

UNIT="<监控服务>.service"

sudo systemctl status "$UNIT" --no-pager
sudo systemctl show "$UNIT" \
  -p User \
  -p Group \
  -p SupplementaryGroups \
  -p DynamicUser \
  -p MainPID \
  -p ExecStart \
  -p StandardOutput \
  -p StandardError

重点看以下字段:

  • User=:主服务进程的用户。
  • Group=:主服务进程的主用户组。
  • SupplementaryGroups=:额外用户组,读取日志时经常依赖该字段。
  • DynamicUser=yes:服务使用临时身份,不能简单按照固定用户名授权。
  • MainPID=:当前主进程编号。
  • StandardOutput=和StandardError=:判断日志究竟写入journald、文件还是其他位置。

如果User=为空,通常表示服务使用默认身份运行,常见情况下是root,但仍应结合服务文件和进程结果确认,不要直接据此修改权限。继续检查主进程及其子进程:

PID="$(sudo systemctl show "$UNIT" -p MainPID --value)"

sudo ps -o pid,ppid,user,group,egroup,args -p "$PID"
sudo systemctl cat "$UNIT"

如果服务启动了多个工作进程,可以查看同一服务相关进程:

sudo ps -eo pid,ppid,user,group,egroup,args --forest

若看到监控程序使用的是monitor,后续所有读取测试都应以monitor身份执行;如果实际身份是临时用户,则应先确认systemd为该服务分配的运行环境,再决定授权方式。不要为了方便把日志目录改成所有用户可读,也不要把服务改为root运行作为临时修复。

第二步:确定日志来源和实际路径

监控日志可能来自三种位置:

  1. systemd journal;

2.应用或监控程序写入的普通日志文件; 3.服务运行时写入的状态、缓存或检查点目录。

先以管理员身份查看服务近期输出,再用监控用户执行同样的读取操作,比较二者结果:

sudo journalctl -u "$UNIT" --since "30 min ago" --no-pager
sudo -u monitor -- journalctl -u "$UNIT" --since "30 min ago" --no-pager

这里的monitor只是示例,必须替换为上一步确认的实际用户。如果第一条命令有日志、第二条命令提示权限不足或没有任何记录,问题很可能是journal读取权限,而不是日志内容本身消失。

如果日志写入普通文件,需要从服务配置、启动参数或程序配置中确认完整路径。不要只检查文件本身,还要检查路径上的每一级目录。例如目标文件是:

/var/log/example/monitor.log

需要同时检查/var、/var/log、/var/log/example和monitor.log。Linux读取文件要求:

  • 对文件本身具备r权限;
  • 对文件所在目录具备x权限;
  • 如果要列出目录内容,还需要目录的r权限;
  • 如果要创建、重命名或删除日志文件,需要目录同时具备w和x权限。

第三步:逐级检查用户、用户组和目录权限

先查看用户和组是否存在,以及服务实际拥有的附加组:

id monitor
getent passwd monitor
getent group

随后查看路径上每一级目录和文件的权限:

namei -l /var/log/example/monitor.log
stat -c '%A %a %U %G %n' \
  /var \
  /var/log \
  /var/log/example \
  /var/log/example/monitor.log

如果系统没有namei,可以分别执行:

ls -ld /var /var/log /var/log/example
ls -l /var/log/example/monitor.log

更重要的是,以监控服务身份进行实际测试。以下命令不会修改文件:

sudo -u monitor -- test -r /var/log/example/monitor.log \
  && echo "file-readable" \
  || echo "file-not-readable"

sudo -u monitor -- test -x /var \
  && echo "/var-traversable" \
  || echo "/var-not-traversable"

sudo -u monitor -- test -x /var/log \
  && echo "/var/log-traversable" \
  || echo "/var/log-not-traversable"

sudo -u monitor -- test -x /var/log/example \
  && echo "app-log-dir-traversable" \
  || echo "app-log-dir-not-traversable"

如果监控程序还需要写入状态文件,应检查目录而不是只检查一个不存在的文件:

sudo -u monitor -- test -w /var/lib/example \
  && echo "state-dir-writable" \
  || echo "state-dir-not-writable"

sudo -u monitor -- test -x /var/lib/example \
  && echo "state-dir-traversable" \
  || echo "state-dir-not-traversable"

结果含义如下:

  • file-not-readable:文件属主、属组、模式或ACL不允许该用户读取。
  • app-log-dir-not-traversable:即使文件显示为可读,监控用户也无法进入父目录,实际仍然读不到。
  • state-dir-not-writable:监控服务可能无法保存状态、游标或检查点,容易出现重复告警、数据中断或重启。
  • root测试成功、监控用户测试失败:优先修复身份和权限,不要据此判断线路正常或异常。

-所有测试成功但应用仍报权限错误:继续检查systemd沙箱和安全策略。

如果文件使用了ACL,仅查看传统的ls -l可能不够,需要执行:

getfacl -p /var/log/example
getfacl -p /var/log/example/monitor.log

输出中的mask::会影响用户组和命名用户ACL的最终有效权限。即使看到user:monitor:r--,如果有效掩码不允许读取,实际测试仍可能失败。

第四步:检查日志轮转和新文件权限

“当前日志可读、过一段时间又失效”是权限排查中很常见的分支。原因通常不是原文件突然变化,而是日志轮转后生成了新的文件,新文件的属主、属组或模式不同。

先列出同一目录下的当前日志和历史日志:

ls -la /var/log/example
stat -c '%A %a %U %G %n' /var/log/example/*

再检查轮转配置,但不要直接执行会产生轮转动作的命令:

sudo grep -R "/var/log/example" /etc/logrotate.conf /etc/logrotate.d 2>/dev/null
sudo logrotate -d /etc/logrotate.conf

logrotate -d用于调试和查看计划,通常不会执行实际轮转。重点核对:

  • 新建日志文件的属主和属组;
  • 新建日志文件的模式是否包含监控用户所需的读取权限;
  • 轮转后目录是否仍允许监控用户遍历;
  • 应用是否重新打开了新日志;
  • 监控程序读取的是固定路径、软链接,还是已打开的文件描述符。

如果服务使用systemd journal,则不应把普通文件权限修复方法套用到journal上,应单独检查监控服务是否有读取journal的权限。可以先确认系统是否存在相关用户组:

getent group systemd-journal

将监控服务加入能够读取系统journal的组,可能扩大其可见日志范围。只有在确有必要且符合权限策略时才采用,优先考虑让监控程序读取专用日志文件或经过明确授权的日志来源。

第五步:排除systemd沙箱和安全策略限制

当传统权限测试全部通过,但服务日志仍出现Permission denied、Read-only file system或无法创建状态文件时,可能是systemd对服务设置了额外限制。

检查相关属性:

sudo systemctl show "$UNIT" \
  -p ProtectSystem \
  -p ReadOnlyPaths \
  -p ReadWritePaths \
  -p InaccessiblePaths \
  -p PrivateTmp \
  -p NoNewPrivileges \
  -p SupplementaryGroups

常见判断方式:

  • ProtectSystem限制了服务对系统目录的写入;
  • ReadOnlyPaths将某些路径设为只读;
  • ReadWritePaths只允许服务写入明确列出的目录;
  • InaccessiblePaths使路径对服务不可见;
  • SupplementaryGroups没有包含日志读取所需的组;
  • PrivateTmp=yes使服务看到的是独立临时目录,不能假设它能访问主机上的临时文件。

如果系统启用了SELinux或AppArmor,还要查看是否存在拒绝记录:

getenforce 2>/dev/null || true
sudo ausearch -m AVC -ts recent 2>/dev/null
sudo journalctl -k --since "30 min ago" --no-pager \
  | grep -Ei 'apparmor|denied|audit'

这类限制不能通过盲目增加chmod权限解决。尤其不要为了验证而关闭SELinux、AppArmor或systemd保护。应根据拒绝记录确认具体路径,再修改正确的安全策略或服务白名单。

第六步:采用最小权限方式修复

修复前先保存当前状态,避免修改后无法恢复。以下命令只用于备份权限信息:

sudo getfacl -p /var/log/example > /root/example-dir.acl.before
sudo getfacl -p /var/log/example/monitor.log > /root/monitor.log.acl.before
sudo systemctl cat "$UNIT" > /root/"$UNIT".before

仅需读取单个日志文件时

如果监控用户只需要读取某一个日志文件,可以使用ACL授予精确权限,而不是把目录改成对所有用户开放:

sudo setfacl -m u:monitor:r /var/log/example/monitor.log
sudo -u monitor -- test -r /var/log/example/monitor.log \
  && echo "read-test-passed" \
  || echo "read-test-failed"

如果父目录缺少遍历权限,还需要对必要的目录授予x权限。但必须先用namei -l确认是哪一级缺失,不要对整个/var或/var/log进行递归放宽。

该修改的影响范围是指定用户和指定文件。回滚时使用之前保存的ACL:

sudo setfacl --restore=/root/monitor.log.acl.before

如果日志轮转后仍然失效,说明只修复当前文件不够,应在轮转规则中固定新文件的属主、属组和读取模式,再通过测试轮转后的新文件进行验证。

需要读取同一目录下多个日志时

如果监控服务确实需要读取某个专用日志目录,可以考虑使用专用用户组。但要确认该组不会让监控用户看到无关的敏感文件。修改前记录目录原属主、属组和模式:

stat -c '%A %a %U %G %n' /var/log/example
getfacl -p /var/log/example > /root/example-dir.before

如果已有合适的日志读取组,应只将监控用户加入该组,并通过轮转规则让新日志继承正确的组和读取模式。用户组变更通常需要重启监控服务或重新建立登录会话后才会生效:

sudo usermod -aG <已确认的日志读取组> monitor
sudo systemctl restart "$UNIT"

该操作会影响监控服务的组成员关系,并可能造成短暂采集间隔。执行前应确认服务允许重启,且已经保存当前配置。回滚时移除新增的附加组,并再次重启服务:

sudo gpasswd -d monitor <已确认的日志读取组>
sudo systemctl restart "$UNIT"

不要直接使用递归chmod -R 777或把服务改为root。前者会扩大所有用户的访问范围,后者会扩大服务进程受到入侵时的影响面,也无法解决轮转规则和安全策略不匹配的问题。

服务只能写入指定状态目录时

如果systemd启用了只读保护,正确做法通常是把实际需要写入的目录加入允许列表,而不是关闭整体保护。修改前保存服务单元内容,并确认目录用途仅限于状态或检查点:

sudo systemctl cat "$UNIT" > /root/"$UNIT".before
sudo ls -ld /var/lib/example

编辑专用的systemd覆盖配置:

sudo systemctl edit "$UNIT"

加入类似内容,路径必须替换为实际状态目录:

[Service]
ReadWritePaths=/var/lib/example

保存后重新加载配置:

sudo systemctl daemon-reload
sudo systemctl restart "$UNIT"

该修改会改变服务可写路径,影响范围是指定目录。不要随意添加根目录、整个/var或其他包含敏感数据的路径。如果确认覆盖配置有误,且该覆盖文件就是本次新增的,可以回滚:

sudo systemctl revert "$UNIT"
sudo systemctl daemon-reload
sudo systemctl restart "$UNIT"

执行systemctl revert前必须确认该服务没有其他需要保留的覆盖配置,否则应手动删除本次新增的配置片段,而不是一次性移除全部覆盖文件。

修复后的验证方法

权限修复不能只看systemctl status显示active。至少要完成以下验证。

以服务身份重新读取和写入测试

读取日志:

sudo -u monitor -- test -r /var/log/example/monitor.log \
  && echo "log-readable" \
  || echo "log-not-readable"

如果服务需要写入状态目录,可以在非生产目录执行临时写入测试。不要直接在正式状态目录创建未知文件;更稳妥的方式是使用程序自身的检查模式,或在维护窗口观察其是否能生成状态文件。

对比管理员和服务用户看到的日志

sudo journalctl -u "$UNIT" --since "10 min ago" --no-pager
sudo -u monitor -- journalctl -u "$UNIT" --since "10 min ago" --no-pager

两者应在权限允许的范围内得到一致的目标服务记录。如果管理员能看到新日志,而服务用户仍看不到,说明权限修复没有覆盖实际日志来源。

检查服务身份是否保持预期

sudo systemctl show "$UNIT" \
  -p User \
  -p Group \
  -p SupplementaryGroups \
  -p MainPID

PID="$(sudo systemctl show "$UNIT" -p MainPID --value)"
sudo ps -o pid,ppid,user,group,egroup,args -p "$PID"

重启后身份变化,通常意味着配置文件、动态用户或启动方式仍未统一。应以重启后的实际进程身份为准重新检查,不要沿用重启前的判断。

验证日志轮转后的权限

先进行配置调试,不要在业务高峰期强制轮转:

sudo logrotate -d /etc/logrotate.conf

在经过批准的维护窗口完成轮转后,再查看新文件:

ls -la /var/log/example
sudo -u monitor -- test -r /var/log/example/monitor.log \
  && echo "new-log-readable" \
  || echo "new-log-not-readable"

如果新文件再次不可读,应修复轮转创建规则,而不是反复对当前文件执行setfacl。

复测与持续观察

完成权限修复后,重新执行独立连接测试,同时观察监控日志、服务日志和状态文件的时间戳是否连续。判断修复是否有效,至少要满足以下条件:

  • 监控用户可以读取实际日志来源,而不只是读取某个旧文件;
  • 服务重启后,运行用户、主用户组和附加组仍符合预期;
  • 日志轮转后,新文件仍具备必要的读取权限;
  • 状态目录可写,但服务没有因此获得无关目录的写权限;
  • 监控日志不再出现权限拒绝、无法打开文件或状态保存失败;
  • 独立探测与监控记录的异常时间能够对应起来。

如果独立探测持续超时或丢失,而监控服务能够连续写入日志、读取目标文件、完成轮转并正常保存状态,那么权限问题就不是主要原因。此时应保留已确认的监控证据,避免继续扩大文件或服务权限,再转入线路路径、目标服务和连接协议的独立排查。

目录结构
全文