openSUSE MicroOS Rebootmgr & systemd-inhibit
1. First | 序
之前在 openSUSE MicroOS | 入门指南之 transactional-update
此篇文章中提到过 Rebootmgr 它的作用就是和 transactional-update 结合使用以协调重启过程,避免系统在不恰当的时间(例如业务高峰期)突然重启.
此篇我们重点来说一下 Rebootmgr & systemd-inhibit
2. Cluster With etcd
先来看一段配置 /etc/rebootmgr/rebootmgr.conf.d/40-maint-window.conf
尝试剖析 Rebootmgr 如何在集群环境中管理重启时间:
[rebootmgr]
strategy=best-effort
window-start=05:00
window-duration=1h30m
lock-group=default
- 触发源:系统通过
transactional-update完成了软件包下载和快照生成。 - 标志位:系统被标记为
/run/reboot-needed(需要重启以应用新快照)。
2.1. 参数逐行解析
-
[rebootmgr]: 配置文件段落头。 -
window-start=03:30: -
定义: 维护窗口开启的时间。
-
隐含逻辑: 由于未指定日期(如
Mon..Sun),默认为 每天 的凌晨 03:30。 -
window-duration=1h30m: -
定义: 窗口持续时间。
-
计算: 窗口将在 05:00 关闭。
-
限制: 如果到了 05:00 还没有成功重启,系统将停止尝试,直到第二天 03:30。
-
strategy=best-effort(核心重点): -
定义: 这是
rebootmgr中最灵活的策略。它结合了“锁机制(Locking)”和“故障回退(Fallback)”。 -
逻辑: 优先尝试获取集群锁(通过 etcd),如果锁服务故障(连接不上 etcd),它不会阻塞重启,而是会忽略锁直接重启。
-
lock-group=default: -
定义: 参与锁竞争的组名。
-
作用: 同一
lock-group内的机器会互相协调,确保不会所有机器同时重启(通常默认最大并发重启数为 1)。
2.2. 详细执行流程图 (Step-by-Step)
假设 transactional-update 在下午 14:00 完成了系统更新,此时系统标记为 "Reboot Needed"。以下是 rebootmgr 的决策逻辑:
2.2.1. 等待窗口 (14:00 - 03:29)
rebootmgr检测到重启请求。- 检查当前时间是否在
03:30-05:00之间。 - 结果: 不在窗口内。
- 动作: 什么都不做。系统继续运行旧快照,业务不受影响。
2.2.2 窗口开启与锁判定 (03:30)
时间到达 03:30,rebootmgr 唤醒并开始执行 best-effort 策略逻辑:
步骤 A: 检查集群锁配置
- 系统会检查是否配置了
etcd等后端。
步骤 B: 尝试获取锁 (根据环境不同会有不同结果)
-
场景 1:单机环境(无 etcd)
-
逻辑:尝试获取锁 -> 发现没有配置锁管理器 ->
best-effort策略生效。 -
判定:既然无法通过锁协调,为了保证更新生效,立即批准重启。
-
结果:服务器在 03:30 立即重启。
-
场景 2:集群环境(配置了 etcd)且运行正常
-
逻辑:向 etcd 请求
default组的重启锁。 -
判定:
-
若拿到锁: 立即重启。
-
若没拿到锁 (例如集群里其他节点正在重启): 等待。它会在窗口期内(03:30-05:00)不断重试获取锁。一旦其他节点释放锁,它就获取并重启。
-
场景 3:集群环境,但 etcd 挂了 (Best-Effort 的核心价值)
-
逻辑:尝试连接 etcd 获取锁 -> 连接超时/失败。
-
判定:如果是
strategy=etcd-lock,系统会为了安全放弃重启。但因为你配置了strategy=best-effort,系统判定“更新系统的优先级高于集群一致性保护”。 -
结果:忽略锁失败,强制重启。
2.2.3. 窗口关闭 (05:00)
如果在 03:30 到 05:00 之间,机器因为某些原因(比如一直没抢到锁)没有重启:
- 时间到达 05:00。
rebootmgr停止所有尝试。- 结果: 当天不再重启,推迟到明天 03:30 再次走上述流程。
3. Single Node With systemd-inhibit
接着我们再来看 Rebootmgr 在单节点中如何配合 systemd-inhibit
查看以下配置:
[rebootmgr]
strategy=maint-window
window-start=05:00
window-duration=1h30m
- 触发源:系统通过
transactional-update完成了软件包下载和快照生成。 - 标志位:系统被标记为
/run/reboot-needed(需要重启以应用新快照)。
具体Reboot执行逻辑参考 2. Cluster With etcd
若系统在维护窗口内且 /run/reboot-needed 文件存在时系统会被触发reboot以应用更新
但是有没有一种方法抑制这种行为呢 ?
当然有 ! 那就是 Inhibitor Lock(抑制锁)
systemd-inhibit DOC现在我们知道了可以通过添加抑制锁来阻止或延迟系统的休眠或关机,
不管这个休眠或关机的请求是用户发起的,还是操作系统自己触发的.
接着我们写一个脚本:
此脚本通过MAC地址反查其IP地址而后确认其是否在线
- 若在线: 则注册一个抑制锁来阻止或延迟系统的休眠或关机
- 若不在线: 释放抑制锁允许系统休眠或关机
slppe 60S继续检测
-
编写检测脚本
#!/bin/bash # ================= 配置区域 ================= # 在这里定义你要检测的 MAC 地址列表 # 格式注意:请使用标准的冒号分隔符 (XX:XX:XX:XX:XX:XX) # 只要列表里有任何一台机器存活,本机就会禁止重启。 TARGET_MACS=( "70:85:C2:F0:C3:C8" "00:11:22:33:44:55" # 示例:可以在这里添加更多 ) # 检测间隔(秒) CHECK_INTERVAL=60 # Ping 超时设置 (秒) PING_TIMEOUT=2 # =========================================== # 转换函数:将 MAC 转换为 IP get_ip_by_mac() { local mac="$1" # 使用 ip neigh (ARP缓存) 查找对应的 IP # grep -i 忽略大小写 ip neigh show | grep -i "$mac" | awk '{print $1}' | head -n 1 } while true; do BLOCK_REBOOT=false ALIVE_HOST="" # 为了保证 ARP 表是最新的,可以先尝试广播 ping 一下子网(可选,视网络环境而定) # 或者简单地假设如果这台机器很重要,它应该最近和本机有过通信。 for MAC in "${TARGET_MACS[@]}"; do # 1. 尝试获取 IP TARGET_IP=$(get_ip_by_mac "$MAC") if [ -n "$TARGET_IP" ]; then # 2. 如果找到了 IP,尝试 Ping 检测存活 # -c 1: 发送 1 个包 # -W: 等待超时时间 if ping -c 1 -W "$PING_TIMEOUT" "$TARGET_IP" > /dev/null 2>&1; then BLOCK_REBOOT=true ALIVE_HOST="$TARGET_IP ($MAC)" break # 只要发现一台存活,就不需要继续检查了,直接阻止重启 fi fi done if [ "$BLOCK_REBOOT" = true ]; then echo "$(date): Dependency alive [$ALIVE_HOST]. Inhibiting reboot..." # 核心逻辑:只要这个命令在运行,rebootmgr 就无法重启系统 # 我们使用 sleep 锁定 $CHECK_INTERVAL 的时间 systemd-inhibit \ --what=shutdown:sleep \ --who="MacDependencyGuard" \ --why="Host $ALIVE_HOST is online" \ --mode=block \ sleep "$CHECK_INTERVAL" else echo "$(date): No target hosts detected online. Reboot allowed." # 没有检测到存活主机,休眠一段时间后再次检测 sleep "$CHECK_INTERVAL" fi done -
赋予执行权限
chmod +x /usr/local/bin/mac-dependency-guard.sh -
创建 Systemd 服务
systemctl edit --force --full mac-dependency-guard.service
[Unit] Description=Block reboot based on LAN MAC address presence After=network-online.target Wants=network-online.target [Service] ExecStart=/usr/local/bin/mac-dependency-guard.sh Restart=always RestartSec=5 User=root [Install] WantedBy=multi-user.target -
启用并立即启动
systemctl enable --now mac-dependency-guard.service -
验证
-
查看服务日志
Dec 29 21:14:53 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:14:53 PM CST 2025: No target hosts detected online. Reboot allowed. Dec 29 21:15:55 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:15:55 PM CST 2025: No target hosts detected online. Reboot allowed. Dec 29 21:16:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:16:56 PM CST 2025: Dependency alive [10.255.255.114 (70:85:C2:F0:C3:C8)]. Inhibiting reboot.> Dec 29 21:17:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:17:56 PM CST 2025: Dependency alive [10.255.255.114 (70:85:C2:F0:C3:C8)]. Inhibiting reboot.> Dec 29 21:18:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:18:56 PM CST 2025: Dependency alive [10.255.255.76 (70:85:C2:F0:C3:C8)]. Inhibiting reboot... Dec 29 21:19:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:19:56 PM CST 2025: No target hosts detected online. Reboot allowed. Dec 29 21:20:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:20:56 PM CST 2025: Dependency alive [10.255.255.114 (70:85:C2:F0:C3:C8)]. Inhibiting reboot.> Dec 29 21:21:56 xzllll-homelab mac-dependency-guard.sh[3623]: Mon Dec 29 09:21:56 PM CST 2025: Dependency alive [10.255.255.114 (70:85:C2:F0:C3:C8)]. Inhibiting reboot.> -
查看抑制锁
➜ ~ systemd-inhibit --list WHO UID USER PID COMM WHAT WHY MODE MacDependencyGuard 0 root 5531 systemd-inhibit shutdown:sleep Host 10.255.255.114 (70:85:C2:F0:C3:C8) is online block ModemManager 0 root 1172 ModemManager sleep ModemManager needs to reset devices delay 2 inhibitors listed. ➜ ~ -
rebootmgrd log
Jan 03 00:29:56 xzllll-homelab rebootmgrd[17201]: Varlink method "Status" called... Jan 03 00:29:56 xzllll-homelab rebootmgrd[17201]: Varlink method "Reboot" called... Jan 03 00:29:56 xzllll-homelab rebootmgrd[17201]: Reboot in 19786 seconds at Sat 2026-01-03 05:59:43 CST Jan 03 05:59:43 xzllll-homelab rebootmgrd[17201]: rebootmgr: soft-reboot triggered now! Jan 03 05:59:43 xzllll-homelab systemctl[42055]: Call to Reboot failed: Access denied Jan 04 01:21:07 xzllll-homelab rebootmgrd[17201]: Varlink method "Status" called... Jan 04 01:21:07 xzllll-homelab rebootmgrd[17201]: Varlink method "Reboot" called... Jan 04 01:21:07 xzllll-homelab rebootmgrd[17201]: Reboot in 13418 seconds at Sun 2026-01-04 05:04:46 CST Jan 04 05:04:46 xzllll-homelab rebootmgrd[17201]: rebootmgr: soft-reboot triggered now! Jan 04 05:04:46 xzllll-homelab systemd[1]: Stopping Reboot Manager... Jan 04 05:04:46 xzllll-homelab systemd[1]: rebootmgr.service: Deactivated successfully. Jan 04 05:04:46 xzllll-homelab systemd[1]: Stopped Reboot Manager. Jan 04 05:04:59 xzllll-homelab systemd[1]: Starting Reboot Manager... Jan 04 05:04:59 xzllll-homelab rebootmgrd[132595]: Starting rebootmgrd (rebootmgr) 3.3... Jan 04 05:04:59 xzllll-homelab systemd[1]: Started Reboot Manager. -
尝试 reboot
➜ ~ reboot Operation inhibited by "MacDependencyGuard" (PID 67121 "systemd-inhibit", user root), reason is "Host 10.255.255.114 (70:85:C2:F0:C3:C8) is online". Please retry operation after closing inhibitors and logging out other users. 'systemd-inhibit' can be used to list active inhibitors. Alternatively, ignore inhibitors and users with 'systemctl reboot -i'.
-
4. Ex | 拓展
如果你确实需要忽略这个锁进行重启
你需要显式地告诉 systemd “忽略抑制器”
方法 A:标准的 Systemd 方式 (推荐)
使用 -i 或 --ignore-inhibitors 参数:
systemctl reboot -i
或者
reboot -i
方法 B:暴力方式 (不推荐)
systemctl reboot --force --force
