Zabbix 인프라 모니터링 구축 – 09. Dell 하드웨어: iDRAC 8 Redfish API 모니터링 (R730xd·스토리지)

2026.10.01

·

8편에서 HP iLO Redfish API를 구현했다면, 이번 편에서는 Dell iDRAC 8을 다룹니다. Redfish는 동일한 표준이지만 제조사마다 API 경로와 응답 구조가 다릅니다. iLO 코드를 그대로 쓰면 동작하지 않습니다.


iDRAC과 iLO의 차이

iDRAC(Integrated Dell Remote Access Controller)은 Dell 서버의 원격 관리 인터페이스로, HP의 iLO에 해당합니다. Redfish 표준을 따르지만 경로가 다릅니다:

항목HP iLO 4Dell iDRAC 8
시스템/redfish/v1/Systems/1/redfish/v1/Systems/System.Embedded.1
섀시 Thermal/redfish/v1/Chassis/1/Thermal/redfish/v1/Chassis/System.Embedded.1/Thermal
섀시 Power/redfish/v1/Chassis/1/Power/redfish/v1/Chassis/System.Embedded.1/Power
스토리지/redfish/v1/Systems/1/SmartStorage/redfish/v1/Systems/System.Embedded.1/Storage

가장 크게 다른 부분은 리소스 ID입니다. HP는 숫자(1)를, Dell은 System.Embedded.1 형태의 식별자를 사용합니다. 스토리지 경로명도 다릅니다(SmartStorage vs Storage).

Sponsored


SSL 처리

iDRAC 8도 구형 펌웨어에서 동일한 SSL 문제가 발생합니다. 8편에서 구현한 LegacySSLAdapter를 그대로 재사용합니다:

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)

def idrac_get(cfg, path):
    s = requests.Session()
    s.auth = (cfg["idrac_user"], cfg["idrac_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['idrac_host']}{path}", timeout=15)
    if r.status_code == 200:
        return r.json()
    return None

호스트 설정

HOSTS = {
    "pbs01": {
        "idrac_host":  "10.0.92.191",
        "idrac_user":  "관리자계정",
        "idrac_pass":  "비밀번호",
        "zabbix_host": "pbs-idc-01-idrac",
        "legacy_ssl":  True,
    },
}

시스템 헬스 수집

iDRAC의 시스템 엔드포인트는 iLO와 응답 구조가 유사합니다:

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

    proc = system.get("ProcessorSummary", {})
    sl("idrac.health.cpu", health_int(proc.get("Status")))
    if proc.get("Count") is not None:
        sl("idrac.cpu.count", proc["Count"])

    mem = system.get("MemorySummary", {})
    sl("idrac.health.memory", health_int(mem.get("Status")))
    if mem.get("TotalSystemMemoryGiB") is not None:
        sl("idrac.memory.total_gb", mem["TotalSystemMemoryGiB"])

iLO와 비교했을 때 키 이름만 ilo. → idrac.으로 바뀌고 로직은 동일합니다.


Thermal 수집

thermal = idrac_get(cfg, "/redfish/v1/Chassis/System.Embedded.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"idrac.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"idrac.fan.{k}.rpm", reading)
        sl(f"idrac.fan.{k}.health", health_int(st))

Dell PowerEdge R730xd의 주요 온도 센서:

센서명위치
Inlet Temp서버 흡입구
Exhaust Temp서버 배출구
CPU1 TempCPU 1번
CPU2 TempCPU 2번

팬은 FAN 1A, FAN 1B 형태로 이름이 붙으며, R730xd는 팬 모듈당 두 개의 팬(A/B)이 있습니다.


전력 수집

power = idrac_get(cfg, "/redfish/v1/Chassis/System.Embedded.1/Power")
if power:
    for pc in power.get("PowerControl", []):
        consumed = pc.get("PowerConsumedWatts")
        if consumed is not None:
            sl("idrac.power.consumed", consumed)
        cap = pc.get("PowerCapacityWatts")
        if cap is not None:
            sl("idrac.power.capacity", cap)
        break

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

iLO와 동일한 구조입니다. Dell 서버도 PSU 이중화 구성이 일반적이며, PSU 하나가 Critical이면 즉시 교체가 필요합니다.


스토리지 수집 — iLO와 가장 다른 부분

iDRAC의 스토리지 수집은 iLO와 구조가 다릅니다. iDRAC은 컨트롤러 → 드라이브로 계층적으로 탐색합니다:

storage = idrac_get(cfg, "/redfish/v1/Systems/System.Embedded.1/Storage")
if storage:
    for member in storage.get("Members", []):
        mpath = member.get("@odata.id", "")
        ctrl = idrac_get(cfg, mpath)
        if not ctrl:
            continue

        ctrl_id = key_norm(ctrl.get("Id", mpath.rstrip("/").split("/")[-1]))
        sl(f"idrac.storage.ctrl.{ctrl_id}.health", health_int(ctrl.get("Status")))

        for drive_ref in ctrl.get("Drives", []):
            dpath = drive_ref.get("@odata.id", "")
            drive = idrac_get(cfg, dpath)
            if not drive:
                continue
            slot = key_norm(drive.get("Id", dpath.rstrip("/").split("/")[-1]))
            sl(f"idrac.storage.pd.{slot}.health", health_int(drive.get("Status")))

탐색 흐름:

/Storage
  └── Members[]
        └── @odata.id → 컨트롤러 경로
              └── Drives[]
                    └── @odata.id → 드라이브 경로

컨트롤러 목록을 먼저 가져오고, 각 컨트롤러의 드라이브를 순서대로 탐색합니다. 컨트롤러와 드라이브 수만큼 API 호출이 발생하므로 서버당 수집 시간이 길어질 수 있습니다.

수집 키 예시:

idrac.storage.ctrl.boss_a1.health       → 0 (OK)
idrac.storage.pd.disk_0_0_0.health      → 0 (OK)
idrac.storage.pd.disk_0_1_0.health      → 0 (OK)

컨트롤러 ID와 드라이브 슬롯 ID는 key_norm()으로 정규화해 Zabbix 키에 사용합니다.


iLO vs iDRAC 수집 항목 비교

수집 항목HP iLO 4Dell iDRAC 8
시스템 헬스✅✅
전원 상태✅✅
CPU 요약 헬스✅✅
메모리 요약 헬스✅✅
온도 센서✅✅
팬 RPM/헬스✅✅
소비 전력✅✅
PSU별 헬스/출력✅✅
스토리지 컨트롤러 헬스✅ (SmartStorage)✅ (Storage)
물리 드라이브 헬스✅ (Smart Array만)✅ (RAID 컨트롤러 연결)

수집 항목은 거의 동일하지만 API 경로와 탐색 방식이 다릅니다. 코드를 재사용하려면 경로만 교체 가능하도록 설계하는 것이 좋습니다.


crontab 등록

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

마치며

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

  • Redfish 표준이지만 iLO와 iDRAC은 API 경로가 다름 — 혼용 불가
  • 핵심 차이: 리소스 ID(1 vs System.Embedded.1), 스토리지 경로
  • iDRAC 스토리지는 컨트롤러 → 드라이브 계층 탐색 구조
  • key_norm()으로 센서/드라이브 ID를 Zabbix 키로 정규화

다음 편에서는 iLO와 iDRAC 모니터링을 위한 Zabbix 호스트, 아이템, 트리거를 Zabbix API로 자동 생성하는 방법을 다룹니다. 수십 개의 아이템을 UI에서 수동으로 만드는 대신 스크립트 한 번으로 일괄 등록하는 구조를 설명합니다.


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분 체크