在只读/文件系统上使用 systemd-timesync

在只读/文件系统上使用 systemd-timesync

我正在尝试设置具有只读文件系统的 Raspberry Pi。基本镜像是 Debian Buster lite Raspbian 镜像。
大多数东西都可以工作,例如必须进行简单的修复,例如:

mv /etc/resolv.conf /var/run/resolv.conf && ln -s /var/run/resolv.conf /etc/resolv.conf

与 dhcp 和其他一些服务类似

然而,我想要一项服务,但它拒绝像这样工作:systemd-timesync。

这是我所做的以及发生的事情。systemd-timesync 我创建了一个目录 /run/systemd-timesync,由用户 systemd-timesync:systemd-timesync 所有 然后创建了一个符号链接 /var/lib/systemd/timesync -> /run/systemd -时间同步

root@raspberrypi:/var/lib/systemd # ls -l /var/lib/systemd/timesync
lrwxrwxrwx 1 root root 21 Dec 25 14:48 /var/lib/systemd/timesync -> /run/systemd-timesync

root@raspberrypi:/var/lib/systemd # ls -l /run/systemd-timesync/
total 0
-rw-r--r-- 1 systemd-timesync systemd-timesync 0 Dec 25 15:02 clock

systemd 单元文件的相关部分:

...
[Service]
User=systemd-timesync
AmbientCapabilities=CAP_SYS_TIME
CapabilityBoundingSet=CAP_SYS_TIME
WorkingDirectory=/run/systemd-timesync
Environment=SYSTEMD_LOG_LEVEL=debug
ExecStartPre=/bin/pwd
ExecStart=!!/lib/systemd/systemd-timesyncd
...
RuntimeDirectory=systemd/timesync
StateDirectory=systemd/timesync
...

请注意,我添加了 ExecStartPre=/bin/pwd ,它应该仅将当前工作目录输出到日志。

现在,如果我启动 systemd-timesync 并将 / 安装为只读,则会发生以下情况

root@raspberrypi:/var/lib/systemd # systemctl stop systemd-timesyncd.service && systemctl daemon-reload && systemctl start systemd-timesyncd.service
Job for systemd-timesyncd.service failed because of unavailable resources or another system error.
See "systemctl status systemd-timesyncd.service" and "journalctl -xe" for details.

journalctl 的输出

Dec 25 15:34:10 raspberrypi systemd[1]: systemd-timesyncd.service: Trying to enqueue job systemd-timesyncd.service/stop/replace
Dec 25 15:34:10 raspberrypi systemd[1]: systemd-timesyncd.service: Installed new job systemd-timesyncd.service/stop as 1214
Dec 25 15:34:10 raspberrypi systemd[1]: systemd-timesyncd.service: Enqueued job systemd-timesyncd.service/stop as 1214
Dec 25 15:34:10 raspberrypi systemd[1]: systemd-timesyncd.service: Job 1214 systemd-timesyncd.service/stop finished, result=done
Dec 25 15:34:10 raspberrypi systemd[1]: /lib/systemd/system/systemd-timesyncd.service:36: Failed to parse system call, ignoring: io_pgetevents
Dec 25 15:34:10 raspberrypi systemd[1]: systemd-timesyncd.service: Changed dead -> failed
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Trying to enqueue job systemd-timesyncd.service/start/replace
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Installed new job systemd-timesyncd.service/start as 1215
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Enqueued job systemd-timesyncd.service/start as 1215
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionFileIsExecutable=!/usr/sbin/VBoxService succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionFileIsExecutable=!/usr/sbin/chronyd succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionFileIsExecutable=!/usr/sbin/openntpd succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionFileIsExecutable=!/usr/sbin/ntpd succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionVirtualization=!container succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: ConditionCapability=CAP_SYS_TIME succeeded.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Failed to run 'start-pre' task: Read-only file system
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Failed with result 'resources'.
Dec 25 15:34:11 raspberrypi systemd[1]: systemd-timesyncd.service: Job 1215 systemd-timesyncd.service/start finished, result=failed
Dec 25 15:34:11 raspberrypi systemd[1]: Failed to start Network Time Synchronization.

显然,ExecStartPre 中的 /bin/pwd 由于只读文件系统而失败。我不明白这一点,也不知道如何解决它。如果我删除 ExecStartPre,ExecStart 命令也会发生同样的情况。

然而当我这样做时,

mount -o remount,rw /

随后

root@raspberrypi:/var/lib/systemd # systemctl stop systemd-timesyncd.service && systemctl daemon-reload && systemctl start systemd-timesyncd.service

一切正常,包括 pwd 输出到日志。

同样,当我开始时

root@raspberrypi:/var/lib/systemd # /lib/systemd/systemd-timesyncd
Synchronized to time server for the first time 84.199.86.247:123 (0.debian.pool.ntp.org).

一切正常。

到目前为止,我的结论似乎是 systemd 需要在某处进行写访问才能启动 ExecStartPre 或 ExecStart 中的任何命令。

关于如何实现让树莓更新时间设置的最初目标有什么想法吗?

注意:可能与单元文件中的StateDirectory、RuntimeDirectory行有关。

答案1

这解决了我在 DietPi 上的问题:

  • /run 挂载为 tmpfs

  • 在 /var/lib 下为 StateDirectory 创建软链接:

    ln -s /run /var/lib/run

  • 禁用 PrivateTmp

    #PrivateTmp=yes

  • 将 StateDirectory 更改为 tmpfs:

    StateDirectory=run/timesync

RuntimeDirectory 对于 /run 来说是绝对的,它已经是一个 tmpfs,所以不需要改变

答案2

经过很长时间的修改,结果发现在 [Unit] 部分注释掉以下两行就足够了:

#CapabilityBoundingSet=CAP_SYS_TIME
#PrivateTmp=yes

事实证明,这是唯一需要注释掉的两行,才能使其在只读/文件系统上正常工作。

我不明白为什么取消注释这两行中的任何一行会破坏 systemd-timesync 在只读文件系统上的工作。我希望 PrivateTmp=yes 为该进程创建一个安装在 private /tmp 上的私有 tmpfs,但显然不是。那么可能是 systemd 中的一个错误。

答案3

您应该考虑使用overlayfs只读(但假可写) / 文件系统。这将防止某些 systemd 服务失败。

您可以使用>raspi-config中的脚本来执行此操作4 Performance OptionsP3 Overlay File System

那么 FS 将是只读的,但假可写(所有更改将在关闭或重新启动时丢失)。

您可以阅读raspi 配置脚本以获取更多详细信息。

答案4

只是设置StateDirectory=对我有用。您可以在例如中添加几行,而不是编辑系统文件/etc/systemd/system/systemd-timesyncd.service.d/local-allow-readonly.conf

[Service]
StateDirectory=

目录/文件路径被硬编码在时间同步程序,所以它没有太大变化,除了User=systemd-timesync意味着 systemd-timesyncd 无法创建目录本身。所以,

  • 如果您在 systemd-timesync 首次运行之前执行此操作(例如在初始设置脚本中),则永远不会创建目录(和时钟文件)。
  • 如果在创建目录后执行此操作,则可以在以读写方式安装文件系统时更新时钟文件。

(如果您想知道错误从何而来,我猜它是尝试 chmod即使模式已设置为所需模式,EROFS 也会失败。似乎与PrivateTmp和无关CapabilityBoundingSet。)

相关内容