Kubernetes 2026.06.02 9 min read

Kubernetes Cluster Infra RCA Platform 개발 기록 1편

노드와 Linux 계층의 evidence로 Kubernetes 장애 원인을 좁히는 RCA 플랫폼을 시작했다. FastAPI MVP, DB 저장, Agent 수집, Rule 기반 분석과 정책 분류의 초기 흐름을 적었다.

Kubernetes 로고가 있는 파란 블록들이 흰 선으로 이어진 주제용 일러스트
Photo by Growtika / Unsplash

Kubernetes 클러스터를 직접 구성하면서 장애의 첫 증상만으로는 원인을 좁히기 어렵다는 생각이 들었다.

NodeNotReady, DiskPressure, MemoryPressure, CrashLoopBackOff, OOMKilled, HTTP 5xx가 먼저 보이는 경우가 많았다.

Pod, Service, Ingress의 문제처럼 보여도 확인할 대상은 그 아래까지 이어졌다.

실제로 원인을 따라가면 노드나 runtime 계층에 문제가 있는 경우가 있었다.

Pod 장애처럼 보임
  -> kubelet 문제일 수 있음
  -> containerd socket 지연일 수 있음
  -> disk I/O, inode, conntrack, kernel log 문제일 수 있음

이 프로젝트에서는 노드와 Linux 계층의 증거를 중심으로 분석하기로 했다.

만들려던 것은 Kubernetes 클러스터의 장애를 노드와 Linux 시스템 레벨 증거로 분석하는 RCA 플랫폼이었다.

RCA는 Root Cause Analysis, 근본 원인 분석을 뜻한다.

Pod가 영향을 받은 이유를 노드와 runtime의 상태까지 따라가 보는 것이 목표였다.


처음 잡은 방향

첫 단계의 범위는 작게 잡았다.

장애 알림이 들어와 report가 생성되는 최소 흐름부터 만들려고 했다.

처음 정한 순서는 다음과 같다.

alert or manual request
  -> evidence request
  -> node agent collection
  -> evidence preprocessing
  -> rule-based RCA
  -> optional LLM diagnosis
  -> policy classification
  -> RCA report

분석 단계의 역할도 먼저 정했다.

Evidence first.
Rule first.
LLM은 보조.
조치는 Policy Engine을 통과해야 함.

LLM에는 진단 설명을 보강하는 역할을 맡기고, 클러스터 수정이나 위험 조치 실행 권한은 주지 않기로 했다.

증거, 규칙, 정책을 기준으로 분석과 조치 분류를 구성하려고 했다.


첫 번째로 한 일: 범위 정하기

먼저 수집하고 분석할 신호를 정했다.

대상은 노드와 Linux 계층의 evidence였다.

다음 항목을 중심으로 봤다.

  • NodeNotReady
  • DiskPressure
  • MemoryPressure
  • PIDPressure
  • NetworkUnavailable
  • kubelet/runtime 장애
  • CNI/DNS 문제
  • disk I/O 병목
  • inode 고갈
  • conntrack 고갈
  • kernel error
  • systemd unit 장애
  • NIC link flap

CrashLoopBackOff, ImagePullBackOff, OOMKilled, HTTP 5xx는 그 자체로 원인이라고 단정하지 않기로 했다.

노드나 네트워크 장애가 상위 계층에서 드러난 결과일 수 있어 보조 근거로 사용하려고 했다.


Backend MVP 만들기

이 범위를 기준으로 FastAPI Backend MVP를 만들었다.

처음 구현한 기능은 다음과 같다.

  • cluster 등록
  • agent 설치 명령 조회
  • Alertmanager webhook 수신
  • fake evidence 생성
  • rule-based RCA report 생성
  • policy classification

실제 노드 연동 전에 알림이 들어오면 report가 만들어지는지 먼저 확인하려고 했다.

알림 수신과 분석, report 생성을 하나의 흐름으로 연결했다.

Alertmanager webhook
  -> evidence 생성 또는 요청
  -> RCA 분석
  -> report 생성

