Zabbix 인프라 모니터링 구축 – 08. HP 하드웨어: iLO 4 Redfish API로 서버 헬스 수집 (온도·팬·PSU)

2026.09.30

·

Proxmox 모니터링이 OS·VM 수준의 지표를 다룬다면, iLO 모니터링은 서버 하드웨어 자체의 상태를 다룹니다. OS가 정상이어도 팬이 멈추거나 PSU가 고장나면 서버는 언제든 다운될 수 있습니다. 하드웨어 헬스 모니터링이 별도로 필요한 이유입니다.


HP iLO와 Redfish API

iLO(Integrated Lights-Out)는 HP 서버의 원격 관리 인터페이스입니다. 서버 본체와 독립된 전용 네트워크 포트와 프로세서를 가지고 있어, OS가 다운된 상태에서도 서버 상태를 모니터링하고 제어할 수 있습니다.

Redfish는 DMTF 표준 REST API로, iLO 4(펌웨어 2.x 이상)부터 지원합니다. JSON 형식으로 하드웨어 상태를 조회할 수 있어 스크립트 통합이 쉽습니다.

Sponsored

주요 Redfish 엔드포인트:

경로수집 내용
/redfish/v1/Systems/1전체 시스템 헬스, 전원 상태, CPU/메모리 요약
/redfish/v1/Chassis/1/Thermal온도 센서, 팬 RPM 및 상태
/redfish/v1/Chassis/1/Power소비 전력, 전력 용량, PSU별 상태
/redfish/v1/Systems/1/SmartStorage스마트 스토리지 컨트롤러 및 드라이브

DH_KEY_TOO_SMALL 오류와 LegacySSLAdapter

iLO 4 구형 펌웨어에서 Python requests로 HTTPS 요청을 보내면 다음 오류가 발생합니다:

SSLError: [SSL: DH_KEY_TOO_SMALL] dh key too small

이는 iLO가 사용하는 Diffie-Hellman 키 크기가 현대 SSL 라이브러리의 최소 기준(1024비트)에 미치지 못하기 때문입니다. 펌웨어 업그레이드가 불가능한 환경에서는 SSL 컨텍스트의 보안 수준을 낮춰 우회합니다:

import ssl
from requests.adapters import HTTPAdapter

class LegacySSLAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        ctx = ssl.create_default_context()
        ctx.set_ciphers("DEFAULT:@SECLEVEL=1")  # 보안 수준 완화
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE
        kwargs["ssl_context"] = ctx
        super().init_poolmanager(*args, **kwargs)

요청 시 이 어댑터를 https://에 마운트합니다:

def idrac_get(cfg, path):
    s = requests.Session()
    s.auth = (cfg["ilo_user"], cfg["ilo_pass"])
    s.verify = False
    s.headers.update({"Accept": "application/json"})

    if cfg.get("legacy_ssl"):
        s.mount("https://", LegacySSLAdapter())

    r = s.get(f"https://{cfg['ilo_host']}{path}", timeout=15)
    if r.status_code == 200:
        return r.json()
    return None

legacy_ssl 플래그를 호스트 설정에 넣어두면 펌웨어가 최신인 서버와 구형 서버를 같은 코드로 처리할 수 있습니다.


다중 호스트 설정

여러 서버를 하나의 스크립트로 관리합니다:

HOSTS = {
    "idc02": {
        "ilo_host":    "10.0.92.112",
        "ilo_user":    "관리자계정",
        "ilo_pass":    "비밀번호",
        "zabbix_host": "proxmox-idc-02-ilo",
        "legacy_ssl":  True,
    },
    "idc03": {
        "ilo_host":    "10.0.92.113",
        "ilo_user":    "관리자계정",
        "ilo_pass":    "비밀번호",
        "zabbix_host": "proxmox-idc-03-ilo",
    },
    "nas01": {
        "ilo_host":    "10.0.92.161",
        "ilo_user":    "관리자계정",
        "ilo_pass":    "비밀번호",
        "zabbix_host": "truenas-prd-01-ilo",
        "legacy_ssl":  True,
    },
}

실행 시 --site idc02 또는 --site all로 대상을 선택합니다.


Health 값 정규화

Redfish는 헬스 상태를 문자열("OK", "Warning", "Critical")로 반환합니다. Zabbix 트리거에서 비교하기 쉽도록 정수로 변환합니다:

