我正在尝试设置具有只读文件系统的 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 Options
P3 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
。)