폐쇄망 환경에서 MinIO AIStor를 타깃으로 삼아 빠르게 PoC 형태의 Incident RCA Agent를 구축하기 위해 필요한 준비 사항과 구체적인 실행 단계를 정리한 가이드입니다.
Vector DB에 적재할 MinIO AIStor 전용 도메인 지식입니다. 노이즈를 줄이기 위해 공식 가이드와 과거 장애 이력 위주로 패키징합니다.
mc admin 명령어 가이드, 드라이브 I/O 및 분산 락(distributed lock/dsync) 동작 원리 문서minio_node_drive_*, minio_s3_requests_*, Goroutine/Heap 관련 지표)Agent에 입력할 가상의 Incident Context를 단일 JSON이나 마크다운 번들 형태로 준비합니다.
minio_node_drive_total_duration_microseconds 등)##, ###) 또는 에러 코드 단위 구조화 청킹을 적용합니다.category: metric_def, error_code, sop, component: minio-aistor)를 명시해 Hybrid Search(키워드+시맨틱) 또는 메타데이터 필터링이 가능하도록 구성합니다.수동 전송(또는 이후 Collector 자동화)을 고려해 표준 입력 스키마를 정의합니다.
{
"incident_id": "INC-202610-001",
"occurred_at": "2026-10-15T14:30:00Z",
"service": "minio-aistor",
"symptom": "Client 503 Slow Down / PutObject Timeout",
"metrics": {
"promql_snapshots": [
{"name": "minio_node_drive_total_duration_microseconds", "node": "data-node-04", "value": "spiked_5000ms"},
{"name": "go_goroutines", "value": "12000"}
]
},
"logs": [
"[ERROR] drive /mnt/drive4: disk latency exceeds threshold (slow down)",
"[WARN] context deadline exceeded on peer data-node-04:9000"
]
}
단일 프롬프트 호출 대신, 단계별 태스크를 명확히 분리하여 환각(Hallucination)을 제어합니다.
[Incident Payload]
│
▼
[Node 1: Symptom Normalization] ──> 증상 요약 및 핵심 엔티티(노드, 디스크, API 등) 추출
│
▼
[Node 2: Knowledge Retrieval] ──> 엔티티 기반 Vector DB/SOP 검색 (k=3~5)
│
▼
[Node 3: Hypothesis Generator] ──> 증상+지식 기반 잠재 원인 가설 2~3개 도출
│ (예: Disk Slow vs Network Partition vs 대량 Listing I/O)
▼
[Node 4: Metric/Log Cross-Check]─> 입력된 로그/메트릭 데이터로 각 가설 검증
│
▼
[Node 5: RCA & Action Plan] ──> 최종 원인 확정, 확신도(Confidence), 조치 Runbook 출력
결과가 운영자 관점에서 즉각 활용될 수 있도록 정형화된 출력 양식을 시스템 프롬프트에 지정합니다.
/mnt/drive4의 I/O Hang으로 인한 분산 락 경합 발생)mc admin drive offline ... 또는 해당 드라이브 격리)우선 구현 검증을 위해 가장 빈번하고 패턴이 명확한 시나리오 1개로 엔드투엔드 파이프라인을 검증하는 것을 권장합니다.
disk slow 로그===
시간이 촉박하고 폐쇄망 사내 시스템에 빠르게 지식과 테스트 데이터를 넣어야 하는 상황에 맞춰, 1) 벤더/SOP 문서의 Markdown 변환 방안과 2) 사내 환경 맞춤형 가공(Synthetic) 로그/메트릭 데이터셋 생성 가이드를 실무 중심으로 정리해 드립니다.
Vector DB나 사내 Agent 플랫폼에 지식을 주입할 때는 불필요한 HTML 태그, 내비게이션 바, CSS 스타일을 제거하고 순수 텍스트와 계층형 헤더(#, ##, ###) 중심의 Markdown으로 만드는 것이 임베딩 품질에 가장 유리합니다.
NotebookLM에 웹 URL로 등록해 두셨다면, 외부망(또는 로컬 PC)에서 원본 웹페이지를 직접 Markdown으로 긁어모아 폐쇄망으로 반입하는 것이 가장 깔끔합니다.
crawl4ai 또는 trafilatura / html2text)# pip install trafilatura
import trafilatura
downloaded = trafilatura.fetch_url("https://min.io/docs/minio/linux/index.html")
# 본문만 추출하여 markdown 형식으로 변환
md_text = trafilatura.extract(downloaded, output_format="markdown")
with open("minio_doc.md", "w", encoding="utf-8") as f:
f.write(md_text)
.md 파일로 내려받을 수 있습니다."현재 등록된 모든 소스를 바탕으로, MinIO 아키텍처, 주요 에러 메시지(503, Slow Down, Drive Offline 등), 핵심 Prometheus 메트릭 목록, mc admin 트러블슈팅 명령어를 헤더(
#,##)와 코드 블록 위주의 Markdown 문서로 작성해줘."
Confluence 문서는 구조화된 매크로(정보 패널, 코드 블록, 표)가 많아 단순 복사/붙여넣기 시 서식이 깨지기 쉽습니다.
atlassian-python-api (가장 추천)markdownify로 변환하여 파일로 저장하는 간단한 스크립트를 작성합니다.# pip install atlassian-python-api markdownify
from atlassian import Confluence
from markdownify import markdownify as md
confluence = Confluence(url='https://your-confluence.internal', username='user', password='token_or_pwd')
page = confluence.get_page_by_id(page_id=12345678, expand='body.storage')
raw_html = page['body']['storage']['value']
# Confluence HTML -> Markdown 변환 (헤더, 표, 코드블록 유지)
markdown_content = md(raw_html, heading_style="ATX")
... (더보기) → 내보내기 → `Word로 내보내기`Pandoc을 사용해 Word(.docx)를 Markdown(.md)으로 일괄 변환:pandoc -f docx -t gfm SOP_MinIO_Troubleshooting.docx -o SOP_MinIO_Troubleshooting.md---
doc_type: post_mortem
component: minio-aistor
related_errors: ["Slow Down", "context deadline exceeded", "drive offline"]
target_servers: ["storage-data-node*"]
---
# 2026-08 MinIO Slow Drive 발생으로 인한 I/O 경합 장애 보고서
...
실제 데이터를 직접 덤프하기 어려울 때는 "가상의 토폴로지(서버/스토리지 네이밍 룰)"를 먼저 정의하고, 그 규칙을 LLM에 주입하여 JSON 페이로드를 생성하는 방식이 가장 빠르고 정확합니다.
먼저 사내 인프라 환경과 유사한 네이밍 규칙을 정의합니다. (예시)
prod-aistor-kr01kr01-aistor-dn01 ~ kr01-aistor-dn08 (총 8노드 분산 구성)/data/nvme01 ~ /data/nvme04 (노드당 NVMe 드라이브 4개)10.200.15.x:9000corp-ai-training-data, model-weights-v2ai-serving-worker-7f89d, model-train-job-401RCA 워크플로우 검증을 위해 아래 3가지 대표 시나리오에 대해 각각 데이터를 생성합니다.
kr01-aistor-dn03의 /data/nvme02 디스크 레이턴시 급증503 Slow Down 발생, Goroutine 점진적 상승context deadline exceeded 로그 다발LLM에게 다음과 같은 완성된 가공 페이로드를 프롬프트 테스트 입력으로 제공할 수 있습니다.
{
"incident_meta": {
"incident_id": "INC-202609-0042",
"timestamp": "2026-09-27T16:45:00+09:00",
"cluster": "prod-aistor-kr01",
"service_tier": "P1",
"alarm_name": "MinIOClientPutObjectLatencyHigh"
},
"symptoms_summary": "ai-serving-worker 클라이언트에서 S3 PutObject 호출 시 간헐적 503 Slow Down 및 HTTP 500 에러 급증. 클러스터 전체 처리량 60% 급감.",
"metrics_summary": [
{
"metric": "minio_node_drive_total_duration_microseconds",
"scope": "kr01-aistor-dn03:/data/nvme02",
"baseline": "15ms",
"incident_value": "4850ms (320x spike)",
"status": "CRITICAL"
},
{
"metric": "minio_node_drive_used_bytes_percent",
"scope": "kr01-aistor-dn01~08 (all drives)",
"baseline": "65%",
"incident_value": "68%",
"status": "NORMAL"
},
{
"metric": "go_goroutines",
"scope": "kr01-aistor-dn03",
"baseline": "2,500",
"incident_value": "18,400",
"status": "WARNING"
},
{
"metric": "minio_s3_requests_waiting_total",
"scope": "prod-aistor-kr01 (cluster-wide)",
"baseline": "10~50",
"incident_value": "1,250",
"status": "CRITICAL"
}
],
"logs_summary": [
{
"timestamp": "16:44:12",
"host": "kr01-aistor-dn03",
"level": "WARN",
"message": "Drive: /data/nvme02 took 4.82s to complete write operation (drive is slow)"
},
{
"timestamp": "16:44:28",
"host": "kr01-aistor-dn01",
"level": "ERROR",
"message": "API: PutObject(bucket=corp-ai-training-data, object=batch_01.tar) client timeout, err: context deadline exceeded while writing to peer kr01-aistor-dn03"
},
{
"timestamp": "16:44:50",
"host": "ai-serving-worker-7f89d",
"level": "ERROR",
"message": "S3Exception: 503 Slow Down (Please reduce your request rate.)"
}
]
}
YAML Frontmatter를 붙인 .md 파일 1개를 생성합니다.kr01-aistor-dn03의 /data/nvme02 디스크 지연을 정확히 짚어내고, 지식 베이스의 SOP에 적힌 드라이브 오프라인 격리 명령(mc admin drive offline ...)을 제안하는지 확인합니다.==
폐쇄망 사내 LLM 환경에서 신뢰도 높은 근본 원인 분석(RCA)을 수행할 수 있도록 LangGraph 기반의 State-Machine 아키텍처를 상세 설계했습니다.
단일 LLM 호출의 환각(Hallucination)과 비결정적 추론을 제어하기 위해 상태(State) 추적, 가설 생성-검증 루프, 근거(Grounding) 기반 검증 노드로 역할을 엄격히 분리했습니다.
RCAState)LangGraph 워크플로우 전반에 걸쳐 노드 간에 전달되고 누적되는 공통 상태 객체입니다.
from typing import List, Dict, Any, Optional
from typing_extensions import TypedDict
from pydantic import BaseModel, Field
class AnomalyEntity(BaseModel):
category: str = Field(description="node, disk, api, network, memory 등")
target: str = Field(description="장애 대상 식별자 (예: kr01-aistor-dn03, /data/nvme02)")
evidence: str = Field(description="추출 근거 (특정 메트릭 수치 또는 로그 라인)")
class Hypothesis(BaseModel):
hypothesis_id: str
description: str
target_component: str
verification_rule: str = Field(description="이 가설이 맞기 위해 확인해야 하는 데이터 조건")
status: str = Field(default="PENDING", description="CONFIRMED | DISPROVED | INCONCLUSIVE")
confidence: float = 0.0
rationale: str = ""
class RCAState(TypedDict):
# 1. Input Context
incident_id: str
raw_payload: Dict[str, Any]
# 2. Symptom Analysis
symptom_summary: str
anomaly_entities: List[AnomalyEntity]
search_queries: List[str]
# 3. Knowledge Retrieval
retrieved_docs: List[Dict[str, Any]]
# 4. Hypothesis & Verification Loop
hypotheses: List[Hypothesis]
loop_count: int
# 5. Output Deliverables
root_cause: str
confidence_level: str # HIGH, MEDIUM, LOW
action_runbook: List[str]
final_report: str
[START]
│
▼
┌───────────────────────┐
│ 1. Symptom Normalizer │ ──> 핵심 엔티티 추출, 증상 정규화
└───────────────────────┘
│
▼
┌───────────────────────┐
│ 2. Knowledge Retriever│ ──> Vector DB/SOP 검색 (엔티티 기반 필터링)
└───────────────────────┘
│
▼
┌───────────────────────┐
│ 3. Hypothesis Gen │ ──> 증상+지식 기반 상위 2~3개 가설 도출
└───────────────────────┘
│
▼
┌───────────────────────┐
│ 4. Cross-Check Verif │ ──> 가설별 데이터(로그/메트릭) 엄격 대조
└───────────────────────┘
│
├────────────────────────────┐
▼ (검증 미흡 & loop < 2) ▼ (검증 완료 OR loop >= 2)
┌───────────────────────┐ ┌───────────────────────┐
│ Refine Hypotheses │ │ 5. Report & Runbook │
│ (가설 재조정/보완) │ │ Generator │
└───────────────────────┘ └───────────────────────┘
▲ │
└──────────────────────────────┘
▼
[END]
raw_payload (JSON)symptom_summary, anomaly_entities, search_queries당신은 대규모 분산 오브젝트 스토리지 SRE 전문가입니다.
주어진 Incident JSON의 로그와 메트릭을 분석하여 비정상 패턴(이상치, 에러)을 보이는 리소스 엔티티를 추출하십시오.
[규칙]
1. 명확한 수치 이상(Baseline 대비 급증) 또는 CRITICAL/ERROR 로그에 명시된 식별자만 포함하십시오.
2. 검색 쿼리는 MinIO 트러블슈팅 매뉴얼/SOP 검색에 적합한 키워드(예: "MinIO Slow Down drive timeout", "dsync lock contention") 형태로 2~3개 생성하십시오.
search_queries와 anomaly_entities 메타데이터를 기반으로 사내 Vector DB를 조회합니다.component == "minio-aistor"retrieved_docs에 저장.추출된 이상 엔티티와 지식 베이스(SOP/장애이력)를 참고하여, 장애의 원인이 될 수 있는 가설을 2~3개 수립하십시오.
[입력 정보]
- 이상 엔티티: {anomaly_entities}
- 참고 지식: {retrieved_docs}
[가설 수립 규칙]
각 가설마다 반드시 '이 가설이 참이 되기 위해 로그/메트릭에서 입증되어야 하는 조건(verification_rule)'을 기술하십시오.
예시:
- 가설: 특정 NVMe 하드웨어 성능 저하로 인한 분산 쓰기 지연
- 검증 규칙: 특정 단일 드라이브 duration 메트릭만 급증하고 다른 피어 노드의 드라이브는 정상이어야 하며, 해당 드라이브 slow 로그가 존재해야 함.
verification_rule을 입력된 원본 로그/메트릭과 대조하여 가설을 확정(CONFIRMED), 기각(DISPROVED), 보류(INCONCLUSIVE) 처리합니다. 환각을 차단하는 핵심 관문입니다.당신은 엄격한 장애 감사관입니다. 제공된 로그와 메트릭 데이터만을 근거로 각 가설을 검증하십시오. 데이터에 없는 사실을 추측하지 마십시오.
[가설 목록]: {hypotheses}
[실제 메트릭]: {raw_payload.metrics_summary}
[실제 로그]: {raw_payload.logs_summary}
[검증 지침]
1. 검증 규칙을 완벽히 만족하고 반증 데이터가 없으면 'CONFIRMED'로 판정하십시오.
2. 모순되는 데이터가 발견되면 즉시 'DISPROVED'로 기각하십시오.
3. 데이터가 부족하여 판정할 수 없다면 'INCONCLUSIVE'로 처리하고 부족한 지표를 명시하십시오.
가설 검증 결과에 따라 다음 분기를 결정하는 순수 파이썬 라우팅 함수입니다.
def check_verification_completion(state: RCAState) -> str:
# 1. 확실한 원인 가설이 채택된 경우
has_confirmed = any(h.status == "CONFIRMED" for h in state["hypotheses"])
if has_confirmed:
return "generate_report"
# 2. 가설이 확정되지 않았으나 최대 루프 횟수(예: 2회)에 도달한 경우
if state.get("loop_count", 0) >= 2:
return "generate_report"
# 3. 가설이 모두 기각되었고 추가 탐색 기회가 남은 경우
return "refine_hypotheses"
mc admin drive offline ... 등) 및 2차 확인 절차HIGH/MEDIUM/LOW) 및 추가 수집 권장 메트릭사내 Agent 환경(Python)에서 즉시 바인딩하여 실행할 수 있는 그래프 구성 코드입니다.
from langgraph.graph import StateGraph, END
def build_minio_rca_graph():
workflow = StateGraph(RCAState)
# 1. 노드 등록
workflow.add_node("symptom_normalizer", symptom_normalizer_node)
workflow.add_node("knowledge_retriever", knowledge_retriever_node)
workflow.add_node("hypothesis_generator", hypothesis_generator_node)
workflow.add_node("cross_check_verifier", cross_check_verifier_node)
workflow.add_node("refine_hypotheses", refine_hypotheses_node)
workflow.add_node("generate_report", generate_report_node)
# 2. 엣지 연결
workflow.set_entry_point("symptom_normalizer")
workflow.add_edge("symptom_normalizer", "knowledge_retriever")
workflow.add_edge("knowledge_retriever", "hypothesis_generator")
workflow.add_edge("hypothesis_generator", "cross_check_verifier")
# 3. 조건부 분기 (Verification Loop)
workflow.add_conditional_edges(
"cross_check_verifier",
check_verification_completion,
{
"generate_report": "generate_report",
"refine_hypotheses": "refine_hypotheses"
}
)
workflow.add_edge("refine_hypotheses", "cross_check_verifier")
workflow.add_edge("generate_report", END)
return workflow.compile()
# 실행 인스턴스 생성
rca_app = build_minio_rca_graph()
INCONCLUSIVE), Node 5는 "원인 불명"으로 끝나지 않고 "가장 의심되는 패턴과 현재 부족한 메트릭(예: OS dmesg, 네트워크 retransmit 지표 필요)"을 운영자에게 가이드하도록 프롬프트를 구성합니다.