HEALTH_MAP = {"OK": 0, "Warning": 1, "Critical": 2, "Unknown": 3}

def health_int(obj):
    if obj is None:
        return -1
    if isinstance(obj, dict):
        h = obj.get("Health") or obj.get("HealthRollup")
        if h is None:
            return -1
        obj = h
    return HEALTH_MAP.get(str(obj), 3)
문자열정수트리거 기준
OK0–
Warning1Average 알림
Critical2High 알림
Unknown3Warning 알림
N/A (없음)-1트리거 제외

시스템 헬스 수집

system = ilo_get(cfg, "/redfish/v1/Systems/1")
if system:
    sl("ilo.health.system", health_int(system.get("Status", {}).get("Health")))
    sl("ilo.power.state",   1 if system.get("PowerState") == "On" else 0)

    proc = system.get("ProcessorSummary", {})
    sl("ilo.health.cpu",   health_int(proc.get("Status")))
    sl("ilo.cpu.count",    proc.get("Count", 0))

    mem = system.get("MemorySummary", {})
    sl("ilo.health.memory",    health_int(mem.get("Status")))
    sl("ilo.memory.total_gb",  mem.get("TotalSystemMemoryGiB", 0))

HealthRollup은 하위 컴포넌트 중 가장 나쁜 상태를 요약합니다. Health가 OK여도 HealthRollup이 Warning이라면 어딘가 이상이 있다는 신호입니다.


온도 및 팬 수집

thermal = ilo_get(cfg, "/redfish/v1/Chassis/1/Thermal")
if thermal:
    for temp in thermal.get("Temperatures", []):
        st = temp.get("Status", {})
        if st.get("State") not in ("Enabled", "Absent"):
            continue
        reading = temp.get("ReadingCelsius")
        if reading is None:
            continue
        k = key_norm(temp.get("Name", "unknown"))
        sl(f"ilo.temp.{k}", reading)

    for fan in thermal.get("Fans", []):
        st = fan.get("Status", {})
        if st.get("State") != "Enabled":
            continue
        name = fan.get("FanName") or fan.get("Name", "")
        k = key_norm(name)
        reading = fan.get("ReadingRPM") or fan.get("Reading")
        if reading is not None:
            sl(f"ilo.fan.{k}.rpm", reading)
        sl(f"ilo.fan.{k}.health", health_int(st))

센서 이름을 Zabbix 키에 사용할 수 있도록 정규화합니다:

import re

def key_norm(name):
    # "Inlet Ambient" → "inlet_ambient"
    return re.sub(r"[^a-z0-9]+", "_", name.lower()).strip("_")

HP ProLiant 서버의 주요 온도 센서:

센서명의미
Inlet Ambient서버 흡입구 온도
CPU 1CPU 1번 온도
P/S 1 Zone전원부 온도
System Board메인보드 온도

전력 및 PSU 수집

power = ilo_get(cfg, "/redfish/v1/Chassis/1/Power")
if power:
    for pc in power.get("PowerControl", []):
        consumed = pc.get("PowerConsumedWatts")
        if consumed is not None:
            sl("ilo.power.consumed", consumed)
        cap = pc.get("PowerCapacityWatts")
        if cap is not None:
            sl("ilo.power.capacity", cap)
        break  # 첫 번째 PowerControl만 사용

    for i, psu in enumerate(power.get("PowerSupplies", []), 1):
        st = psu.get("Status", {})
        if st.get("State") == "Absent":
            continue
        sl(f"ilo.power.ps{i}.health",   health_int(st))
        out = psu.get("PowerOutputWatts") or psu.get("LastPowerOutputWatts")
        if out is not None:
            sl(f"ilo.power.ps{i}.output", out)
        volt = psu.get("LineInputVoltage")
        if volt is not None:
            sl(f"ilo.power.ps{i}.voltage", volt)

PSU가 Absent 상태인 경우 슬롯이 비어 있는 것이므로 건너뜁니다. PSU가 있지만 Critical이라면 즉시 교체가 필요합니다.


iLO가 볼 수 없는 디스크

iLO에서 물리 드라이브 상태를 확인할 수 있는 것은 HP Smart Array(P-Series) 컨트롤러에 연결된 드라이브에 한합니다. LSI HBA(IT 모드)나 다른 제조사의 컨트롤러에 연결된 드라이브는 iLO가 인식하지 못합니다.

