构建时 systemd 调度
摘要
文章探讨了使用 NixOS 来检查和管理自托管服务的构建时 systemd 调度,以增强运行时检查。
<p><a href="https://lobste.rs/s/irgjfw/build_time_systemd_schedule">评论</a></p>
查看缓存全文
缓存时间: 2026/08/17 08:07
# 构建时 systemd 调度
来源:https://gvolpe.com/blog/systemd-schedule/
缩略图
系统和服务管理器 [systemd](https://systemd.io/) 为 Linux 系统提供了基础构建模块,也是 NixOS 的默认选择——尽管目前也有一些替代方案,如 [finix](https://github.com/finix-community/finix) 和 [sixos](https://codeberg.org/amjoseph/sixos),正在探索这一设计领域。作为一名在 NixOS 服务器上托管若干服务的自建用户,它已成为我工具箱中的常备项。
*当前服务器拓扑图,由 nix-topology(https://oddlama.github.io/nix-topology/)生成(附带少量自定义补丁)❄️*
## 运行时调度
最近,我在其中一台运行 [Immich](https://gvolpe.com/blog/immich-photos) 的服务器上进行了一些升级和维护,并想检查当前的作业调度情况,以确认它们在我的时区中配置正确。
```
[admin@metropolis:~]$ systemctl list-timers --all
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-08-15 10:44:47 CEST 15min Sat 2026-08-15 10:14:47 CEST 14min ago disk-monitor.timer disk-monitor.service
Sat 2026-08-15 11:00:00 CEST 30min Sat 2026-08-15 10:00:08 CEST 29min ago logrotate.timer logrotate.service
Sat 2026-08-15 15:21:37 CEST 4h 52min Fri 2026-08-14 15:21:40 CEST 19h ago acme-renew-immich.gvolpe.com.timer acme-order-renew-immich.gvolpe.com.service
Sat 2026-08-15 22:52:43 CEST 12h Fri 2026-08-14 22:52:43 CEST 11h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Sun 2026-08-16 00:00:00 CEST 13h Sat 2026-08-15 00:00:08 CEST 10h ago custom-immich-stop-trigger.timer custom-immich-stop-trigger.service
Sun 2026-08-16 00:00:01 CEST 13h Sat 2026-08-15 00:00:08 CEST 10h ago postgresql-backup.timer postgresql-backup.service
Sun 2026-08-16 00:00:05 CEST 13h Sat 2026-08-15 00:00:08 CEST 10h ago borgbackup-job-immich-s3-media.timer borgbackup-job-immich-s3-media.service
Sun 2026-08-16 00:00:05 CEST 13h Sat 2026-08-15 00:00:08 CEST 10h ago borgbackup-job-postgres.timer borgbackup-job-postgres.service
Sun 2026-08-16 00:00:30 CEST 13h Sat 2026-08-15 00:00:35 CEST 10h ago s3-replica.timer s3-replica.service
Sun 2026-08-16 03:00:00 CEST 16h Sat 2026-08-15 03:00:08 CEST 7h ago s3ql-fsck.timer s3ql-fsck.service
Sun 2026-08-16 03:30:00 CEST 17h Sat 2026-08-15 03:30:06 CEST 6h ago custom-immich-start-trigger.timer custom-immich-start-trigger.service
Mon 2026-08-17 00:00:00 CEST 1 day 13h Mon 2026-08-10 02:00:08 CEST 5 days ago nix-gc.timer nix-gc.service
Mon 2026-08-17 01:39:34 CEST 1 day 15h Mon 2026-08-10 02:52:22 CEST 5 days ago fstrim.timer fstrim.service
13 timers listed.
```
*随着作业数量的增加,很容易失去跟踪。*
然而,查看这些信息让我产生了一个疑问:是否可以在我部署之前,直接从 NixOS 配置中获取这些信息——即进行构建时检查,而非运行时检查。NixOS 的一个优秀特性是它在构建时会生成一个派生(derivation),这是整个系统的构建配方,易于检查;其中包含的 systemd 配置也不例外。
```
nix-repl> nixosConfigurations.metropolis.config.systemd.timers
{
"acme-renew-immich.gvolpe.com" = { ... };
borgbackup-job-immich-s3-media = { ... };
borgbackup-job-postgres = { ... };
custom-immich-start-trigger = { ... };
custom-immich-stop-trigger = { ... };
disk-monitor = { ... };
fstrim = { ... };
logrotate = { ... };
nix-gc = { ... };
postgresql-backup = { ... };
s3-replica = { ... };
s3ql-fsck = { ... };
}
nix-repl> nixosConfigurations.metropolis.config.systemd.timers.s3-replica.timerConfig
{
OnCalendar = "*-*-* 0:00:30";
Persistent = false;
}
```
因此信息是可用的,我们可以按需处理。在我的案例中,我想要为每个服务器的调度创建一个 Mermaid 流程图,结果如下(可在 [Mermaid Live](https://mermaid.live/edit#pako:eNqtlVtu2zgUhrdCMCh6geXoakua1EDdGH1rHprBAAO_0BQtc0yKGpJK4gRZy8wOurUuoRSlKLLj2GkR2TBE-vzU9x8eHd5BLDICU_jmDfhCCiKRJhlYSsEBuUKsssOv9ObiG1AbpQnPgKacSDWcF0smrvEKSQ0uz-cFMH9oRt7N4WUdABRekaxiBCyFPFvI0wk4W0w40VKUglF1drqYNNPvZpWZI6d_IanQ9fs5fF8vhhlS6pwsm1XBkjKWniSzaTIbDZRZZE3Sk6W9BlgwIdMTz1472pqk0U7jmTudvly7EEK30s9JLX65tCSSioziVj4bTUefvJfJW7v2t568dE1CTeI-OOYDXDe13y55uFJacIdyTvHKMfeloyXNcyKH1rsNOitN8OTHf_9_t7rTcgIO6BSRVxST_jYYiiaV3S4Dx5mYWUvobRFaQK8DLIXSuSTqX-YsEF5X5WGup-F7cbxHHINmWWwKL_2nLFHHshAyb1Z1_hGLznzgcJJRdBjsiLalbNVA6Q0jH982W5xLtPnj7cQUhaLmDSpMVSGmSL3stiu_58prXPl2EPyCq4cM_pKdTvQqPoKeD7_xEdhB-MRH8FjKJpeSlIziIzvRi3sV2rBHGzS0oR1EW7TBzpunAlOjS4XXx2gfwl4FNurBhg1sZAejHdjgYJswPfv3-kRfuPfNHPUAowZwZAfjBvCimJq--o3gjxEfgIviz4LqT1jTK1LPBS7vmDOq1g4X5n9xBHIrci_V2Hbzne41tlxxw5UhyjbdsxHmxFRZQa5b68P8SrCSDLHgh1msUsiMyGf1LygEiYpMcHprzt6MMLQBfrhq2uljhWyIelofcXf27JiNrdmkMbsSley5ZSKXQpuT_rC1x7C9OU6ee3TSNLT2ILsmZN179tKcivRITtuYrbytzE9Bb5wcH9a2Mb-Tc3c341pWe15Jz33OuGfORziAuaQZTGvxABpSjuohvKuD51CvCDeJTM1thuR6DufFvdGUqPhbCP4gk6LKVzC1TWEAqzIzu3BOkSHn3awpN1N1n0VVaJiOI7sGTO_gDUz9MBkmrhuEXhj5sZcEowHcwNSJ46HnReMwdt1k7Id-cD-At_ax3tB3_XHsB1EYJ7Efef79T2O6XiQ) 查看)\)。
调度图
这是通过一个 Python 脚本临时拼凑起来的,该脚本使用以下命令获取核心信息:
```
nix eval --json .#nixosConfigurations.metropolis.config.systemd.timers \
--apply 'builtins.mapAttrs (name: timer: timer.timerConfig)' | jq
```
生成的 JSON 数据如下:
```
{
"acme-renew-immich.gvolpe.com": {
"AccuracySec": "86400s",
"FixedRandomDelay": true,
"OnCalendar": "daily",
"Persistent": "yes",
"RandomizedDelaySec": "24h",
"Unit": "acme-order-renew-immich.gvolpe.com.service"
},
"borgbackup-job-immich-s3-media": {
"OnCalendar": "*-*-* 0:00:05",
"Persistent": false
},
"borgbackup-job-postgres": {
"OnCalendar": "*-*-* 0:00:05",
"Persistent": false
},
"custom-immich-start-trigger": {
"OnCalendar": "*-*-* 03:30:00",
"Unit": "custom-immich-start-trigger.service"
},
"custom-immich-stop-trigger": {
"OnCalendar": "*-*-* 00:00:00",
"Unit": "custom-immich-stop-trigger.service"
},
"disk-monitor": {
"OnBootSec": "5m",
"OnUnitActiveSec": "30m"
},
"fstrim": {
"OnCalendar": [
"",
"weekly"
]
},
"logrotate": {
"OnCalendar": [
"hourly"
]
},
"nix-gc": {
"OnCalendar": [
"weekly"
],
"Persistent": true,
"RandomizedDelaySec": "0"
},
"postgresql-backup": {
"OnCalendar": "*-*-* 0:00:01",
"Unit": "postgresql-backup.service"
},
"s3-replica": {
"OnCalendar": "*-*-* 0:00:30",
"Persistent": false
},
"s3ql-fsck": {
"OnCalendar": "*-*-* 03:00:00",
"Persistent": false,
"Unit": "s3ql-fsck.service"
}
}
```
接下来,就是处理这些数据,以所需格式生成 Mermaid 图。
### 时区
脚本按以下顺序评估,默认使用 UTC(如果两个值都缺失)。
```
nix-repl> nixosConfigurations.metropolis.config.systemd.globalEnvironment.TZ
"Europe/Warsaw"
nix-repl> nixosConfigurations.metropolis.config.time.timeZone
"Europe/Warsaw"
```
虽然可以在每个服务单元单独设置多个时区,但这目前不是我需要的功能。
## 运行时依赖
在运行的服务器上,我们可以使用以下命令生成 systemd 依赖关系图:
```
systemd-analyze dot --require --from-pattern="*.service" --to-pattern="*.service" \
| dot -Tsvg > services.svg
```
这将为该 NixOS 服务器渲染出类似这样的图表:
依赖图
图表很快就会变得难以阅读,因此通常分析特定单元而非全部单元更为有用,例如:
```
[admin@metropolis:~]$ systemctl show immich-server.service -p Requires -p Wants
Requires=postgresql.target s3ql-mount.service -.mount system-immich.slice
Wants=-.mount
```
这些工具对于日常的服务器维护任务很有用,但我们能否在不实际部署的情况下验证依赖关系?
## 构建时依赖
毫不意外,这些信息同样可在我们的 NixOS 配置蓝图中找到。
```
nix-repl> nixosConfigurations.metropolis.config.systemd.services.s3
nixosConfigurations.metropolis.config.systemd.services.s3-aliases
nixosConfigurations.metropolis.config.systemd.services.s3-replica
nixosConfigurations.metropolis.config.systemd.services.s3ql-auth
nixosConfigurations.metropolis.config.systemd.services.s3ql-fs
nixosConfigurations.metropolis.config.systemd.services.s3ql-fsck
nixosConfigurations.metropolis.config.systemd.services.s3ql-mount
```
以下单行命令展示了如何直接从 NixOS 配置获取所有 systemd 依赖关系:
```
nix eval --json .#nixosConfigurations.metropolis.config.systemd.services \
--apply 'builtins.mapAttrs (name: service: { inherit (service) requires wants wantedBy requiredBy; })' \
| jq 'with_entries(.value |= with_entries(select(.value != []))) | with_entries(select(.value != {}))'
```
为简洁起见,这里展示其生成的部分 JSON 数据:
```
{
"immich-machine-learning": {
"requires": [
"postgresql.target",
"s3ql-mount.service"
],
"wantedBy": [
"multi-user.target"
]
},
"immich-server": {
"requires": [
"postgresql.target",
"s3ql-mount.service"
],
"wantedBy": [
"multi-user.target"
]
},
"nginx": {
"wantedBy": [
"multi-user.target"
],
"wants": [
"acme-immich.gvolpe.com.service"
]
}
}
```
我还没有为此创建任何图表,但如果需要,我们已有必要的数据。
## 最终想法
我认为这值得分享,因为 NixOS 总是让我感到惊喜 🤩。可以说我总是在学习新事物,更重要的是,在运行这些服务器时获得了极大的乐趣!强烈推荐。
你怎么看?请在下方评论区告诉我 👇
祝好,
Gabriel。
相似文章
使用Nix构建系统软件
一篇博客文章,讨论Nix如何帮助解决构建系统软件时的依赖和可重现性问题,特别是针对像BPF和io_uring这样快速演进的子系统。
你对 systemd 定时器的爱还不够
本文提倡在 Linux 上使用 systemd 定时器替代传统的 cron 作业来执行定时任务,强调其更好的集成性、日志记录以及更清晰的语法。
后现代构建系统
一篇博客文章,探讨理想中的'后现代'构建系统的设计,该系统优先考虑可信的增量构建、最大化计算复用和分布式构建,并以Nix作为参考。
今日记录:在NixOS上符号链接点文件
一位开发者分享了在NixOS上使用systemd-tmpfiles符号链接点文件的技巧,无需依赖home-manager或其他工具。
改进我的自托管 Actions Runner 设置
作者通过用 systemd-nspawn 容器替换 Docker 来改进其自托管的 Gitea Actions Runner 设置,以提高安全性,并详细说明了配置和权衡。