前言
大学以来,接触 Linux 命令行的时间越来越多,也越来越发现,在使用成品 NAS 系统的时候会遇到各种不便利。黑群晖毕竟是特殊手段运行的,用 U 盘启动缓慢且系统魔改而庞大;OpenMediaVault 虽然基于 Debian,但发现其运行的 PHP Web 服务在我本地运行的时候出现了各种疑难杂症,包括但不限于 WebUI 上应用配置的时候,经常需要等一两分钟的情况。抱着更高自定义,更低资源占用的目的,和学习命令行操作的心态,我决定直接为 NAS 安装原生 Debian 并自行部署服务。
本文章是该部署过程中,对不间断电源相关配置的记录。
由于时间仓促,文章疏漏在所难免,如果你发现有什么不对的地方,跑不起来之类的,可以大胆提出,说不定是文章问题,欢迎在评论区交流~
环境和主要软件
- UPS设备: SANTAK TG-BOX 600
- 系统:Debian 12 bookworm x86_64
- UPS管理:NUT(Network UPS Tools)
- 邮件发送:msmtp
- 手机通知:ServerChan3
NUT
NUT (Network UPS Tools),顾名思义,具备网络功能的 UPS 工具。NUT 提供了非常多管理,控制和监控功能,可以为多 UPS,多设备的场景提供较为完善的管理支持。不过在本文,我们只讨论单独使用一个 UPS 为设备提供不间断电源的情况,只需要用到它的部分功能即可。
NUT 是一个 C/S(客户端/服务端) 架构的程序。这意味着,部署过程中,需要配置客户端部分和服务端部分。upsd 等充当服务端角色,向客户端提供 UPS 相关信息。upsmon 等充当客户端角色,监控并接收来自 upsd 提供的信息,并结合 upsd 提供的用户角色,对本机执行相关操作,并向服务端传递信息。
在本文运行场景下,客户端与服务端运行在同一个设备上。
安装
推荐使用 Debian 自带的 nut 软件包,他会将一系列运行需要的准备措施配置好。执行如下命令即可安装:
|
|
需要注意的是,如果你参考了官方文档,你可能会注意到,有关 upsd
的指令会执行失败,提示大致形如下方:
|
|
这是因为 Debian 软件包安装方式运行的 upsd 并不会创建 PID 文件,这些服务统一由 systemd 管理。upsd 在 systemd 中对应的服务是 nut-server
。因此,需要重启 upsd 的话,执行 systemctl restart nut-server
或者更直接地,重启整个 nut.target 即可。
配置
注意:本文列出的配置文件,通常仅涉及需要修改的部分。其余保持默认即可。
所有配置文件均位于 /etc/nut
目录下,后续不做说明。
NUT 运行模式 (nut.conf)
在本文讨论范围内(即单 UPS 单主机)情况下,只需如下配置即可。
UPS 驱动 (ups.conf)
配置 UPS 驱动相对较为简单。通常情况下,以 root 权限运行 nut-scanner
即可自动扫描,获取到当前 UPS 的信息。示例的输出结果如下,可以看到,山特 TG-BOX 系列的驱动是 usbhid-ups
。
|
|
通常情况下,复制从 [netdev1]
到最后的输出,然后粘贴到 /etc/nut/ups.conf
文件末尾即可直接使用。其中 [nutdev1]
为 UPS 名字,你可以自定义。我使用 [santek]
。
配置完成后,使用 systemctl restart nut.target
重启整个 nut 服务,然后可执行如下命令,检查 UPS 状态信息。其中,UPSNAME 修改为上述你自定义的 UPS 名字。
|
|
执行后,输出形如下方:
|
|
upsd 用户 (upsd.users)
在文件末尾加上如下内容。
其中,USERNAME
改成你想要取的用户名,PASSWORD
改成你自定义的密码即可。
关于 upsmon primary,注释中有写,大致上就是为多设备情况下,调度电源策略使用。本文场景单设备,直接使用 primary (主服务器)即可。
本地运行无需修改 upsd.conf 的监听地址,因此无需动 upsd.conf,除非有需求。
upsmon 客户端配置 (upsmon.conf)
MONITOR 部分指定了 upsmon 客户端需要监控哪个 UPS 服务和设备。在 MONITOR 部分,加上如下配置
其中修改 UPSNAME 为 ups.conf 中你自定义的名字。由于 upsd 在本地运行,因此主机名直接写 localhost 即可。USERNAME 和 PASSWORD 与上文设置的一致。通常情况下,无需更改 powervalue,保持为 1 即可,除非系统特殊。详见官方文档。
如此设定之后,使用默认的配置即可实现低电量自动关机。你可以使用 systemctl restart nut.target
重启整个 nut 服务,应用更改的配置。随后,用如下命令进行低电量 Forced Shutdown 的模拟测试。
注意:这会执行 UPS 低电量时的整个关机流程,因此这会关闭你的 NAS 电源并重启你的 UPS。请不要在无法直接可靠接触到设备时操作,以免造成服务无法访问。
|
|
至此,整个 UPS 系统配置完毕。文末附录贴上了(稍微审核了一下没问题的)由 ChatGPT 翻译的 NUT 文档描述的关机流程,可供参考。
通知
UPS 系统能正常运作之后,我们通常还希望能及时了解到其状态的变化。在我的环境下,我用 邮件+ServerChan3 的提醒策略,既可以保证收到邮件,又能用 Server 酱及时在手机上收到提醒。
由于我只需要实现简单的提醒功能,因此不使用 upssched 进行更高级的配置,直接用 upsmon 自带的 NOTIFYCMD 即可。
由于只需要发送邮件提醒,而 sendmail 工具配置相对复杂,本文使用 msmtp。
安装
直接使用包管理器提供的安装包即可。
|
|
编写邮件发件配置
msmtp 可以使用系统默认配置和用户配置。前者位于 /etc/msmtprc
,后者位于 ~/.msmtprc
或 $XDG_CONFIG_HOME/msmtp/config
。
本文采用系统配置。编辑 /etc/msmtprc
,样例配置如下:
配置完成后,可使用如下命令测试发件情况。(由于邮件信息不全,可能会被认为是 spam 而被放入垃圾箱,请检查)
|
|
设定发件 & Server 酱脚本
由于 upsmon 的 NOTIFYCMD 将 NOTIFYMSG(下文会进行设置)内容通过字符串参数方式传递给 NOTIFYCMD 执行的指令,因此可以自定义一个脚本,读取字符串并进行切割处理,匹配到标题和正文进行发送。
示例脚本如下:
|
|
记得授予执行权限。
该脚本读取 NOTIFYMSG 内容,并识别其中的竖线分隔符("|"),将分隔符前面的内容识别为标题,后面的内容识别为正文;随后,通过 msmtp 和 curl 分别发送邮件和通知 ServerChan3。
如果你不需要 ServerChan3 通知,可以将 # ServerChan3
后面的部分全部删除。
设置 upsmon 触发通知
回到 /etc/nut/upsmon.conf
。设置如下内容:
|
|
通知部分到这里就结束啦,可以实现简单的提醒功能了~
最后
至此,简单的 UPS 配置和通知提醒就完成啦~ˋ( ° ▽、° )
参考资料
附录:NUT 关机流程设计(Shutdown Design)
当 UPS 电池电量不足时,操作系统需要被优雅地关闭。此外,UPS 的负载也需要断电,以便连接到 UPS 上的所有设备都能被强制重启,并在之后以可预测的顺序和状态重新启动,适应数据中心的需求。
以下是发生关键电源事件时的典型关机流程(以“一台 UPS 供电给一台或多台系统”的简单情况为例):
-
UPS 切换至电池供电(on battery)
-
UPS 电量降至低电(low battery)状态,成为“关键 UPS(critical UPS)”,即
upsc
显示如下状态:1
ups.status: OB LB
具体行为取决于 UPS 的型号,相关的参数包括:
battery.charge
与battery.charge.low
battery.runtime
与battery.runtime.low
-
主机上的
upsmon
进程检测到“关键 UPS”状态,并设置FSD
(强制关机标志,Forced Shutdown),通知所有次级系统(secondary)准备断电。
⚠️ 警告:
根据设计,为了确保所有系统能同时断电重启(而不是电力恢复时部分系统开机、部分仍关机),一旦 FSD
被设置,它将无法被取消,除非你重启 upsmon
进程。一旦进入关键电源模式,意味着我们打算完整执行整个流程——即优雅地关闭所有服务器,并最终关闭 UPS。
请注意:某些 UPS 设备及其驱动即使在“市电已恢复”后,也会继续保持 FSD
状态——只要电池电量未达到设备定义的安全阈值。这通常出现在“长时间停电后手动重启 UPS”的场景中。这是 UPS 厂商的设计策略,因为在这种情况下,如果再次停电,UPS 可能无法保证安全地关闭系统。因此,它们倾向于在电池未充满前保持关闭状态,以确保安全。
(如果你没有配置次级系统,直接跳至第 6 步) # 笔者注:本文环境无次级系统,直接跳到第 6 步。
-
所有次级系统的
upsmon
进程检测到FSD
,并执行以下操作:- 生成
NOTIFY_SHUTDOWN
事件 - 等待
FINALDELAY
秒(默认通常为 5 秒) - 调用配置的
SHUTDOWNCMD
- 与
upsd
服务断开连接
- 生成
-
主机(primary)系统等待最多
HOSTSYNC
秒(默认通常为 15 秒),以便让所有次级系统断开。如果在超时后仍有系统连接,主机将不再等待,继续执行自己的关机流程。 -
主机
upsmon
执行以下操作:- 生成
NOTIFY_SHUTDOWN
事件 - 等待
FINALDELAY
秒(默认通常为 5 秒) - 在本地文件系统中创建
POWERDOWNFLAG
文件(通常是/etc/killpower
,或临时目录下的/run/nut/killpower
) - 执行
SHUTDOWNCMD
(通常是shutdown -h now
)
- 生成
-
在大多数系统上,init 进程接管后会:
- 终止所有进程
- 同步并卸载部分文件系统
- 将部分文件系统重新挂载为只读
-
接着 init 执行你的关机脚本。该脚本会检查
POWERDOWNFLAG
,如果存在,就通知 UPS 驱动,向 UPS 发送断电命令,关闭 UPS 输出电源。 -
所有系统彻底失去电力。
-
时间过去,市电恢复,UPS 自动重新供电。
-
所有系统重启并恢复正常运行。