由于 bind9 尚未真正准备好,iptables 服务因 systemd 而失败

由于 bind9 尚未真正准备好,iptables 服务因 systemd 而失败

我正在尝试在 systemd.service 脚本中调用 iptables-restore。我有几个规则需要 DNS 查找。我在防火墙的 Unit 部分中包含了 After=bind9.service。但是,systemd 认为 bind9 是在它分叉时启动的,而不是在 named 准备好处理请求时启动的。它在解析主机名之前启动了 iptables-restore,因此失败了。以下是系统日志的相关部分:

12 月 13 日 21:29:02 fw systemd[1]:已启动 BIND 域名服务器。
12 月 13 日 21:29:02 fw systemd[1]: 已达到目标主机和网络名称查找。
12 月 13 日 21:29:02 fw systemd[1]: 开始加载 iptables 规则...
12 月 13 日 21:29:02 fw systemd[1]:已启动 Homebridge HomeKit 桥。
12 月 13 日 21:29:02 fw systemd[1]: 正在启动 OpenBSD 安全 Shell 服务器...
12 月 13 日 21:29:02 fw sh[1841]: iptables-restore v1.6.0: 未找到主机/网络“example.com”
12 月 13 日 21:29:02 fw sh[1841]: 错误发生在第 24 行
12 月 13 日 21:29:02 fw sh[1841]: 请尝试“iptables-restore -h”或“iptables-restore --help”获取更多信息。
12 月 13 日 21:29:02 fw 命名 [1838]:启动 BIND 9.10.3-P4-Ubuntu <id:ebd72b3> -f -4 -u bind

这是服务文件:

[单元]
描述=加载 iptables 规则
之后=bind9.service

[安装]
WantedBy=多用户.目标
WantedBy=network-online.target

[服务]
类型=oneshot
退出后继续保留=是
ExecStart=/bin/sh -c “/sbin/iptables-restore < /etc/iptables.up.rules”

让 iptables-restore 命令在启动时执行但等待命名激活的最佳方法是什么?

答案1

但是,systemd 认为 bind9 是在它 fork 时启动的,而不是在 named 准备好处理请求时启动的

Systemd 没有其他方法可以知道何时命名“准备好处理请求”。可以追溯到 SysVinit 时代,普遍接受的协议是守护进程分叉,设置好一切,一旦准备好就告诉其父进程它现在可以退出(通常通过管道或信号)。这很简单,即使您的“init”只是一个 shell 脚本,它也能正常工作:named; echo Ready!

(换句话说,systemd 根本不关心初始进程分叉它的孩子,但当它退出

还有其他可能的协议 - 例如,如果使用 Type=notify,则守护进程应该发送 READY=1 消息;如果使用 Type=dbus,它必须在系统总线上声明一个名称;等等。

但是如果named没有正确实现这个协议——也就是说,如果它的初始进程在分叉后过早退出——那么init就无能为力了。处理欺骗它的守护进程(由于无能或其他原因)不是init的工作。

话虽如此,首先要做的是检查它的bind9.service实际工作原理。它仍然可能不是直接运行命名,而是通过 init.d 脚本层运行,这往往会导致类似的问题。(即使日志没有显示典型的“LSB:...”前缀,我还是会检查。)

它可以bind9.service 被改为 Type=simple,不支持任何根本没有什么‘就绪’通知!当维护人员盲目地从某些网站上获取“systemd 说分叉是邪恶的”时,这种情况也经常发生。

因此,请确保 bind9.service 实际上是 Type=forking(而不是 Type=simple)并且它直接以命名方式运行(并带有必要的“请守护进程”选项)。

如果这不起作用(即命名仍然过早守护进程),你唯一的其他选择是有一个第二持续检查 DNS 可用性的服务。

相关内容