No description
  • Go 86.2%
  • Shell 10.4%
  • HTML 3.4%
Find a file
2026-07-30 09:19:39 +03:00
cmd fix: Устранение некоторых недочетов по блокировкам и производительности 2026-07-30 08:55:00 +03:00
docs fix: Устранение некоторых недочетов по блокировкам и производительности 2026-07-30 08:55:00 +03:00
internal fix: Устранение некоторых недочетов по блокировкам и производительности 2026-07-30 08:55:00 +03:00
packaging fix: Устранение некоторых недочетов по блокировкам и производительности 2026-07-30 08:55:00 +03:00
.gitignore fix: Обновлеение команд получения данных 2026-07-29 14:51:39 +03:00
.woodpecker.yml fix: CI 2026-07-29 15:33:22 +03:00
bench_ipmi.sh fix: Обновлеение команд получения данных 2026-07-29 14:51:39 +03:00
benchmark_test.go first commit 2026-07-29 13:57:55 +03:00
capture_samples.sh fix: Обновлеение команд получения данных 2026-07-29 14:51:39 +03:00
check.sh first commit 2026-07-29 13:57:55 +03:00
config.yaml.example fix: Устранение некоторых недочетов по блокировкам и производительности 2026-07-30 08:55:00 +03:00
go.mod first commit 2026-07-29 13:57:55 +03:00
go.sum first commit 2026-07-29 13:57:55 +03:00
leak_test.go first commit 2026-07-29 13:57:55 +03:00
LICENSE first commit 2026-07-29 13:57:55 +03:00
README.md fix: README.md 2026-07-30 09:19:39 +03:00

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:

  1. Устанавливает hold_pwm (100%) на hold_duration (5 с) — защита от перегрева
  2. Переключает вентиляторы в автоматический режим
  3. Останавливает 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

Как импортировать:

  1. Configuration → Templates → Import
  2. Выбрать packaging/zbx_template_iceberg.xml
  3. Назначить шаблону хост с iceberg
  4. Шаблон использует 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 (0100%)
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)

При пуше тега:

  1. Сборка linux/amd64 + linux/arm64
  2. Упаковка deb + rpm
  3. Публикация релиза в 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