systemd.offline-updates 中文手册

译者:金步国


版权声明

本文译者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布。

其他作品

本文译者十分愿意与他人分享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有的作品集:

联系方式

由于译者水平有限,因此不能保证译文内容准确无误。如果你发现了译文中的错误(哪怕是错别字也好),请来信指出,任何提高译文质量的建议我都将虚心接纳。


手册索引 · 指令索引systemd-241

名称

systemd.offline-updates — systemd 离线系统更新机制

离线系统更新机制

本手册页描述了如何实现 systemd 风格的"离线"系统更新。 所谓"离线"系统更新,是指将系统启动到一个特殊的"系统更新模式", 并在此模式下执行软件包的安装与更新操作, 从而避免直接更新正在使用的例如动态库或可执行程序之类的文件(因为这种操作可能造成系统故障)。本文档遵循 GNOME design whiteboard 规范。

逻辑步骤如下:

  1. 软件包管理程序下载好系统更新所需要的全部更新包(RPM 或 DEB 之类), 并将其存放在例如 /var/lib/system-update 这样的目录里(也可能是软件包管理程序特定用来存放更新包的其他目录)

  2. 当用户确认要执行离线系统更新之后,将会创建 /system-update 软连接, 并将其指向 /var/lib/system-update 目录(也可能是软件包管理程序特定用来存放更新包的其他目录),然后重新启动操作系统。 之所以将软连接直接创建在根目录下,是因为在系统启动的早期就要检测它的存在, 而此时 /var 有可能尚未挂载。

  3. 在重新启动之后很早期的阶段,如果 systemd-system-update-generator(8) 检测到存在 /system-update 软连接,那么它将会仅为本次启动将 default.target 软连接临时指向 system-update.target 目标。该目标单元中仅包含启动基本系统所必须的 sysinit.target 目标(仅挂载所有文件系统而不启动任何其他服务), 以及用于执行系统更新操作的更新服务。

  4. 系统继续向着 default.target 目标(也就是包含了所有系统更新服务的 system-update.target 目标)启动。 每一个系统更新都应该仅实际执行一个特定的更新服务(参见下一步), 所有其他更新服务都应该不执行任何操作,只需干净的退出并返回"成功"状态码即可。 所有更新服务都必须安排在 sysinit.target 之后执行, 这样可以确保在执行更新操作的时候,所有文件系统都已经挂载完毕。

  5. 每一个更新服务启动之后的第一步都应该是立即检查 /system-update 软连接是否指向了该更新服务所要求的正确位置。 如果指向了错误位置或者软连接根本不存在,那么该更新服务必须什么也不做,立即退出并返回"成功"状态码。 虽然可以同时安装多个更新服务,也可以同时并行启动多个更新服务, 但是仅有那个在重启之前创建了软连接的工具所对应的更新服务, 才可以实际执行系统更新操作,所有其他更新服务必须什么也不做。 因为同时执行多个系统更新的操作是不安全的,也就是多个系统更新必须以串行的方式一个接一个的执行。

  6. 如果 /system-update 软连接确实指向了正确的位置, 那么更新服务将会首先尝试创建一个文件系统快照(如果确实可以的话),然后安装全部更新包。 无论更新操作是否成功,接下来必须使用例如 systemctl reboot 之类的命令重新启动。 如果更新失败并且之前曾经成功的创建了文件系统快照, 那么更新脚本应该按照先前创建的快照回滚文件系统(不含 /system-update 软连接)。

  7. 更新脚本应该仅在更新完成之后才能退出。 执行实际更新操作的更新服务应该在完成更新操作之后重启系统。 如果最终成功到达了 system-update.target 目标, 也就是已经运行了所有更新服务,并且 /system-update 软连接依然存在, 那么软连接将会被删除,并且整个系统将会被视为以大功告成的安全方式重启。

  8. 重启之后,因为已经不再存在 /system-update 软连接了, 所以 default.target 也就不会再被临时重定向。 整个系统将以正常模式向默认目标启动。

建议

  1. 为了提高可靠性,建议软件包直接向 system-update.target.wants/ 目录添加软连接来调用更新脚本,而不是在预安装阶段使用 systemctl enable 命令。进一步明确的说, 就是要为软件包的更新脚本创建一个不含 [Install] 小节的 foobar.service 文件,然后添加一个类似 /usr/lib/systemd/system-update.target.wants/foobar.service../foobar.service 这样的软连接。

  2. 确保尽可能早的在更新脚本中删除 /system-update 软连接, 以避免在更新失败时导致循环重启。

  3. 在更新服务的单元文件中为更新脚本使用 FailureAction=reboot , 以确保在更新失败后触发自动重启。 FailureAction= 仅用于在更新脚本非正常退出时(退出码非零或被中断或崩溃), 确保可以触发特定的动作或启动特定的单元。 如果更新脚本成功的完成了所有操作,那么应该自己触发重启动作,例如可以调用 logind 的 Reboot() 函数,或者使用 systemctl reboot 命令。详见 logind dbus API 手册。

  4. 更新服务应该明确声明 DefaultDependencies=no, Requires=sysinit.target, After=sysinit.target, After=system-update-pre.target , 同时应该明确将所依赖的其他服务包含在依赖关系中。

  5. 当启动到离线更新模式时, 如果需要运行辅助单元(该单元本身不安装更新), 那么可以创建一个包含 Wants=system-update-pre.targetBefore=system-update-pre.target 的 .service 单元,并在 /usr/lib/systemd/system-update.target.wants/ 目录中添加一个指向该单元的软连接。

参见

systemd(1), systemd.generator(7), systemd-system-update-generator(8), dnf.plugin.system-upgrade(8)