重新加载 systemd-journald 配置

W K*_*han 8 linux logs systemd systemd-journald

不知道为什么会这样。我有一个测试服务,每 10 秒将一些任意文本记录到 stdout。这是我的服务文件/etc/systemd/system/samplego.service

[Unit]
Description=Sample go app
After=network.target

[Service]
SyslogIdentifier=my-samplego
ExecStart=/opt/samplego/samplego
Restart=on-failure

[Install]
WantedBy=multi-user.target 
Run Code Online (Sandbox Code Playgroud)

这很有效,我可以使用journalctl.

但是,如果我更改了设置/etc/systemd/journald.conf,例如forwardtosyslog=yes,然后 issue systemctl restart systemd-journald,我的应用程序将停止记录,并且在journalctl -fissue 之前我看不到更新systemctl restart samplego。重新启动后是否必须重新启动所有服务journald

Jde*_*eBP 18

1990 年代中期 daemontools 的主要创新之一是可靠日志记录的想法。守护程序主管运行两个守护程序,守护程序和日志守护程序。它在调用之前打开一个管道,将管道的写入端作为守护进程的标准输出,将管道的读取端作为日志守护进程的标准输入。它本身保持打开的文件描述符到管道的两端。因此,如果日志守护程序死亡或终止,然后重新启动,则写入管道的日志数据将被保留并可供新重新启动的日志守护程序实例读取和记录,因为管道不会关闭。

systemd 设计人员没有从这个设计中学习。

systemd安排派生的服务进程,在配置的情况下,将它们的标准输出通过套接字发送到日志进程。但是,而不是如在daemontools的情况下,打开一个管道并安排每个进程继承管的适当端,systemd采用了AF_LOCAL在流套接字/run/systemd/journal/stdout。主进程作为客户端连接;日志进程作为服务器进行侦听。

这意味着数据连接具有客户端-服务器套接字语义而不是继承的管道语义。如果服务器死机,连接就会消失。所有缓冲的日志数据都将丢失,主守护进程写入的所有进一步数据都将转到关闭的套接字并丢失。(这就是为什么 systemd 有一个IgnoreSIGPIPE默认设置为 true 的部分原因。将日志输出写入关闭的套接字也会导致内核尝试杀死正在写入日志的守护进程。)

因此,如果您终止systemd-journald进程,进程出口将关闭与所有守护进程的套接字连接,这些进程的输出正在记录,并且所有进一步的输出都将丢失。没有办法从中恢复并将主进程的输出重新连接到日志进程。必须重新启动所有主要进程,以便systemd重新打开与(新创建的)日志服务器的客户端连接。

systemd 人员在 2016 年解决了这个问题。它涉及添加进程的能力,将他们自己选择的任意打开的文件描述符推送到进程 #1,然后再拉取它们。 systemd-journald使用服务器端连接到它正在记录的客户端来执行此操作,以便它们在重新启动日志记录守护程序本身时保持打开状态。

这种机制的问题在于它需要做更多的工作来确保它的安全,而 systemd 人员在设计安全事物方面没有良好的记录,仅今年的事件就证明了这一点。它需要更多的工作,因为可以将什么多少打开的文件描述符推送到进程 #1 中,以及需要访问控制和限制多长时间。否则有很多可能的漏洞利用。(在 daemontools 设计中,服务管理器进程本身就是打开文件描述符的东西,因此它可以绝对控制它为子进程打开的文件描述符。它不能被欺骗、滥用或淹没。)

在 Laurent Bercot 的 s6 中,s6-svscan使用主服务和日志服务之间的管道执行通常的 daemontools 操作。它还具有保持任意文件描述符打开的机制。这不是通过在进程 #1 中的服务管理器中以超级用户权限运行的代码来完成的,就像在 systemd 中一样。它是由一个完全没有特权的进程完成的,该进程与服务管理器分开运行。

进一步阅读