BMC exporter monitoring¶
Purpose¶
kubernetes/apps/observability/bmc-exporter runs idrac_exporter against a fleet of Supermicro
BMCs over Redfish, plus a second, single-target deployment for a separate workstation BMC.
Together they feed two Grafana dashboards and the PrometheusRule alerts in this directory.
Naming and metric prefix¶
The HelmRelease is named bmc-exporter for what it does here, but the chart, image and metric
prefix stay upstream's idrac. The exporter is vendor-neutral Redfish, explicitly tested against
Supermicro, and keeping the default idrac_ prefix means upstream's dashboards and docs still
apply to this deployment. The prefix is settable, but changing it later would orphan every stored
series, so it stays as-is on purpose rather than by omission.
What the boards actually return¶
Measured against the live fleet rather than assumed from the Redfish schema:
- temperatures, fan RPM and health, voltages, PSU health/watts/input voltage, per-DIMM health, per-CPU health, BMC manager health, system power state
- no storage metrics on either board generation. Supermicro doesn't populate that part of the Redfish tree, so drive health stays with smartctl-exporter
- a powered-off host drops all of its sensor series and reports only
idrac_system_power_on 0, which is what the alert rules key off
Why the workstation gets its own deployment¶
The workstation is a desk machine, powered off most of the time, so it needs to be exempt from
BmcHostPoweredOff while staying covered by every other rule. Excluding one host from one alert
needs something in PromQL to match on, and none of the obvious options work:
instanceis the target address, and this BMC has no DNS record, so matching on it would put a LAN address in this public repository- the
modellabel doesn't discriminate: this board and the storage node both report the generic "Super Server" - the ScrapeConfig relabelings could synthesise a label, but only by matching the address, which is the same leak
Giving it its own deployment gives it its own job label instead, a plain string that discloses
nothing. The rules then use job=~"bmc-exporter.*" for hardware health and job="bmc-exporter"
exactly for power state, so the exact match excludes the workstation. The cost is one more 64Mi
pod. If an internal DNS record is ever created for this BMC, the tidier form is to fold it back
into the main config and select on the hostname instead.
BmcHostPoweredOff also gates on the host having been on within the last 24h, so an unexpected
power-off still pages within 15m and keeps paging for a day, then the alert self-silences once the
host reads as deliberately parked. That is what stops a retired sled or a cold spare from paging
forever, without keeping a hostname list in a public repository, which would only drift as boxes
get repurposed.
Scrape timing¶
Targets come from the exporter's own /discover endpoint, which lists exactly the hosts in the
mounted config, so adding a BMC to the ExternalSecret is the only change needed to add a scrape
target.
The scrape interval is 60s with a 55s timeout, not the usual 30s, because a warm scrape measured
about 7.5s on the H13 boards and about 13s on the X12, and a cold scrape right after a BMC restart
measured about 23s on the X12. The exporter's own timeout: 45 config setting sits below that 55s
ScrapeConfig timeout and above the exporter's 10s default, which was aborting mid-collection on
this hardware.
PSU power reading vs system power draw¶
The fleet dashboard's power panels sum idrac_power_control_consumed_watts, the system-level
reading, rather than idrac_power_supply_output_watts per PSU. On the H13 boards the two disagree
by an order of magnitude: a node drawing about 95W at the system level reports around 450W per PSU.
The PSU figure is shown on its own panel, labelled as reported, and isn't meant to be read as
consumption.
Temperature thresholds¶
Thresholds are split by sensor class, taken from max by (name) across the whole running fleet
rather than one sampled host, because a single fleet-wide number can't fit the spread:
| Sensor class | Peak measured |
|---|---|
| CPU Temp | 77C |
| AOC_NIC1 | 68C |
| MLP_NIC | 66C |
| GPU0 | 63C |
| M2_SSD | 53C |
| Everything else | 49C or below |
A single 80C threshold for every sensor would sit only 3C off a normal CPU reading while letting a NIC reach 79C unnoticed. So CPU packages get their own band (alerting from 90C, critical above 95C), and everything else gets a wider one (alerting from 80C, critical above 90C), which leaves about 12C of headroom over the hottest non-CPU sensor instead of 3C.
The CPU band's regular expression is CPU[0-9]* Temp rather than a bare CPU prefix, so it
matches a second socket (CPU1 Temp) without also catching the much cooler CPU_VRM0 Temp or
SOC_VRM Temp rails.
SEL event log¶
Supermicro SEL entries surface as idrac_events_log_entry, bounded to severity: warning and
maxage: 7d in the exporter config, since message is a label and an unfiltered log would be a
cardinality risk. The BmcEventLogWarning rule's aggregation choice and two exclusion codes have
their own history in KB-037.