PVE配合UPS实现断电关机和来电自启
前言
在家里搭建All in One服务器,很重要的一点就是数据安全。由于家里使用的是普通的居民用电,因此总会有停电的可能性。所以为了防止数据损坏,UPS(不间断电源)几乎是必备的装备了。一般对于成品NAS来说,厂家已经帮我们设置好了,插上UPS的USB线就可以用,但如果是自己DIY的服务器,就需要自己设置。我家的服务器底层操作系统是PVE,可以使用NUT(Network UPS Tools)软件包实现需求。
NUT的安装可以使用APT包管理器,而设置基于配置文件、脚本和命令行,官方文档又是全英文的,对于新手还是挺头痛的。截止发布时,最新版本是2.8.0,但网上的各类教程都是2.7.*的,配置文件中的部分参数会有不同。我也是结合官方的文档才最终搞定。在此记录下全过程,作为笔记待用,也分享给有需要的人。
本人使用的PVE版本为8.2.7,UPS是山特(santak)tg-box 850。经过设置,可以实现停电自动关机、来电自动启动,并发送电子邮件通知。
安装
进入PVE的控制台(或SSH到服务器),使用APT包管理器安装NUT。
apt install -y nut |
注意,在Debian中,nut包包含nut-server和nut-client两部分,因此安装nut就可以了,不需要像有些教程中那样安装两个包。
另外,确保UPS的USB线正确连接UPS和服务器主机,服务器主机的BIOS设置中打开通电自启。
NUT基本上分为两部分,server和client。server负责和UPS通讯,将UPS的信息发送给各个client,client负责处理策略,控制主机行为。因此,通过USB线直接连接UPS的主机同时需要server和client两部分,而其他UPS负载的主机仅需要client部分,他们可以通过局域网和server通讯。
另外,PVE上的虚拟机不需要安装nut-client,因为在PVE上执行关机命令时,PVE会自动按照用户设置的启动优先级反序关闭所有虚拟机,之后才关闭系统。
设置nut-server
添加UPS
首先确认UPS的USB信号已经正确连接:
lsusb |
返回如下:
Bus 002 Device 002: ID 05e3:0626 Genesys Logic, Inc. Hub |
可以看到其中有UPS的信息,UPS已经正确连接了。
获取UPS的详细信息:
nut-scanner -U |
返回如下:
Scanning USB bus. |
我们稍后需要把这些信息添加到nut-server的UPS列表里。
nut的所有配置文件都在/etc/nut目录,先打开UPS列表文件ups.conf,在最后添加:
[tg-box] |
注意这部分信息来自于上面nut-scanner -U命令的输出。只需要把[]中的名字改成自己喜欢的,另外删掉最后的bus = "001"(不固定usb接口)。
设置工作模式
打开nut.conf,修改对应项目为:
MODE=netserver |
这里可用选项有三个:
none:不启用;standalone: 启用几乎所有功能,但是不监听网络,适用于UPS只为一台物理机供电的情况;netserver:启用所有功能,包括监听网络,为其他client提供服务;netclient:只启用client部分,适用于UPS上负载的其他物理机。
其实不管有没有其他client,都可以设置为netserver,没有关系。
设置网络监听
打开upsd.conf,最后一行添加或改为:
LISTEN * 3493 |
该设置会监听IPv4和IPv6所有地址的3493端口,如果只监听IPv4:
LISTEN 0.0.0.0 3493 |
修改角色列表
打开upsd.users,添加:
[ups_host] |
[]里是角色名,可以设置成自己喜欢的,密码改成强一点的密码。这里解释下最后一行。
upsmon primary和upsmon secondary赋予使用不同角色登陆server的client应有的关机优先级和权限,前者设计用于直接连接UPS的主机,并会等待所有使用后者的主机关机完成才开始关机。注意,这个已经有控制权限的作用,不要学其他教程再添加actions和instcmds条目,不然会出现不可预期的错误。
启动nut-server
nut相关服务可以有两种启动方式,自带命令或利用systemd管理,两种方式不兼容。为方便统一管理,建议都利用systemd启动服务:
systemctl restart nut-server |
确认UPS状态:
upsc tg-box |
这个地方语法是upsc name@host:port,如果前面设置的是默认端口3493,则可以省略端口号,如果host是localhost(同一台主机),则还可以省略主机名。
返回内容很多:
Init SSL without certificate database |
其中battery.charge表示当前电量百分比,battery.charge.low表示低电量阈值。
现在server部分设置完成了。
设置nut-client
监控程序upsmon
client部分的主程序是监控程序upsmon。打开upsmon.conf,修改相关内容:
# 登陆服务端,指定监控的UPS。 |
解释一下大致流程:upsmon登陆到server端,获取ups事件,如果触发了某个事件,推送相应通知内容到相应目标。目标中SYSLOG指系统日志,WALL指发送给当前登陆的所有用户,EXEC指执行NOTIFYCMD指定的命令。
NUT默认会在UPS严重事件(如低电量、UPS失去信号连接)时触发FSD(Forced shutdown),而我希望市电断开一定时间后开始关机流程,因此需要在upssched中设置策略。所以这个地方我设置触发ONLINE和ONBATT事件时推送到EXEC。
再解释一下FSD:这个流程会先关闭登陆upsmon secondary的机器,再关闭登陆upsmon primary的机器,另外,还会通知UPS没有负载后关机。UPS会在所有机器关机后断电,并准备好在下一次市电恢复时重新通电。
其他部分保持默认,不用修改了。
设置upssched
上一步中指定的命令upssched的具体执行动作需要进一步设置,配置文件依然在/etc/nut中。upssched主要的的作用是定时执行脚本。修改upssched.conf:
# 指定要执行的脚本位置 |
解释一下触发对应事件的动作部分:
基本语法是以AT开头,后面的ONBATT和ONLINE是从upsmon传递过来的事件。后面可以接:
START-TIMER:开始计时,后面接计时器名和时间(单位为秒),时间到后会将计时器名作为参数传递给执行脚本;CANCEL-TIMER:取消计时,后面接计时器名,会取消前面同名的计时器;EXCUTE:不计时直接将后面接的字符串作为参数传递给执行脚本并执行。
这个地方我设置的逻辑就是,一旦UPS开始使用电池(市电断开),就执行一次脚本的onbatt部分,并开始一个60s的计时器。这60s中如果市电未恢复,则执行脚本的poweroff部分;如果市电恢复,就取消poweroff计时器并执行backonline。
可以看出,upssched利用传递不同参数,运行脚本的不同部分,因此在下一步的脚本中,需要一个判断参数的case结构。
编写upssched-cmd脚本
上一步我们指定了执行脚本的位置是/etc/nut/upssched-cmd,这个脚本是不存在的,我们需要新建一个脚本文件,并按以下格式填入内容:
|
关于NUT的FSD流程,可以查看这里
发送邮件部分,需要服务器有公网访问权限,并且DNS解析的记录和服务器的FQDN一致,否则需要配置STMP。
更改下脚本文件的权限:
chown root:nut /etc/nut/upssched-cmd |
启动nut-client
现在可以启动nut-client了,和nut-server一样,还是推荐用systemd统一管理。
systemctl restart nut-client |
测试
先检查下服务状态:
systemctl status nut-server |
两个服务都应该显示active (running)。
注意!!!后续测试拔插头都是拔UPS的插头,不要拔掉主机插在UPS上的插头!!!
注意!!!后续测试拔插头都是拔UPS的插头,不要拔掉主机插在UPS上的插头!!!
注意!!!后续测试拔插头都是拔UPS的插头,不要拔掉主机插在UPS上的插头!!!
拔掉UPS的插头,邮箱应该会收到邮件提示,计时60s后PVE开始关闭所有虚拟机,虚拟机关闭完成后PVE物理机关闭,之后UPS自动关机断电。
重新插上UPS的电源,UPS开机通电,之后PVE物理机自动启动,虚拟机按照用户设置顺序启动。
总结
NUT分成了许多个模块,运行顺序是driver → upsd → upsmon → upssched → upssched-cmd ,通过配置文件中的设置连接。并且upsmon内置了fsd命令,可以按顺序关闭所有负载后关闭UPS。
