当前位置: 首页 > 文档资料 > systemd 中文手册 >

systemd.generator 中文手册

优质
小牛编辑
147浏览
2023-12-01

名称

systemd.generator — systemd 单元生成器

大纲

/path/to/generator normal-dir early-dir late-dir

系统生成器目录/run/systemd/system-generators/*
/etc/systemd/system-generators/*
/usr/local/lib/systemd/system-generators/*
/usr/lib/systemd/system-generators/*

用户生成器目录/run/systemd/user-generators/*
/etc/systemd/user-generators/*
/usr/local/lib/systemd/user-generators/*
/usr/lib/systemd/user-generators/*

描述

本文所说的"生成器",本质上是位于上文所列目录中的一些可执行程序。systemd(1)将会在其自身刚启动的早期、以及重新加载其自身的配置信息时,执行这些单元生成器(也就是在加载单元文件之前执行)。生成器的主要目的是将非单元配置转化为动态生成的单元文件。

每个生成器都接受三个目录参数,用作输出目录。生成器在这三个目录中动态生成单元文件(常规单元、实例单元、模板单元)、单元配置片段(位于 .d/ 目录中)、指向单元文件的软连接(表示单元间额外的依赖关系、表示单元的别名、表示基于现有模板实例化的单元)。因为这些目录包含在systemd(1)的单元加载路径中,所以生成的配置能够扩展或覆盖现有的定义。

不同的生成器输出目录拥有不同的优先级,由高到低排列,依次为:…/generator.early/etc…/generator/usr…/generator.late 。详见下文以及systemd.unit(5) 手册。

生成器的加载目录取决于编译时的配置,一般情况下(--prefix=/usr),就是上一小节所列的目录。系统单元生成器与用户单元生成器分别从system-generators/user-generators/ 目录中加载。位于列表中较前目录中的生成器,将会覆盖列表中较后目录中的同名生成器,也就是列表中较前的目录的优先级也更高。因此,可以使用高优先级目录中的一个指向/dev/null 的同名软连接(或空文件),去屏蔽低优先级目录中的一个同名生成器(也就是禁止它运行)。注意,生成器目录的优先级顺序与单元目录的优先级顺序并不相同,具体就是/run 目录的优先级比/etc 目录更高。

在安装或更新了生成器之后,必须执行 systemctl daemon-reload 命令才能最终实际生效。该命令将会删除先前的单元生成器所创建的所有单元文件与软连接,然后重新运行所有生成器来重新创建单元文件与软连接,最后再让systemd 重新加载所有的单元文件。详见systemctl(1)手册。

输出目录

需要给单元生成器传递三个目录参数,以指示所生成的单元文件或软连接的存放位置。默认情况下,这些参数是包含在systemd 单元目录中的运行时目录,但是出于调试目的,也可以设为其他路径。

  1. normal-dir

    对于系统生成器来说,一般是 /run/systemd/generator 目录;对于用户生成器来说,一般是 $XDG_RUNTIME_DIR/generator 目录。此目录中的单元文件能够覆盖厂商提供的单元文件(/usr),但是不能覆盖本地系统管理员/普通用户的单元文件(/etc)。

  2. early-dir

    对于系统生成器来说,一般是 /run/systemd/generator.early 目录;对于用户生成器来说,一般是 $XDG_RUNTIME_DIR/generator.early 目录。此目录中的单元文件能够覆盖 /usr, /run, /etc 中的单元文件。也就是说,此目录中的单元文件能够覆盖所有单元文件,包括厂商提供的单元文件以及本地系统管理员/普通用户的单元文件。

  3. late-dir

    对于系统生成器来说,一般是 /run/systemd/generator.late 目录;对于用户生成器来说,一般是 $XDG_RUNTIME_DIR/generator.late 目录。此目录中的单元文件不会覆盖任何现存的单元文件,仅用于扩展单元文件。任何现存的单元文件的优先级都高于此目录中的单元文件。

编写单元生成器的注意事项

  • 所有单元生成器都会在同一时间被并行执行。这就要求所有单元生成器之间不能存在依赖关系,并且足够小巧以适用这种并发式的运行场景。

  • 单元生成器在系统启动的早期运行,因此它不能依赖于任何其他单元。单元生成器在运行过程中不能与任何其他进程通信,包括与日志记录进程 syslog(3)systemd 自身都不行,当然,更不要说使用 systemctl(1) 工具了。此外,例如 /var/home 这样的非关键文件系统也是尚未挂载的。单元生成器只能使用最基本的内核功能,并且只能假定 /sys, /proc, /dev, /usr 已经被挂载。

  • 单元生成器生成的单元文件将会在重新加载配置文件时被删除。换句话说,就是单元生成器生成的单元的生命周期与 systemd 自身的生命周期是紧紧绑定在一起的。

  • 单元生成器应该仅仅用于生成单元文件与指向单元文件的软连接,而不应该做任何与配置相关的工作。由于上文提到的生命周期的原因,单元生成器并不适用于为服务单元动态生成配置文件。如果你需要为某个服务单元动态生成配置文件,那么你应该使用一个普通的服务单元,并强迫命令该单元先于被配置的服务单元启动。

  • 由于在系统启动的早期阶段,syslog(3) 处于不可用状态(见上文),必须将日志信息写入到 /dev/kmsg 文件中。

  • 在动态生成的单元文件中使用 SourcePath= 指明其来源于哪个配置文件通常是个好主意。这样做可以帮助用户轻松的理解该单元是派生于哪个配置文件,同时也有助于让 systemd 及时的发出警告: 磁盘上的配置文件已经发生变化,但是我现在还没有刷新动态单元。

  • 单元生成器可能会动态生成单元文件,也可能只是通过软连接将已有的单元添加到其他单元的 .wants/.requires/ 目录中。通常,在实践中,最佳做法是尽量使用单元生成器从 /usr 中的模版实例化出一个单元,而不是从头创建一个完整的动态单元文件。当然,这只能用于仅使用单个参数的场合。

  • 虽然你实际上可以使用 shell 脚本来实现一个单元生成器,但是我们还是强烈建议你使用C语言来实现。因为单元生成器都以同步的方式执行,所以执行速度较慢脚本会拖慢系统的启动速度。

  • 关于单元文件之间的覆盖,我们应该尽量遵守如下两条规则:

    1. 用户配置应该覆盖厂商的配置。 在大多数情况下,这意味着 /etc 中的内容应该覆盖 /usr 中的内容。

    2. 原生配置应该覆盖非原生配置。 在大多数情况下,这意味着 动态生成的单元文件不应该覆盖系统上已有的单元文件。

    对于上述两个原则,第一个原则应该被严格遵守,而第二个原则在某些场合有可能会被打破。因此,在决定使用 argv[1], argv[2], argv[3] 之中的哪一个时,一般应该默认使用 argv[1]

  • 与其写一堆单元生成器来兼容传统的配置方式,不如直接舍弃这些不符合 systemd 规范的传统配置方式,转而使用 systemd 风格的配置方式。就让那些老旧的配置方式消失在历史的垃圾桶中吧!

例子

例 1. systemd-fstab-generator

systemd-fstab-generator(8)用于将 /etc/fstab 转换为本地 mount 单元。该生成器将 argv[1] 用作存放单元文件的目录。这样,在明确允许使用用户的原生单元文件覆盖 /etc/fstab 的同时,又能确保 /etc/fstab可以覆盖厂商在 /usr 中默认提供的 mount 单元。

/etc/fstab 被修改之后,用户应该明确使用systemctl daemon-reload 命令来重新运行所有生成器,以强制让 systemd 重新加载所有单元文件。要想挂载新添加到 fstab 中的挂载点,可以使用 systemctl start/path/to/mountpointsystemctlstart local-fs.target 命令。


例 2. systemd-system-update-generator

systemd-system-update-generator(8)用于在计划更新系统的时候,将 default.target 软连接临时指向system-update.target 目标。因为需要覆盖用户对default.target 的配置,所以该单元生成器使用 argv[2] 目录存放单元文件。详见systemd.offline-updates(7) 手册。


例 3. 调试单元生成器

dir=$(mktemp -d)
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/system-generators/systemd-fstab-generator \  "$dir" "$dir" "$dir"
find $dir

参见

systemd(1),systemd-cryptsetup-generator(8),systemd-debug-generator(8),systemd-fstab-generator(8),fstab(5),systemd-getty-generator(8),systemd-gpt-auto-generator(8),systemd-hibernate-resume-generator(8),systemd-rc-local-generator(8),systemd-system-update-generator(8),systemd-sysv-generator(8),systemd.unit(5),systemctl(1),systemd.environment-generator(7)