openSUSE MicroOS Rebootmgr & systemd-inhibit

实践 | Practices 2025年12月30日

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)

  1. rebootmgr 检测到重启请求。
  2. 检查当前时间是否在 03:30 - 05:00 之间。
  3. 结果: 不在窗口内。
  4. 动作: 什么都不做。系统继续运行旧快照,业务不受影响。

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 之间,机器因为某些原因(比如一直没抢到锁)没有重启:

  1. 时间到达 05:00。
  2. rebootmgr 停止所有尝试。
  3. 结果: 当天不再重启,推迟到明天 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
systemd-inhibit(1) — Arch manual pages

现在我们知道了可以通过添加抑制锁来阻止或延迟系统的休眠或关机,

不管这个休眠或关机的请求是用户发起的,还是操作系统自己触发的.

接着我们写一个脚本:

此脚本通过MAC地址反查其IP地址而后确认其是否在线

  • 若在线: 则注册一个抑制锁来阻止或延迟系统的休眠或关机
  • 若不在线: 释放抑制锁允许系统休眠或关机 slppe 60S 继续检测
  1. 编写检测脚本

    #!/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
    
  2. 赋予执行权限

    chmod +x /usr/local/bin/mac-dependency-guard.sh
    
  3. 创建 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
    
  4. 启用并立即启动

    systemctl enable --now mac-dependency-guard.service
    
  5. 验证

    1. 查看服务日志

      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.>
      
    2. 查看抑制锁

      ➜  ~ 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.
      ➜  ~
      
    3. 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.
      
    4. 尝试 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
👩‍🏫
在采用 systemd 作为初始化系统(init system)的现代 Linux 发行版中,reboot 命令实际上只是指向 systemctl 的一个 符号链接(Symbolic Link) 或包装器

方法 B:暴力方式 (不推荐)

systemctl reboot --force --force
👩‍🏫
Specifying --force twice with any of these operations might result in data loss. Note that when --force is specified twice the selected operation is executed by systemctl itself, and the system manager is not contacted. This means the command should succeed even when the system manager has crashed.

Thanks & Copy

GitHub - SUSE/rebootmgr
Contribute to SUSE/rebootmgr development by creating an account on GitHub.
Inhibitor Locks

标签

xzllll

三分钟热度三分钟收获