Поставил ИБП и научил сервер гаситься сам
Свет у меня моргает редко, но метко. Пару раз в год — короткое отключение на минуту-две, и каждый раз сервер падал жёстко, как будто выдернули вилку. А он так и было, по сути. После одного такого падения ext4 ругнулся при загрузке, а у Postgres пришлось чистить WAL. Ничего не потерял, но понервничал. После второго — поехал за ИБП.
Купил обычный линейно-интерактивный UPS с USB. Задача простая: продержать сервер пару минут и, если свет не вернулся, корректно его погасить — чтобы файловая система и базы закрывались штатно, а не аварийно.
Софт для этого — NUT (Network UPS Tools). Он общается с ИБП по USB, понимает заряд и состояние сети, и дёргает shutdown по заданным правилам.
Ставится из репозитория:
sudo apt install nut
Дальше три конфига. Сначала описываем сам ИБП в /etc/nut/ups.conf:
[homeups]
driver = usbhid-ups
port = auto
desc = "Home server UPS"
Проверяем, что NUT его видит:
sudo upsdrvctl start
upsc homeups
# battery.charge: 100
# ups.status: OL <- OL = на сети, OB = на батарее
Самое интересное — логика выключения. Живёт в /etc/nut/upssched.conf и в скрипте-обработчике. Я не глушу сервер при первом же чихе сети: даю отлежаться, и реагирую либо по таймеру на батарее, либо по проценту заряда — что наступит раньше.
# /etc/nut/upssched.conf
CMDSCRIPT /etc/nut/upssched-cmd
# свет пропал — НЕ паникуем, ждём 60 секунд
AT ONBATT * START-TIMER onbatt_grace 60
# свет вернулся раньше — отменяем таймер
AT ONLINE * CANCEL-TIMER onbatt_grace
# UPS сам кричит "заряд низкий" — гасимся немедленно
AT LOWBATT * EXECUTE ups_shutdown
А вот сам обработчик, где добавляю ещё и порог по проценту — не хочу дожидаться, пока батарея сядет в ноль:
#!/bin/bash
# /etc/nut/upssched-cmd
case $1 in
onbatt_grace)
CHARGE=$(upsc homeups battery.charge)
logger "NUT: на батарее, заряд ${CHARGE}%"
# ниже 50% — не рискуем, гасимся
if [ "$CHARGE" -le 50 ]; then
/usr/sbin/upsmon -c fsd # инициируем shutdown
fi
;;
ups_shutdown)
logger "NUT: LOWBATT, аварийное выключение"
/usr/sbin/upsmon -c fsd
;;
esac
Идея такая: пропал свет — ждём минуту (вдруг это короткое моргание и всё вернётся). Если через минуту мы всё ещё на батарее и заряд просел до 50% — гасим заранее, с запасом. А если ИБП сам сигналит LOWBATT — выключаемся не раздумывая.
Команда upsmon -c fsd (forced shutdown) запускает штатное выключение: systemd останавливает сервисы, контейнеры получают SIGTERM, базы закрываются как надо, ext4 размонтируется чисто.
Проверять это удобно, выдернув ИБП из розетки и глядя в логи (journalctl -fu nut-monitor). У меня сервер на батарее в простое живёт минут двадцать, так что 50%-порог срабатывает сильно раньше — времени на корректное гашение вагон.
С тех пор отключения света — не событие. Свет мигнул, сервер пережил, я даже не заметил. А если надолго — он сам аккуратно ляжет спать и утром поднимется без единого fsck.