7편에서 다룬 HBA 교체 오탐 사례가 바로 이 한계에서 비롯된 것입니다:

P440ar 연결 드라이브 → iLO/Smart Storage API로 조회 가능
LSI 9217 연결 드라이브 → iLO 조회 불가 → Proxmox API로 수집

서버에 HBA 카드가 설치되어 있다면 Proxmox API의 disks/list + disks/smart를 통해 수집하고, iLO의 Smart Storage 수집에서는 해당 드라이브를 기대하지 않아야 합니다.


crontab 등록

# HP iLO 수집 (5분)
*/5 * * * * /usr/bin/python3 /data/zabbix/scripts/ilo_collector.py --site all >> /var/log/zabbix-collector.log 2>&1

하드웨어 헬스는 5분 주기로 수집합니다. 1분 주기는 iLO에 불필요한 부하를 줄 수 있고, 온도·팬·전력 이상은 보통 수분에 걸쳐 나타나기 때문에 5분으로 충분합니다.


마치며

이번 편에서 다룬 핵심 포인트입니다:

  • iLO Redfish API는 OS 독립적으로 하드웨어 상태 수집 가능
  • 구형 펌웨어의 DH_KEY_TOO_SMALL → LegacySSLAdapter로 해결
  • Health 문자열을 정수로 변환해 Zabbix 트리거에서 쉽게 비교
  • 센서명은 key_norm()으로 정규화해 Zabbix 키로 사용
  • iLO는 HP Smart Array 컨트롤러 드라이브만 인식 — HBA 드라이브는 Proxmox API로 별도 수집

다음 편에서는 Dell 서버의 iDRAC 8 Redfish API를 다룹니다. HP iLO와 동일한 Redfish 표준이지만 API 경로와 응답 구조가 다른 부분을 비교하며 설명합니다.


MORE POSTS

다른 글 보기

guniq 인사이트 썸네일 — 중소기업 OpenLDAP 통합 인증 구축 – 00. 왜 OpenLDAP인가: 비용과 자유, 그리고 표준의 중요성
테크 랩

중소기업 OpenLDAP 통합 인증 구축 – 00. 왜 OpenLDAP인가: 비용과 자유, 그리고 표준의 중요성

MS Active Directory 대신 OpenLDAP을 선택한 이유, 오픈소스 디렉토리 서버의 장단점, 그리고 연동 유연성을 결정짓는 LDAP 표준 준수의 중요성을 실제 운영 경험 기반으로 정리합니다.
2026.10.12
guniq 인사이트 썸네일 — Zabbix 인프라 모니터링 구축 – 15. 실전 이슈: 운영 중 마주친 오탐·누락·설정 오류 총정리 (트러블슈팅)
테크 랩

Zabbix 인프라 모니터링 구축 – 15. 실전 이슈: 운영 중 마주친 오탐·누락·설정 오류 총정리 (트러블슈팅)

Zabbix 모니터링 구축과 운영 중 실제로 마주친 문제들을 총정리합니다. Media Type 기본 비활성화, 트리거 표현식 포맷 변경, stale value 오탐, crontab 초기화, netstat 타입 오류 등 삽질의 기록과 해결책을 공유합니다.
2026.10.09
guniq 인사이트 썸네일 — Zabbix 인프라 모니터링 구축 – 14. 환경 분리: DEV·PRD를 하나의 Zabbix로 운영하기 (호스트그룹·권한)
테크 랩

Zabbix 인프라 모니터링 구축 – 14. 환경 분리: DEV·PRD를 하나의 Zabbix로 운영하기 (호스트그룹·권한)

개발과 운영 환경을 하나의 Zabbix 서버로 운영하면서 호스트 그룹, 사용자 권한, Slack 알림 채널을 분리하는 방법을 다룹니다. API 토큰, 스크립트, 로그까지 환경별 분리 전략 전체를 설명합니다.
2026.10.08

프로젝트 문의 환영합니다

기획부터 개발, 운영까지 함께 만들어 드립니다.

무료 3분 자가진단

우리 회사, 자체 클라우드가 답일까?

AWS vs 자체 인프라 · 11개 항목 3분 체크