Задача клиента: оператор связи теряет серверы из-за отключений электричества
Осенью 2025 года к нам обратился региональный оператор связи КомЛинк из Воронежа. Компания обслуживает 15 000 абонентов и предоставляет услуги интернета, телефонии и IPTV. В серверной стоят 6 стоек с оборудованием: коммутаторы, маршрутизаторы, серверы биллинга, BRAS и медиа-платформа.
Проблема пришла неожиданно: в сентябре во время грозы произошло отключение электричества на 40 минут. ИБП (источники бесперебойного питания) продержали нагрузку 12 минут, после чего разрядились. Два сервера — биллинг на Dell PowerEdge R740 и BRAS на SuperMicro — не пережили жёсткого отключения. У биллинга оказался повреждён RAID-контроллер, у BRAS — два SSD из зеркала.
«Мы были офлайн 14 часов. 15 000 абонентов без интернета, телефоны раскалены, мы теряли клиентов каждый час. Ущерб — больше миллиона рублей, не считая ремонта серверов» — технический директор КомЛинк.
Расследование показало, что ИБП были установлены при запуске серверной 5 лет назад и ни разу не тестировались. Никто не знал реальное время автономной работы, состояние батарей и текущую нагрузку на каждый UPS.
Аудит системы электропитания
Наши инженеры провели полный аудит серверной и обнаружили критическую ситуацию:
| Стойка | UPS | Нагрузка | Ёмкость батарей | Время автономии |
|---|
| Стойка 1 (Биллинг) | APC Smart-UPS 3000VA | 2 400 Вт (80%) | 62% (изношены) | ~6 мин |
| Стойка 2 (BRAS) | APC Smart-UPS 3000VA | 2 100 Вт (70%) | 55% (изношены) | ~8 мин |
| Стойка 3 (Коммутация) | Eaton 5PX 2200VA | 1 800 Вт (82%) | 78% | ~7 мин |
| Стойка 4 (Медиа) | APC Smart-UPS 2200VA | 1 900 Вт (86%) | 45% (критично) | ~4 мин |
| Стойка 5 (Мониторинг) | CyberPower OL3000 | 1 200 Вт (40%) | 90% | ~20 мин |
| Стойка 6 (Резерв) | Eaton 5PX 1500VA | 800 Вт (53%) | 85% | ~12 мин |
Проблемы:
- Нет мониторинга — никто не знал состояние UPS в реальном времени
- Нет автоматического отключения — серверы работали до полного разряда батарей
- Изношенные батареи — стойки 1, 2, 4 требовали замены батарей
- Перегрузка — стойки 1, 3, 4 работали на 80%+ мощности (рекомендуется не выше 70%)
- Разнородное оборудование — три бренда UPS, разные интерфейсы управления
Проектирование системы мониторинга
Мы спроектировали комплексное решение на базе двух технологий:
- NUT (Network UPS Tools) — для UPS с USB/Serial-подключением (APC и CyberPower)
- SNMP — для UPS с сетевыми картами (Eaton с предустановленными Network-M2)
Архитектура:
# Архитектура мониторинга UPS
┌──────────────────────────────────────────────────┐
│ Zabbix Server (Стойка 5) │
│ ┌───────────┐ ┌────────────┐ ┌─────────────┐ │
│ │ Dashboards │ │ Alerts │ │ Capacity │ │
│ │ & Maps │ │ (Telegram) │ │ Planning │ │
│ └───────────┘ └────────────┘ └─────────────┘ │
└───────┬──────────────┬──────────────┬────────────┘
│ │ │
NUT (SNMP) NUT (USB) SNMP native
│ │ │
┌──────┴──────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ APC×3 │ │CyberPower │ │ Eaton×2 │
│ (USB→NUT) │ │ (USB→NUT) │ │(SNMP card)│
└─────────────┘ └───────────┘ └───────────┘
Дополнительно мы запланировали: замену батарей в трёх ИБП, перераспределение нагрузки и настройку каскадного автоматического отключения серверов.
Установка и настройка NUT (Network UPS Tools)
NUT — это универсальный фреймворк для мониторинга UPS под Linux. Он поддерживает сотни моделей от десятков производителей и работает по клиент-серверной модели: один NUT-сервер опрашивает UPS, а несколько NUT-клиентов на защищаемых серверах получают данные и выполняют автоматическое отключение.
Конфигурация NUT-сервера для APC Smart-UPS
NUT-сервер мы развернули на выделенном хосте мониторинга (стойка 5), к которому по USB были подключены APC Smart-UPS из стоек 1 и 2, а остальные опрашивались по сети:
# Установка NUT на Ubuntu 22.04
sudo apt update
sudo apt install -y nut nut-client nut-server
# Определение подключённых UPS
sudo nut-scanner -U # Сканирование USB-устройств
# [nutdev1]
# driver = "usbhid-ups"
# port = "auto"
# vendorid = "051D" # APC
# productid = "0002"
# serial = "AS1234567890"
Конфигурация UPS-устройств в /etc/nut/ups.conf:
# /etc/nut/ups.conf
[apc-billing]
driver = usbhid-ups
port = auto
serial = AS1234567890
desc = "APC Smart-UPS 3000 - Стойка 1 (Биллинг)"
pollinterval = 5
[apc-bras]
driver = usbhid-ups
port = auto
serial = AS0987654321
desc = "APC Smart-UPS 3000 - Стойка 2 (BRAS)"
pollinterval = 5
[apc-media]
driver = usbhid-ups
port = auto
serial = AS1122334455
desc = "APC Smart-UPS 2200 - Стойка 4 (Медиа)"
pollinterval = 5
[cyberpower-monitoring]
driver = usbhid-ups
port = auto
serial = CP6677889900
desc = "CyberPower OL3000 - Стойка 5 (Мониторинг)"
pollinterval = 5
Настройка режима работы NUT и пользователей:
# /etc/nut/nut.conf
MODE=netserver
# /etc/nut/upsd.conf
LISTEN 0.0.0.0 3493
MAXAGE 25
# /etc/nut/upsd.users
[admin]
password = UPS_Adm1n_S3cure!
actions = SET
instcmds = ALL
[monitor]
password = UPS_M0n_R3ad!
upsmon slave
[upsmon_local]
password = UPS_L0cal_M@ster!
upsmon master
Настройка NUT-клиентов на защищаемых серверах
На каждом сервере, который должен корректно завершать работу при разряде UPS, мы установили NUT-клиент:
# Установка на сервере биллинга
sudo apt install -y nut-client
# /etc/nut/nut.conf
MODE=netclient
# /etc/nut/upsmon.conf
MONITOR apc-billing@10.0.5.10 1 monitor UPS_M0n_R3ad! slave
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
POLLFREQ 5
POLLFREQALERT 2
HOSTSYNC 15
DEADTIME 25
RBWARNTIME 43200 # Предупреждать о замене батареи каждые 12 часов
NOCOMMWARNTIME 300 # Предупреждать о потере связи через 5 мин
FINALDELAY 5
# Скрипт уведомлений
NOTIFYCMD /opt/scripts/nut-notify.sh
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYFLAG FSD SYSLOG+EXEC
NOTIFYFLAG REPLBATT SYSLOG+EXEC
NOTIFYFLAG NOCOMM SYSLOG+EXEC
Скрипт уведомлений, отправляющий алерты в Telegram:
#!/bin/bash
# /opt/scripts/nut-notify.sh
TG_BOT_TOKEN="..." # Из переменных окружения
TG_CHAT_ID="..."
HOSTNAME=$(hostname)
MSG="⚡ UPS Alert на ${HOSTNAME}:\n${NOTIFYTYPE}\n\nUPS: ${UPSNAME}"
curl -s -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
-d chat_id="${TG_CHAT_ID}" \
-d text="${MSG}" \
-d parse_mode=HTML
logger -t nut-notify "${NOTIFYTYPE}: ${UPSNAME}"
Каскадное отключение серверов
Критически важный момент: при разряде UPS серверы должны отключаться в определённом порядке. Нельзя выключить биллинг раньше, чем BRAS корректно завершит сессии абонентов.
Мы реализовали каскадное отключение через скрипт на NUT-сервере:
#!/bin/bash
# /opt/scripts/cascade-shutdown.sh
# Вызывается при LOWBATT от любого UPS
set -euo pipefail
LOG="/var/log/cascade-shutdown.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG"
}
log "=== КАСКАДНОЕ ОТКЛЮЧЕНИЕ НАЧАТО ==="
# Фаза 1: некритичные сервисы (медиа-платформа)
log "Фаза 1: Отключение медиа-сервера..."
ssh root@10.0.1.40 'systemctl stop iptv-streaming && shutdown -h now' &
sleep 10
# Фаза 2: BRAS (завершение абонентских сессий)
log "Фаза 2: Graceful shutdown BRAS..."
ssh root@10.0.1.20 '/opt/scripts/bras-graceful-stop.sh && shutdown -h now' &
sleep 30 # Даём время на завершение сессий
# Фаза 3: Биллинг (после завершения BRAS)
log "Фаза 3: Отключение биллинга..."
ssh root@10.0.1.10 'systemctl stop billing-app && pg_ctlcluster 16 main stop && shutdown -h now' &
sleep 15
# Фаза 4: Мониторинг (последний)
log "Фаза 4: Отключение мониторинг-сервера..."
log "=== ВСЕ СЕРВЕРЫ ОТКЛЮЧЕНЫ ==="
shutdown -h now
Время выполнения полного каскада — около 60 секунд. При ёмкости батарей, обеспечивающей минимум 5 минут автономии, запас был более чем достаточным.
Мониторинг Eaton UPS через SNMP
Два ИБП Eaton 5PX в стойках 3 и 6 были оснащены сетевыми картами Eaton Network-M2, поддерживающими SNMPv3. Мы подключили их напрямую к Zabbix без промежуточного NUT.
Настройка SNMPv3 на Eaton Network-M2
SNMPv3 — обязательный выбор для продакшн-среды, так как v1/v2c передают community string открытым текстом. В серверной оператора связи, где проходят данные абонентов, это недопустимо — перехват SNMP-пакетов позволил бы злоумышленнику узнать состояние инфраструктуры и спланировать атаку в момент переключения на батарею.
Eaton Network-M2 — сетевая карта, устанавливаемая непосредственно в слот UPS. Она превращает ИБП в полноценное сетевое устройство с веб-интерфейсом, SNMP, Modbus TCP и REST API. Настройку мы выполняли через веб-интерфейс:
# Настройка через веб-интерфейс Eaton Network-M2
# https://10.0.5.30 → Network → SNMPv3
# Параметры пользователя:
# Username: zabbix_mon
# Auth Protocol: SHA-256
# Auth Password: SNMP_Auth_S3cure!
# Privacy Protocol: AES-256
# Privacy Password: SNMP_Priv_K3y!
# Access: Read-Only
# Проверка с хоста мониторинга
snmpwalk -v3 -u zabbix_mon \
-l authPriv \
-a SHA-256 -A "SNMP_Auth_S3cure!" \
-x AES256 -X "SNMP_Priv_K3y!" \
10.0.5.30 \
1.3.6.1.4.1.534.1 # Eaton MIB root
# Пример: получение заряда батареи
snmpget -v3 -u zabbix_mon \
-l authPriv \
-a SHA-256 -A "SNMP_Auth_S3cure!" \
-x AES256 -X "SNMP_Priv_K3y!" \
10.0.5.30 \
1.3.6.1.2.1.33.1.2.4.0 # upsEstimatedChargeRemaining
# INTEGER: 78
Ключевые OID для мониторинга UPS
Стандартные OID из UPS-MIB (RFC 1628), которые мы мониторили:
| OID | Параметр | Тип |
|---|
| 1.3.6.1.2.1.33.1.2.1.0 | Статус батареи (1=unknown, 2=normal, 3=low, 4=depleted) | INTEGER |
| 1.3.6.1.2.1.33.1.2.2.0 | Время работы от батареи (секунды) | INTEGER |
| 1.3.6.1.2.1.33.1.2.3.0 | Оставшееся время автономии (минуты) | INTEGER |
| 1.3.6.1.2.1.33.1.2.4.0 | Заряд батареи (%) | INTEGER |
| 1.3.6.1.2.1.33.1.2.5.0 | Температура батареи (°C × 10) | INTEGER |
| 1.3.6.1.2.1.33.1.3.3.1.3.1 | Входное напряжение (В × 10) | INTEGER |
| 1.3.6.1.2.1.33.1.4.4.1.5.1 | Выходная мощность (Вт) | INTEGER |
| 1.3.6.1.2.1.33.1.4.4.1.4.1 | Нагрузка (%) | INTEGER |
Интеграция с Zabbix: шаблоны, триггеры и дашборды
У КомЛинк уже был установлен Zabbix 6.4. Мы создали единый дашборд, объединяющий данные со всех 6 UPS — как с NUT, так и с SNMP.
Шаблон Zabbix для NUT
Для UPS, подключённых через NUT, мы использовали UserParameter в Zabbix Agent:
# /etc/zabbix/zabbix_agentd.d/nut.conf
# Установка на NUT-сервере (10.0.5.10)
UserParameter=nut.ups.status[*],upsc $1 ups.status 2>/dev/null || echo "N/A"
UserParameter=nut.battery.charge[*],upsc $1 battery.charge 2>/dev/null || echo "0"
UserParameter=nut.battery.runtime[*],upsc $1 battery.runtime 2>/dev/null || echo "0"
UserParameter=nut.battery.voltage[*],upsc $1 battery.voltage 2>/dev/null || echo "0"
UserParameter=nut.input.voltage[*],upsc $1 input.voltage 2>/dev/null || echo "0"
UserParameter=nut.output.voltage[*],upsc $1 output.voltage 2>/dev/null || echo "0"
UserParameter=nut.ups.load[*],upsc $1 ups.load 2>/dev/null || echo "0"
UserParameter=nut.ups.temperature[*],upsc $1 ups.temperature 2>/dev/null || echo "0"
UserParameter=nut.battery.date[*],upsc $1 battery.date 2>/dev/null || echo "N/A"
# Перезапуск агента
sudo systemctl restart zabbix-agent
Проверка работоспособности:
# С Zabbix-сервера
zabbix_get -s 10.0.5.10 -k nut.battery.charge[apc-billing]
# 62
zabbix_get -s 10.0.5.10 -k nut.ups.status[apc-billing]
# OL (Online — работа от сети)
Триггеры и оповещения
Мы настроили многоуровневую систему алертов:
# Триггеры Zabbix (экспорт в формате описания)
# CRITICAL: UPS работает от батареи
Trigger: UPS {HOST.NAME} на батарее
Expression: last(/Template NUT UPS/nut.ups.status[{$UPS_NAME}])="OB"
Severity: High
Action: Telegram + SMS дежурному
# CRITICAL: Заряд батареи < 30%
Trigger: UPS {HOST.NAME} заряд батареи {ITEM.VALUE}%
Expression: last(/Template NUT UPS/nut.battery.charge[{$UPS_NAME}])<30
Severity: Disaster
Action: Telegram + SMS + Звонок
# WARNING: Нагрузка > 70%
Trigger: UPS {HOST.NAME} перегружен {ITEM.VALUE}%
Expression: last(/Template NUT UPS/nut.ups.load[{$UPS_NAME}])>70
Severity: Warning
Action: Telegram
# WARNING: Температура батареи > 35°C
Trigger: UPS {HOST.NAME} перегрев {ITEM.VALUE}°C
Expression: last(/Template NUT UPS/nut.ups.temperature[{$UPS_NAME}])>35
Severity: Warning
Action: Telegram
# INFO: Батарея требует замены
Trigger: UPS {HOST.NAME} замените батарею
Expression: last(/Template NUT UPS/nut.ups.status[{$UPS_NAME}])="RB"
Severity: Average
Action: Telegram + Email IT-директору
Дашборд мониторинга
Мы создали единый дашборд в Zabbix, отображающий все 6 UPS на одном экране. Это было принципиально важно для дежурной смены — оператор NOC (Network Operations Center) должен видеть состояние всей системы питания одним взглядом, без переключения между экранами.
Ключевые виджеты:
- Сводная таблица — статус, заряд, нагрузка, время автономии для каждого UPS
- График входного напряжения — 24 часа, все UPS на одном графике (позволяет видеть просадки)
- График нагрузки — тренд за месяц для планирования ёмкости
- Карта серверной — визуальная схема стоек с цветовой индикацией статуса UPS
Для карты серверной мы использовали функцию Zabbix Maps:
# Цветовая индикация:
# Зелёный — OL (Online, питание от сети)
# Жёлтый — OL CHRG (Online, идёт зарядка после отключения)
# Красный — OB (On Battery, работа от батареи)
# Серый — OFF (UPS выключен или нет связи)
# Мигающий красный — OB LB (Low Battery, критический разряд)
Планирование ёмкости и замена батарей
Мониторинг — это только половина работы. Вторая половина — обеспечить достаточное время автономии для корректного отключения всех серверов.
Расчёт необходимого времени автономии
Мы составили матрицу требований:
| Сервер | Время корректного отключения | UPS | Требуемая автономия |
|---|
| Медиа-платформа | 15 сек (просто shutdown) | APC 2200VA | ≥ 2 мин |
| BRAS | 30 сек (graceful stop сессий) | APC 3000VA | ≥ 3 мин |
| Биллинг (PostgreSQL) | 45 сек (checkpoint + shutdown) | APC 3000VA | ≥ 4 мин |
| Коммутация | 10 сек | Eaton 2200VA | ≥ 5 мин (последним) |
| Мониторинг | 10 сек | CyberPower 3000VA | ≥ 6 мин (самый последний) |
С учётом каскадного отключения (60 сек) и запаса безопасности (×2), минимальное время автономии для каждого UPS — 10 минут при текущей нагрузке.
Замена батарей и перебалансировка нагрузки
По результатам аудита мы выполнили физические работы:
- Стойка 1 — замена батарейного модуля APC RBC55 (ёмкость восстановлена до 95%)
- Стойка 2 — замена батарейного модуля APC RBC55
- Стойка 4 — замена батарейного модуля APC RBC43 + перенос части нагрузки в стойку 6
- Стойка 3 — перенос двух коммутаторов в стойку 6 (снижение нагрузки с 82% до 65%)
После замены батарей и перебалансировки:
| Стойка | Нагрузка | Ёмкость | Время автономии |
|---|
| 1 (Биллинг) | 2 400 Вт (80%) | 95% | ~14 мин |
| 2 (BRAS) | 2 100 Вт (70%) | 95% | ~16 мин |
| 3 (Коммутация) | 1 400 Вт (64%) | 78% | ~12 мин |
| 4 (Медиа) | 1 500 Вт (68%) | 95% | ~13 мин |
| 5 (Мониторинг) | 1 200 Вт (40%) | 90% | ~22 мин |
| 6 (Резерв) | 1 200 Вт (80%) | 85% | ~10 мин |
Все стойки превысили минимальный порог в 10 минут автономии. Для стойки 6, которая оказалась на границе, мы запланировали апгрейд UPS до 2200VA в следующем квартале.
Тестирование и результаты внедрения
После развёртывания системы мы провели серию контролируемых тестов, имитируя отключение электричества.
Сценарий тестирования
В нерабочее время мы провели три теста:
Тест 1: Отключение питания одной стойки — отключили ввод на стойке 4. UPS перешёл на батарею за 0 мс (online-режим), NUT зафиксировал статус OB, Zabbix отправил алерт в Telegram через 7 секунд. После 5 минут на батарее мы восстановили питание — UPS вернулся в режим OL CHRG.
Тест 2: Имитация критического разряда — на тестовом UPS снизили порог LOWBATT до текущего заряда. Каскадный скрипт сработал: сервер получил сигнал и корректно завершил работу за 12 секунд.
Тест 3: Полное отключение серверной — отключили основной ввод. Все 6 UPS перешли на батарею. Каскадное отключение прошло штатно: медиа (0 сек) → BRAS (10 сек) → биллинг (40 сек) → коммутация (55 сек) → мониторинг (60 сек). Все серверы выключились корректно, данные не пострадали.
# Лог каскадного отключения (тест 3)
[2025-11-15 03:00:05] === КАСКАДНОЕ ОТКЛЮЧЕНИЕ НАЧАТО ===
[2025-11-15 03:00:05] UPS apc-billing: статус OB, заряд 92%
[2025-11-15 03:00:05] Фаза 1: Отключение медиа-сервера...
[2025-11-15 03:00:08] media-server: shutdown initiated
[2025-11-15 03:00:15] Фаза 2: Graceful shutdown BRAS...
[2025-11-15 03:00:18] bras-server: stopping sessions (1247 active)
[2025-11-15 03:00:35] bras-server: all sessions closed, shutdown
[2025-11-15 03:00:45] Фаза 3: Отключение биллинга...
[2025-11-15 03:00:48] billing-server: PostgreSQL checkpoint complete
[2025-11-15 03:00:52] billing-server: shutdown initiated
[2025-11-15 03:01:00] Фаза 4: Отключение мониторинг-сервера...
[2025-11-15 03:01:05] === ВСЕ СЕРВЕРЫ ОТКЛЮЧЕНЫ ===
Финальные результаты
Проект занял 5 рабочих дней: 2 дня на настройку мониторинга и автоматизации, 1 день на замену батарей и перебалансировку, 2 дня на тестирование.
| Метрика | До внедрения | После внедрения |
|---|
| Мониторинг UPS | Нет | Все 6 UPS в Zabbix |
| Автоматическое отключение | Нет (серверы работали до разряда) | Каскадное отключение за 60 сек |
| Время алерта | Узнавали постфактум | 7 сек (Telegram) |
| Мин. автономия | 4 мин (стойка 4) | 10 мин (все стойки) |
| Средняя нагрузка | 72% (перегрузка) | 64% (норма) |
| Состояние батарей | 3 из 6 изношены | Все в норме |
За 4 месяца после внедрения было 3 отключения электричества. Во всех случаях система отработала штатно: серверы корректно завершились, ни одного повреждения данных, среднее время восстановления — 8 минут после возврата питания (вместо 14 часов, как было раньше).
«Раньше отключение света — это паника. Теперь я получаю SMS, смотрю в Zabbix и спокойно жду. Серверы сами выключатся и сами включатся» — системный администратор КомЛинк.
Отдельно стоит отметить экономический эффект. Стоимость двух сгоревших серверов составила более 800 000 ₽ (замена RAID-контроллера Dell и двух NVMe SSD). Стоимость нашего проекта, включая замену батарей — 320 000 ₽. Окупаемость — менее одного инцидента. А учитывая, что за 4 месяца было 3 отключения электричества, система окупилась уже в первый месяц работы.
Мы также составили регламент обслуживания UPS для IT-отдела КомЛинк:
- Ежемесячно — проверка логов NUT, визуальный осмотр UPS
- Ежеквартально — запуск self-test на каждом UPS через NUT (
upscmd apc-billing test.battery.start) - Раз в полгода — полный тест автономии с контролируемым отключением питания стойки
- Ежегодно — замер ёмкости батарей, планирование замен