fake evidence로 먼저 파이프라인의 연결을 검증했다.


저장소 구조 바꾸기

초기 저장소는 in-memory로 만들었다.

하지만 cluster와 장애 기록은 서버 재시작 뒤에도 남아야 했다.

그래서 DB 기반 저장소로 옮겼다.

InMemoryStore
  -> SqlAlchemyStore
  -> PostgreSQL / MariaDB / SQLite 지원
  -> Alembic migration으로 schema 관리

프로세스 메모리에만 두면 기록이 사라질 수 있었기 때문이다.

문제: 프로세스가 재시작되면 cluster, evidence request, RCA report가 사라질 수 있음
수정: DB persistence 추가, Alembic migration으로 schema 관리, PostgreSQL/MariaDB/SQLite 개발 환경 지원

초기 파이프라인을 확인한 뒤 persistence를 추가한 이유다.


Agent와 evidence request 구조 잡기

Node Agent와 Backend 사이의 요청 흐름도 정했다.

Backend가 노드와 수집할 evidence를 지정하고, Agent가 요청을 받아 결과를 제출하도록 했다.

순서는 다음과 같다.

Agent register
  -> node token 발급
  -> Backend evidence request 생성
  -> Agent poll
  -> Agent evidence submit
  -> RCA report 생성

이 구조를 선택한 이유는 세 가지였다.

Agent의 임의 제출을 제한할 수 있었다.

Backend가 어느 노드에서 어떤 Collector를 실행할지 정할 수 있었다.

이후 수동 수집, Alert 수집, RCA 후속 수집을 같은 방식으로 처리할 수 있었다.

추가 수집 기능도 이 요청 구조에 연결하려고 했다.


Node Agent collector 설계

Node Agent는 read-only collector로 시작했다.

장애 분석에 필요한 정보를 읽고 제출하는 역할로 제한했다.

수집 대상으로 검토한 항목은 다음과 같다.

  • /proc
  • /etc
  • /var/log
  • /run
  • systemd
  • kernel log
  • containerd/runtime
  • kubelet
  • CNI
  • DNS
  • disk/inode
  • network/conntrack

Collector 실패 처리도 초기에 정했다.

노드마다 journalctl 접근 권한, containerd socket 위치, CNI 설정 경로가 다를 수 있었다.

특정 Collector가 실패해도 나머지 수집은 계속할 수 있어야 했다.

다음처럼 전체 실행을 중단하는 방식은 피하려고 했다.

raise RuntimeError("collector failed")

대신 실패 상태와 수집한 필드를 함께 반환하는 방향을 잡았다.

return {
    "collector": "runtime",
    "status": "partial",
    "error": "permission denied or file not found",
    "collected_fields": {...},
}

실패 이유도 evidence에 포함했다.

이후 실제 Collector의 permission 문제를 다룰 때도 같은 기준을 적용했다.

접근 실패와 실제 장애를 구분하려는 처리였다.


rule-based RCA를 먼저 둔 이유

LLM을 사용하지 않아도 기본 분석을 할 수 있도록 했다.

Rule-based RCA Analyzer부터 만들었다.

DiskPressure에서는 다음 신호를 확인하도록 했다.

DiskPressure
  -> inode_usage_percent 높음
  -> disk usage 높음
  -> kubelet eviction 관련 log
  -> root cause candidate 생성

NodeNotReady에서는 다음 항목을 봤다.

NodeNotReady
  -> kubelet 재시작 여부
  -> containerd socket 지연
  -> API Server 통신 실패
  -> network / conntrack 신호

원인 후보에 연결할 필드와 신호를 Rule로 먼저 정의했다.

LLM은 그 분석 결과를 보강하는 단계에 뒀다.


AI와 Codex를 어떻게 사용했는가

AI는 개발 도구와 제품 기능으로 나눠 사용했다.

개발 과정에서는 Codex를 활용했다.

프로젝트 범위, 필요한 evidence, Backend와 Agent의 구조는 직접 정했다.

