为一条隧道添加的重启策略开始作用到机器上的每一条隧道。这不是 systemd 的缺陷,而是实例 drop-in 与模板 drop-in 的区别。你把文件写在哪个路径下,决定了有多少服务会继承它。

先定范围,再定设置。两个目录看起来几乎一样,只有其中一个只作用于你想要的实例。

症状:改一次,所有隧道

实例专属的 drop-in 位于以完整实例命名的目录下,例如 [email protected]。模板 drop-in 位于 [email protected] 下,中间有 @ 符号、没有实例名。前者只作用于 office。后者作用于由该模板实例化出的每一个服务。

模板形式触及不到单独的 [email protected] 模板,也触及不到名字里带 openvpn 的无关服务。

选择与范围匹配的目录

两个目录都在 /etc/systemd/system/ 下。省略最后的 system 组件,会得到一条 systemd 不认作系统覆盖的路径,这是让一个看起来正确的文件悄无声息地什么都不做的办法。把完整路径写一次,然后重复使用。

drop-in 还需要正确的节标题。服务设置应放在 [Service] 下。有设置却没有节的文件会被忽略或拒绝,文件摆在那里显得很有权威,unit 却照旧运行。

如果添加多个 drop-in,就把用途留在文件名里。合并顺序由字典序决定,一个说明文件做什么的名字能让这个顺序可读。

写之前先读合并后的 unit

写任何东西之前,先读合并后的 unit。systemctl cat [email protected] 会按合并顺序打印主 unit 和每一个生效的 drop-in。考虑改模板时,把它和第二个实例对比。这个对比能准确看出哪些服务会继承这次修改。

实例文件不会抹掉模板设置。两者会合并,所以你忘记的模板值可能仍然生效。

其他具名 drop-in、运行时设置和软件包提供的配置也会参与。不要以为你最后改的文件就是整个 unit。合并后的输出才是 unit。

把 unit 策略留在配置文件之外

把 unit 策略和 VPN 配置分开。配置指令不会因为它位于 [Service] 下就变成合法的 systemd 语法。重启设置同样不属于 .ovpn 文件。

这种分离也正是重启策略不同于OpenVPN自身对端恢复的原因。选范围之前,先决定你要哪种行为。

应用并验证实例

改动之后,用 systemctl daemon-reload 重新加载管理器的定义。那次重载不会重启隧道,只是重新读取 unit 文件。然后把你打算做的生命周期操作应用到确切的实例上。

再次读取已加载的 unit,并观察你改动过的行为,以此验证。承载着正在进行的工作的重启,值得安排一次计划内的中断,而不是在生产隧道上快速试一下。把覆盖的用途和范围记录在部署旁边,好让下一个人知道这个文件本来是否打算共享。

如果策略确实需要共享,就有意把它移到模板里,并在宣布完成之前检查第二个实例。systemd unit 参考文档记录了 drop-in 的优先级与合并顺序。

相关文章