OpenVPN 的日志归谁管:守护进程、rsyslog 还是 logrotate?
一个写入方、一个轮转方、一套保留策略。先定路径,为过滤规则给守护进程起名,再用一个轮转后的文件验证重新打开。
日志轮转会以可预期的方式坏掉:三个组件各自以为文件归自己管,结果是一个被轮转的日志继续长大,而新文件始终为空。守护进程握着描述符,logrotate 改名了路径,rsyslog 却写在完全不同的地方。在往上堆规则之前,先选定一个写入方和一个轮转方。下面的清单按这个顺序推进,因为后面每一步都依赖它。
先决定谁写这个文件
两种设计都成立。第一种由 VPN 进程通过自己的 log 或 log-append 选项直接写文件。第二种把记录送给系统日志,由 rsyslog 或 journald 决定落点。
两者是替代关系,不是层级。同时启用的主机会得到两份互相矛盾的文件,而你正在读的往往是比较旧的那份。有意选定一条路径,然后把另一个写入方去掉。
动手之前先读服务的真实生效配置,包括可能覆盖 unit 文件的 drop-in。你在编辑过的配置里看到的指令,并不能证明它就是 运行中的进程实际加载的那一条。把 unit 与进程参数对照,再与它真正打开过的文件对照。
给守护进程起名,好让过滤规则足够窄
走 syslog 这条路时,给守护进程一个明确标识,并按它过滤。匹配本实例程序名的规则,能把记录挡在共享文件之外,而那份文件的保留策略属于别的东西。
窄规则还能让下一个问题答得出来:这一行是哪个服务产生的?匹配所有含 VPN 字样的过滤器会乐于把第二条隧道的流量也收进来,两边都变模糊。要匹配 unit 传给日志的精确标识。
动作之后关闭规则,记录才不会又落到默认目的地去。两个文件里出现重复行,看起来像记录故障,其实是一个缺失的停止。这一处遗漏还会让保留策略的磁盘成本翻倍。
轮转,但别丢掉描述符
守护进程自己写文件时,logrotate 只是改了路径名,进程仍握着打开的描述符。新记录继续写进改过名的文件,直到有什么东西迫使进程重新打开原路径;所以轮转可能看起来成功,而新文件一直是空的。
解决方法是 postrotate 动作,触发服务文档写明的重载或重启行为。给日志发信号完全是另一回事,对握着自有文件的守护进程毫无作用。
无法重新打开时 copytruncate 是退路:先复制文件,再就地截断。它以丢失复制与截断之间写入的内容为代价保住描述符,所以这是取舍而不是解决方案。高负载下,那段空隙可能正好吞掉你想抓的故障。
每个文件只选两种之一,并把选择写下来,因为同一条路径上混用会留下日后极难归因的空隙。在一个目录里同时看到两种模式的人,说不出哪一种才是准的。
按事故回溯窗口来定保留
保留时长、压缩和大小上限应当来自你实际会回溯多远。带压缩和大小上限的七天窗口对许多部署是合理起点,从教程里抄来的数字不是。
策略只放在一处。如果 logrotate 轮转文件,rsyslog 也轮转它,第二次轮转就会胜出,第一套命名规则只剩杂乱。选一个归属方,关掉另一处轮转,并把决定记在策略旁边。
rsyslog 的文档讲的是它的路由与动作模型,而守护进程自身的日志选项仍以 OpenVPN 服务文档为准。两者都不会替你决定保留策略。
测一次轮转和一个新事件
强制轮转一次,然后制造一个新事件,例如一次失败的认证。确认新记录出现在新文件里,而旧文件不再增长。
也要看新文件的权限,因为用另一个属主重建它的轮转会打断下一次写入,留下一个看起来像崩溃的空隙。离开之前把属主和模式与服务账户比对。随后确认压缩归档可读,因为打不开的归档不算保留。快速读一遍旧文件里最新的记录,压缩与权限就都验证了。
最后把每一步的归属方记录下来:哪个组件写、哪个轮转、保留策略放在哪里。正是这份记录,让下一次日志事故变成五分钟的核对,而不是花一下午猜是哪一层把日志行弄丢了。