반복 구현, 테스트 케이스 확장, 문서와 보일러플레이트 작성에 Codex를 사용했다.

대상은 다음과 같았다.

  • 반복적인 API route 구현
  • Pydantic model 정리
  • 테스트 케이스 확장
  • 문서 초안 정리
  • Helm/manifest 구조 보강
  • 에러 처리 패턴 보강

제품에는 선택적으로 사용할 LLM Analyzer를 뒀다.

원본 로그를 바로 보내지는 않았다.

evidence를 전처리한 compact JSON을 필요할 때 LLM에 전달하도록 설계했다.

raw evidence
  -> key metrics
  -> derived signals
  -> log summary
  -> config findings
  -> compact JSON
  -> optional LLM Analyzer

LLM의 역할은 다음으로 제한했다.

  • root cause candidate 보강
  • RCA report 설명 문장 보강
  • 추가 확인 포인트 제안
  • 운영자가 읽기 쉬운 요약 생성

다음 작업은 맡기지 않기로 했다.

  • 클러스터 직접 수정
  • 무조건 자동 복구
  • 위험 조치 실행 판단

제품 설계 단계에서 이 범위를 먼저 정했다.

운영 상태를 바꾸는 권한은 진단 보조와 분리할 필요가 있었다.


Policy Engine을 먼저 둔 이유

조치 제안은 실제 서비스에 영향을 줄 수 있으므로 별도로 검토했다.

다음과 같은 조치가 나올 수 있었다.

  • kubelet 재시작
  • containerd 재시작
  • 노드 cordon/drain
  • CNI 설정 변경
  • Pod 삭제
  • 디스크 정리

조회와 변경 작업의 영향 범위가 다르므로 위험도 분류가 필요했다.

모든 추천 조치가 Policy Engine을 통과하도록 했다.

  • AUTO_SAFE
  • APPROVAL_REQUIRED
  • GITOPS_PR_ONLY
  • NEVER_AUTO_EXECUTE
  • MANUAL_INVESTIGATION

분류 흐름은 다음과 같다.

LLM/Rule 추천 조치
  -> Policy Engine classify
  -> UI에는 policy level + reason 표시
  -> 위험 조치는 자동 실행 금지

이 도구는 증거 수집, 원인 후보 분석, 조치 위험도 분류를 맡도록 설계했다.


가장 중요하게 고려했던 점

첫 단계의 구현 범위와 동작 기준을 다음처럼 정했다.

  1. 원인을 Pod에서 바로 찾지 말고 노드/Linux 계층에서 찾기
  2. LLM보다 evidence와 rule을 먼저 신뢰하기
  3. Agent는 read-only로 시작하기
  4. collector 실패를 전체 실패가 아니라 evidence로 남기기
  5. 자동 조치보다 guardrail과 승인 흐름을 먼저 만들기
  6. RCA report는 운영 기록이므로 DB에 남기기

LLM은 진단 설명을 보강하되 클러스터를 직접 수정하지 않도록 했다.

자동 실행을 넓히기 전에 근거와 정책, 승인, 기록을 남기는 구조부터 만들려고 했다.


마무리

첫 단계에서는 구상한 흐름을 코드로 연결했다.

다음 파이프라인의 초기 구성을 만들었다.

Alertmanager webhook
  -> evidence request
  -> Node Agent evidence
  -> RCA report
  -> policy decision

당시에는 아직 초기 구현이었지만 수집부터 정책 분류까지 이어지는 흐름을 확인했다.

evidence, rule, policy를 분석의 기준으로 두고, LLM은 설명 보강에 사용했다. 개발 과정에서는 Codex로 반복 구현 시간을 줄였다.

다음 글에서는 인증, RBAC, webhook 보호, report drilldown, 실제 노드 수집의 permission 문제를 다룬다.

SEARCH JOURNAL

기록 검색

글 제목, 요약, 태그에서 찾습니다.

검색을 준비하고 있어요.

검색어를 입력해 주세요.

    Ctrl/⌘ K 검색 Esc 닫기 결과 이동