编程 别再为全量重启买单:Linux 上 systemd soft-reboot 实操

2026-09-07 13:13:24

别再为全量重启买单:Linux 上 systemd soft-reboot 实操

你刚完成一轮用户态包更新。库变了,守护进程需要一个干净的启动图。机器"还开着",但半个栈还跑在旧代际上。直觉反应是 reboot——但那是固件、引导器、内核启动、initrd 和所有冷启动成本,即使内核根本没变。

systemd 为此提供了更窄的工具:soft-reboot。它拆除并重启用户态,内核继续跑。停机时间从"整机循环"缩到"服务管理器重新执行 + 新启动事务"。这篇 dev.to 文章是完整操作指南:什么时候该用 soft-reboot、/run/nextroot/ 根切换怎么工作、什么能跨过边界存活、怎么验证,以及哪些硬边界上你仍然需要真重启或 kexec。

soft-reboot 是什么

从 systemd-soft-reboot.service(8) 和 systemctl(1):用 systemctl soft-reboot 触发(不要手工启动 systemd-soft-reboot.service)。它向 soft-reboot.target 隔离,该 target 依赖 systemd-soft-reboot.service。接近结束时,剩余进程先收到 SIGTERM 再 SIGKILL(最后一道杀波不等待礼貌退出)。如果 /run/nextroot/ 存在(目录、挂载点或指向两者的符号链接),根文件系统会切换到它。PID 1 从(可能新的)根重新执行服务管理器,并入队一个新启动事务——类似正常重启的用户态阶段。

它刻意不走:常规关机的第二阶段(systemd-shutdown)、回到 initrd 上下文、硬件重启、固件初始化、引导器初始化、内核初始化、initrd 初始化。systemctl soft-reboot 是 systemd 254 加入的(Debian 13 自带 257.x;上游 man page 跟踪 261)。

三种重启深度的心智模型

深度命令内核固件/引导器典型用途
仅用户态systemctl soft-reboot保持跳过用户态刷新、/run/nextroot/ A/B 根翻转
换内核跳过固件systemctl kexec(先装载)替换基本跳过内核更新但跳过完整 POST
全循环systemctl reboot替换完整路径固件/内核/initrd/设备拓扑变化

Soft-reboot 不是"更快的魔法重启",是不同契约:内核状态连续,用户态状态不连续(除非你刻意钉住幸存者)。

前置条件与两个操作注意

  • systemd ≥ 254 且存在 soft-reboot.target;
  • root(或与电源命令等价的 polkit 权限);
  • 一个"用户态形状"的理由:包刷新、需要完整依赖图的配置生成、基于镜像的根交接;
  • 接受 sysctl /sys 内核旋钮不会被重置、运行中的内核不变。

ArchWiki 的 systemd 页面补充两点与 man page 一致:解锁的 dm-crypt 设备可以跨 soft-reboot 保持挂载(不走常规关机路径的完整拆除);更新同时动了内核 + initramfs 时,不要把 soft-reboot 当唯一动作——那需要 kexec 或完整重启。

动手前先检查基线

soft-reboot 会像重启一样断开你的 SSH 会话,交互式工作请准备控制台或带外访问。先记录:uname -r、/proc/sys/kernel/random/boot_id、systemctl show 的 UserspaceTimestamp/FirmwareTimestamp/LoaderTimestamp/KernelTimestamp。有用的预期:boot_id 在完整重启/kexec 路径上改变;soft-reboot 应视作用户态周期,用时间戳和服务启动时间验证;固件/加载器/内核时间戳应连续,UserspaceTimestamp 在 PID 1 启动新用户态启动事务时前进;soft-reboot 后 uname -r 必须不变(变了说明你没做 soft-reboot)。

默认操作:普通 soft-reboot

sudo systemctl soft-reboot

等价于以 --job-mode=replace-irreversibly --no-block 启动 soft-reboot.target,异步返回;支持 --force 和 --when=(调度)等选项。不要直接 systemctl start systemd-soft-reboot.service——man page 明确要求走 systemctl soft-reboot。

会发生什么:正常单元沿常规停止任务在隔离事务中停止;属于关机图的挂载可以卸载;日志和单元状态在新用户态周期从 PID 1 重新执行开始。不会发生:systemd-shutdown 第二阶段、/usr/lib/systemd/system-shutdown/ 下的可执行文件(systemd-shutdown 没跑所以跳过)、固件/引导器/内核/initrd、/proc/sys 和 /sys 策略自动重置。如果你依赖 system-shutdown 钩子做磁盘刷写或 LED 脚本,soft-reboot 不会跑它们——关键工作放进正常服务的 ExecStop=/ExecStopPost=。

