- Go 86.2%
- Shell 10.4%
- HTML 3.4%
| cmd | ||
| docs | ||
| internal | ||
| packaging | ||
| .gitignore | ||
| .woodpecker.yml | ||
| bench_ipmi.sh | ||
| benchmark_test.go | ||
| capture_samples.sh | ||
| check.sh | ||
| config.yaml.example | ||
| go.mod | ||
| go.sum | ||
| leak_test.go | ||
| LICENSE | ||
| README.md | ||
iceberg
iceberg — демон для автоматического управления вентиляторами сервера через REST API OpenBMC (Redfish).
Проблема
Во многих серверных платформах встроенный алгоритм управления оборотами вентиляторов (gouvernant) настраивается через BIOS/BMC, но:
- Предустановленная кривая накручивает вентиляторы при малейшем нагреве одного датчика
- В заводских настройках нельзя гибко указать пороги срабатывания и hysteresis
- Нельзя задать вентиляторам минимальный безопасный PWM, чтобы сбалансировать шум и охлаждение
- Невозможно адаптировать поведение под конкретные задачи (рендер-ферма, LLM и AI, тихий офисный сервер)
iceberg решает это, подменяя управление вентиляторами через Redfish API, и реализует собственную логику с гистерезисом и настраиваемой кривой PWM.
Как это работает
каждые 1 с при изменении
┌──────────┐ ──────────────► ┌────────────┐ ─────────────► ┌───────────┐
│ sensor │ │ control │ │ openbmc │
│ (GPU/CPU)│ │ (PWM calc) │ │ (PATCH) │
└──────────┘ └────────────┘ └───────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────┐
│ monitor (:3000) │
│ /metrics (Prometheus) / (HTML+SSE) │
└──────────────────────────────────────────────┘
1. Сбор температур
iceberg поддерживает два backend'а для сбора температур, которые работают одновременно с разной частотой:
| Сенсор | Backend | Частота |
|---|---|---|
| GPU | nvidia-smi |
Каждый tick (1 с) |
| CPU, PCH | sensors -j (lm-sensors) |
Каждый tick (1 с, ~15 ms) |
| DIMM | ipmitool sensor list (кэш) |
Каждые 30 с |
- lm-sensors — основной backend для CPU и чипсета (быстрый, ~15 ms)
- IPMI — для DIMM (медленный, ~9 с, поэтому опрашивается раз в 30 с без перекрытия)
- Если lm-sensors не установлен — CPU и PCH читаются из IPMI, но на той же медленной частоте
2. Расчёт PWM
maxTemp ──► Hysteresis check ──► Curve interpolation ──► max_pwm clamp ──► (mode, pwm)
- Автоматический режим:
maxTemp < auto_below - hysteresis_drop - Ручной режим:
maxTemp >= manual_on - Hysteresis: чтобы не дёргать вентиляторами на каждом градусе
- Кривая: линейная интерполяция между опорными точками
temp → pwm - Ограничение: PWM не выше
max_pwm
3. Применение к BMC
При каждом изменении режима или PWM iceberg отправляет PUT/PATCH-запрос на OpenBMC (в зависимости от настроек):
{"mode": "manual", "constPWM": 70}
Все endpoint'ы, методы, тела запросов и заголовки полностью настраиваются через шаблоны text/template. Это позволяет адаптироваться под любой Redfish-совместимый BMC и даже под нестандартные API.
4. Мониторинг
Встроенный HTTP-сервер на порту :3000:
/metrics— метрики Prometheus (температуры, PWM, ошибки)/— HTML-панель с live-статусом через SSE/events— SSE-поток для real-time обновлений
5. Graceful shutdown
При получении SIGTERM/SIGINT:
- Устанавливает
hold_pwm(100%) наhold_duration(5 с) — защита от перегрева - Переключает вентиляторы в автоматический режим
- Останавливает HTTP-сервер
Требования
Аппаратные
- Сервер с OpenBMC (или совместимым Redfish-интерфейсом)
- GPU NVIDIA (опционально, для контроля температуры GPU)
Программные
| Утилита | Назначение | Debian/Ubuntu | RHEL/Fedora |
|---|---|---|---|
nvidia-smi |
Температура GPU | nvidia-utils |
nvidia-driver |
sensors |
Температура CPU/PCH | lm-sensors |
lm_sensors |
ipmitool |
Температура DIMM | ipmitool |
ipmitool |
Все зависимости — опциональны (suggests/recommends). При отсутствии утилиты соответствующий сенсор пропускается (лог на уровне warning, температура считается 0 °C).
Установка
deb (Debian/Ubuntu)
sudo dpkg -i iceberg_*.deb
# или
sudo apt install ./iceberg_*.deb
rpm (RHEL/Fedora/AlmaLinux/Rocky)
sudo rpm -ivh iceberg-*.rpm
# или
sudo dnf install ./iceberg-*.rpm
Вручную
go install git.ymnuktech.ru/ymnuk/iceberg/cmd/iceberg@latest
Быстрый старт
# Скопировать пример конфига
cp config.yaml.example config.yaml
# Отредактировать: указать URL BMC, логин, пароль
vim config.yaml
# Запуск в режиме мониторинга (без отправки PATCH)
./iceberg --config config.yaml --dry-run
# Проверить, что данные приходят
curl http://localhost:3000/metrics
# Если всё корректно — переключить в боевой режим
./iceberg --config config.yaml
Dry-run режим
Флаг --dry-run (или dry_run: true в YAML) отключает отправку PATCH-запросов к BMC:
- Температуры собираются и отображаются в веб-интерфейсе
- Алгоритм управления считает PWM
- Graceful shutdown не выполняется
- PATCH на BMC не уходит
Используется для отладки кривой, hysteresis и проверки соединения без риска для оборудования.
Конфигурация
iceberg использует go-simple-args: приоритет настроек: CLI → Env → YAML → Defaults.
Полный пример — в config.yaml.example.
Ключевые секции:
| Раздел | Описание |
|---|---|
openbmc |
URL, учётные данные, шаблоны endpoint'ов и тел запросов |
sensors |
Список активных сенсоров: gpu, cpu, dimm, pch |
control |
Пороги, hysteresis, кривая PWM, min_pwm, pwm_mode |
shutdown |
PWM на время hold при остановке |
sensor |
Backend сбора температур и интервал IPMI |
dry_run |
Режим мониторинга без PATCH |
poll_interval |
Интервал основного цикла (сек) |
Как работает управление
Управление решает: включить ручной режим (мы задаём PWM) или отдать управление обратно BMC (auto).
Вход в ручной режим — когда температура поднимается выше manual_on (50°C).
Выход из ручного режима — когда температура падает ниже auto_below - hysteresis_drop (48 − 2 = 46°C).
Зазор между manual_on и auto_below - drop нужен, чтобы не дёргаться туда-сюда при маленьких колебаниях.
Пример на пальцах:
Температура по секундам: 48, 49, 50, 51, 52, 49, 48, 47, 46, 45
Настройки: auto_below=48, manual_on=50, drop=2
сек 1: 48°C → auto (ниже manual_on, режим ещё auto)
сек 2: 49°C → auto (всё ещё ниже manual_on)
сек 3: 50°C → manual! (достигли manual_on — включаем ручной режим, PWM=70)
сек 4: 51°C → manual (держим ручной)
сек 5: 52°C → manual (держим)
сек 6: 49°C → manual (всё ещё manual — не ушли в auto, потому что 49 >= 46)
сек 7: 48°C → manual (48 >= 46, держим)
сек 8: 47°C → manual (47 >= 46, держим)
сек 9: 46°C → manual (46 >= 46, держим — на границе)
сек 10: 45°C → auto! (45 < 46, ушли в auto, PWM сброшен)
Если бы не было hysteresis_drop:
auto_below=48, manual_on=50, drop=0 (выход при < 48)
сек 6: 49°C → manual (49 >= 48, держим)
сек 7: 48°C → auto! (48 < 48 — нет, это не сработает)
На самом деле если drop=0, то выход будет при auto_below - 0 = 48, то есть при строго меньше 48:
сек 6: 49°C → manual
сек 7: 48°C → manual (потому что 48 >= 48)
сек 8: 47°C → auto! (47 < 48 — ушли)
Без drop выход происходит при 47°C, с drop=2 — при 45°C. Чем больше drop, тем шире петля гистерезиса, тем реже переключения между manual и auto.
Пример кривой
control:
auto_below: 48
manual_on: 50
min_pwm: 20
max_pwm: 100
hysteresis_drop: 2
pwm_mode: follow # follow — идёт за кривой в обе стороны
# peak_hold — только растёт, сброс при переходе в auto
curve:
- temp: 50
pwm: 50
- temp: 60
pwm: 70
- temp: 75
pwm: 85
- temp: 85
pwm: 100
При температуре ≤ 48 °C — вентиляторы в авторежиме (BMC управляет сам). При 50 °C — ручной режим, PWM=50. Между 50 и 60 — линейная интерполяция. При ≥ 85 °C — PWM=100.
pwm_mode:
| Режим | Поведение |
|---|---|
follow (default) |
PWM следует за кривой в обе стороны — при снижении температуры PWM падает |
peak_hold |
PWM в ручном режиме только растёт, не падает. Сброс до значения кривой происходит только при переходе в auto (по гистерезису) и повторном входе в ручной режим |
Шаблоны запросов
Все endpoint'ы и тела запросов используют text/template. Доступные переменные:
| Переменная | Описание |
|---|---|
{{.URL}} |
Базовый URL BMC |
{{.User}} |
Имя пользователя |
{{.Password}} |
Пароль |
{{.ChassisID}} |
Идентификатор шасси |
{{.Token}} |
Текущий токен авторизации |
{{.Mode}} |
Режим: manual или auto |
{{.PWM}} |
Целевой PWM (только в body_manual) |
Это позволяет интегрироваться с любым API, а не только со стандартным Redfish.
Мониторинг
Prometheus
iceberg экспортирует метрики в формате Prometheus на /metrics:
# HELP iceberg_temperature_celsius Current sensor temperature in Celsius
# TYPE iceberg_temperature_celsius gauge
iceberg_temperature_celsius{type="gpu"} 65
iceberg_temperature_celsius{type="coretemp-isa-0000"} 52
iceberg_temperature_celsius{type="pch"} 38
iceberg_temperature_celsius{type="DIMM A1 CPU1"} 38
# HELP iceberg_max_temperature_celsius Current maximum temperature across all sensors
# TYPE iceberg_max_temperature_celsius gauge
iceberg_max_temperature_celsius 65
# HELP iceberg_fan_pwm Current fan PWM value
# TYPE iceberg_fan_pwm gauge
iceberg_fan_pwm 70
# HELP iceberg_fan_mode Current fan mode (1=manual, 0=auto)
# TYPE iceberg_fan_mode gauge
iceberg_fan_mode{state="manual"} 1
iceberg_fan_mode{state="auto"} 0
# HELP iceberg_errors_total Total number of errors by type
# TYPE iceberg_errors_total counter
iceberg_errors_total{error_type="api"} 0
iceberg_errors_total{error_type="sensor"} 0
Prometheus + Grafana
scrape_configs:
- job_name: 'iceberg'
static_configs:
- targets: ['server-ip:3000']
Zabbix (без Prometheus)
Начиная с Zabbix 5.0 можно забирать Prometheus-метрики напрямую, без установки Prometheus.
В репозитории готов шаблон для импорта:
📄 packaging/zbx_template_iceberg.xml
Как импортировать:
- Configuration → Templates → Import
- Выбрать
packaging/zbx_template_iceberg.xml - Назначить шаблону хост с iceberg
- Шаблон использует master item (HTTP-запрос раз в 30 с на
http://{HOST.CONN}:3000/metrics) и зависимые элементы данных с парсингом Prometheus-формата
Что входит в шаблон:
| Элемент | Описание | Триггер |
|---|---|---|
iceberg.temp.gpu |
Температура GPU | >85°C — HIGH |
iceberg.temp.cpu |
Максимальная температура CPU | — |
iceberg.temp.max |
Максимум по всем сенсорам | >85°C — HIGH, >95°C — DISASTER |
iceberg.fan.pwm |
Текущий PWM (0–100%) | — |
iceberg.fan.mode |
Режим: auto/manual | — |
iceberg.errors.api |
Ошибки OpenBMC (счётчик) | при росте — WARNING |
iceberg.errors.sensor |
Ошибки сенсоров (счётчик) | при росте — WARNING |
Сборка из исходников
git clone https://git.ymnuktech.ru/ymnuk/iceberg
cd iceberg
go build -o iceberg ./cmd/iceberg
# или
./check.sh # полная проверка: линтер, тесты, бенчмарки, сборка
CI (Woodpecker)
При пуше тега:
- Сборка
linux/amd64+linux/arm64 - Упаковка deb + rpm
- Публикация релиза в Gitea
Проверка соединения с BMC
iceberg-check --openbmc-url https://192.168.1.100 --openbmc-user root --openbmc-password secret
Утилита выполняет логин, GET-запрос на проверочный endpoint и выводит JSON-результат с временем выполнения.
Логи
Логи пишутся в JSONL (по умолчанию stdout → journald). Для записи в файл укажите log.file: /var/log/iceberg.log — тогда потребуется настроить ротацию:
# /etc/logrotate.d/iceberg (устанавливается из deb/rpm пакета)
/var/log/iceberg.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
}
План развития
Текущие задачи и приоритеты описаны в docs/ROADMAP.md.
Лицензия
MIT