在不破坏写入进程的前提下轮转 VPN 看门狗日志
先确定输出去向,再让轮转方式与写入进程打开文件的方式一致:短命检查用改名,守护进程用重开或 copytruncate。
一项 VPN 健康检查每分钟追加一行,会悄悄带来第二项职责:决定这些行如何离开磁盘。修好隧道对这项职责毫无帮助,而给文件改名也不会重定向仍然持有旧描述符的进程。先回答输出去向的问题,再让轮转方式与写入进程打开文件的方式一致。
先确定输出去向,再定轮转策略
已经把输出送进日志的 systemd 单元把保留集中在一处。journald 会强制执行 SystemMaxUse 和 MaxRetentionSec 之类的限制,因此在那里写日志的看门狗无需额外工作就继承了边界。在它旁边再加一个没有上限的文件,只会让维护量翻倍而没有收益。
专用文件之所以值得,是因为还有别的东西在读它:解析器、审计导出,或期望路径稳定的页面。做出这个决定后,文件的所有者、权限模式和轮转策略必须一起写下来,因为三者只有作为一个整体才正确。任何人都能创建的路径,也是任何人都能替换的路径,所以目录权限要写进同一份说明。把这些都写在检查旁边,下一次修改就从同样的事实出发。
让配置与写入进程匹配
从这样的写入进程开始:每次调用都打开路径,追加一行,然后退出。这种模式无需进程配合就能挺过轮转,因为下一次运行打开的是当时位于该路径的文件。下面的配置保留一周的版本,并按写入进程所需的所有者和模式重建文件:
/var/log/vpn-watchdog.log {
daily
rotate 7
create 0600 root root
missingok
notifempty
}
logrotate 手册把数量定义为保留的轮转版本数,而不是保证七天历史;daily 关键字是在任务运行时才被评估,并不自己充当调度器。多数发行版里 systemd 定时器或 cron 条目已经拥有那次调用,所以添加第二个之前先确认哪一个存在。让所有者匹配比保留数量更重要。把只属于 root 的模式复制到由服务账户写入的文件上,会在下一次轮转时让日志停掉,而故障要过几个小时才以陈旧时间戳而不是报错的形式出现。从别处复制配置之前先确认写入进程的用户。
从不重新打开的写入进程需要另一种解法
长期运行且持有打开描述符的进程会继续写进被改名的 inode。空间不会释放,可见文件也不再增长,看起来像轮转坏了,直到你检查 inode。要么教会进程重新打开,要么让轮转改为复制后截断而不是改名。
在软件支持的地方,重开路径更干净:发送文档中给出的信号,或运行文档中给出的命令,让进程自己打开新文件。另一种做法是 copytruncate :把内容复制到轮转后的名字,然后在原地截断原文件,描述符仍然有效,但复制与截断之间落下的写入会丢失。
对由 systemd 启动的单元,把 StandardOutput 指向日志或某个文件,让单元掌管生命周期。用不设大小上限、通过 tee -a 追加的 shell 循环,正是故障期间填满分区的做法,因为失败的检查往往比健康的检查记录多得多。
不等定时器就测试轮转
调试模式只报告会发生什么,不动任何东西,所以它是修改之后安全的第一步。满意后强制执行一次真正的轮转,然后确认下一行日志落进新文件而不是被改名的文件:
logrotate -d /etc/logrotate.d/vpn-watchdog logrotate -f /etc/logrotate.d/vpn-watchdog ls -l /var/log/vpn-watchdog.log* tail -n 3 /var/log/vpn-watchdog.log df -h /var/log
按这个顺序读输出。调试运行应当报出文件及其打算执行的动作;强制运行应当产生你预期的轮转名;tail 应当显示写入进程再次运行后的新条目。df 的值在增长而可见文件在缩小,说明就是上面描述的描述符问题。
把强制运行重复两次,看看版本已经存在时保留行为如何。删除最旧的文件是预期结果;没有删除通常意味着轮转名里的数量或通配符与 logrotate 实际创建的不一致。
保留回滚手段和书面记录
编辑前保存上一份配置,并记下由哪个调度器运行它,因为只恢复文件而不恢复定时器的回滚会重现原问题的一半。恢复后手动轮转一次,然后确认写入进程的账户能写日志路径。如果服务在 systemd 下运行,改动其输出重定向后要重新加载单元,因为运行中的进程仍在往旧目标写。自己读接下来几行日志,而不是相信单元干净地回来了。
把权限模式、所有者、保留数量和预期磁盘预算记在检查本身旁边。以后检查从一次性脚本变成守护进程时,轮转策略必须随之改变,那条说明会告诉下一个人是哪个假设被打破了。
最后,把日志决定和恢复决定分开。失败的探测应当遵循连接自身的恢复策略,而不是藏在 logrotate 里的规则;任何日志安排都不应成为重启一条正常隧道的理由。