高级:用 /run/nextroot/ 切换根

这是镜像化和 A/B 场景的杀手锏:在 /run/nextroot/ 准备一整套根文件系统层级,然后 soft-reboot 进去,不丢内核持有的状态(路由、部分设备设置、未重置的 sysctl、适用的未锁 LUKS 映射)。/run/nextroot/ 可以是 /run tmpfs 上的普通目录、挂载点(bind、loop、镜像)或指向两者的符号链接;必要时 systemd 会把非挂载的 /run/nextroot/ 自动变成挂载点。

最小教学实验(仅限一次性 VM):mkdir -p /run/nextroot,bind 挂载已准备的根树或挂载非活跃槽位(/dev/disk/by-partlabel/root-b),确认 /run/nextroot/usr/lib/systemd/systemd 或 lib/systemd/systemd 可见,然后 sudo systemctl soft-reboot。重连后 findmnt / 确认落在目标槽位。

与普通重启的重要交互:只要 /run/nextroot/ 就位,systemctl reboot 会执行 soft-reboot 而不是完整重启——除非设 SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT=1。自动化里很容易踩到:镜像更新器把 next root 放到 /run/nextroot/ 后调 reboot,往往正是依赖这个自动行为;而只想测试 next root、期待完整重启的操作者会被意外吓到。

资源穿越(谨慎使用)

soft-reboot 可以把选定的运行时资源带进下一轮用户态周期,man page 提示谨慎——新旧代际混合正是"半更新"系统的来源:

  • /run 保持挂载:跨 soft-reboot 边界共享,是 next-root 暂存、下轮启动一次性标志、不应落盘的临时协调状态的天然位置。别把 /run 当持久存储。
  • 文件描述符存储:服务可用 FileDescriptorStoreMax=/fdstore 协议把 FD 交给管理器;FileDescriptorStorePreserve=(254 加入)控制保留策略。systemd-analyze fdstore some.service 检查,systemctl clean --what=fdstore 清理。
  • 不停止的 .socket 单元:DefaultDependencies=no 且避免与停止集冲突,套接字 FD 保持打开可连接,客户端在用户态回收期间能继续连接——对负载均衡器和本地 broker 有用,但激活策略在新启动事务后不一致就容易出错。
  • 幸存服务进程:跨 soft-reboot 存活的进程需要 SurviveFinalKillSignal=yes、IgnoreOnIsolate=yes、DefaultDependencies=no、Conflicts=reboot.target 等、Before=shutdown.target 等;模板单元还要配一个存活的 slice。官方建议直白:最好别存活。幸存者会钉住旧文件系统挂载和库、跳过代码更新、需要 D-Bus 重连逻辑。需要与宿主 OS 树隔离就用 Portable Services,别 BindPaths 宿主文件。
  • 挂载与复杂存储:DefaultDependencies=no 且无 Conflicts=umount.target 的挂载可以保持挂载——复杂存储在用户态轮换时保持挂载,与"未锁 LUKS 保持"的运行现实一致。

Homelab 模式:apt 之后只刷用户态

内核没变的服务器上的安全模式:apt update/upgrade 后,先检查 /boot 是否有比 /proc/1/root 新的 vmlinuz(有就安排 kexec 或完整重启),没有就 systemctl soft-reboot 干净回收用户态。搭配 needrestart 看哪些守护进程仍需关注、为内核 CVE 安排完整重启窗口、用监控区分"用户态启动年龄"与"内核启动年龄"。

验证清单

soft-reboot 前记录 KernelTimestamp/UserspaceTimestamp 和 uname -r;完成后:uname -r 不变、固件/加载器/内核时间戳连续(如可查)、用户态服务显示新鲜启动时间、systemctl --failed 为空(或只有已知旧故障)、journalctl 里有 systemd-soft-reboot.service 的软重启路径证据、用了 /run/nextroot/ 的话 findmnt / 指向新后端存储。失败信号:向 soft-reboot.target 隔离卡死超过任务超时(留意 soft-reboot-force 升级)、服务经意外幸存者/bind 挂载钉在旧树上、期望重置的 sysctl 没重置(需要时显式 sudo sysctl --system)。

边界:新内核/模块/initramfs → systemctl kexec 或完整 reboot;固件/UEFI 变量/引导条目变化 → 完整 reboot;需要重置设备拓扑 → 完整 reboot。Soft-reboot 只解决"用户态需要重来"这一件事,选对工具,停机时间就能从整机循环缩到一次服务管理器重执行。

来源:Stop Paying Full Reboot Downtime: Practical systemd soft-reboot on Linux - DEV Community

复制全文 生成海报 systemd Linux 运维 重启

推荐文章

程序员茄子在线接单