Kubernetes Cluster Infra RCA Platform
Kubernetes 노드와 Linux evidence로 RCA report를 만드는 프로젝트다. Agent 수집, Rule 기반 분석, LLM 보강과 Policy 분리를 설계하고 Spring Boot·React 구조로 옮겼다.
프로젝트 소개
Kubernetes Cluster Infra RCA Platform은 클러스터 노드와 Linux 시스템 레벨의 증거로 장애 원인을 분석하는 플랫폼이다.
Kubernetes에서 CrashLoopBackOff, OOMKilled, HTTP 5xx, Service endpoint 없음 같은 증상이 보이면 kubelet, container runtime, CNI/DNS, disk I/O, inode, conntrack, kernel log, systemd, node pressure까지 확인할 필요가 있었다.
Node Agent가 모은 Linux/Kubernetes evidence로 원인 후보를 좁히고, Rule-based Analyzer, 선택적 LLM Analyzer, Policy Engine을 거쳐 RCA report를 만들도록 설계했다.
전체 흐름은 다음과 같다.
Alertmanager 또는 수동 수집 요청
-> Node Agent evidence 수집
-> evidence preprocessing
-> Rule-based RCA
-> 선택적 LLM 분석
-> Policy Engine 검증
-> RCA report / incident / export
운영자가 근거와 조치 위험도를 확인하는 데 사용할 도구로 만들었다. 자체 판단으로 클러스터를 수정하는 기능은 범위에 넣지 않았다.
내가 기여한 부분
1. 프로젝트 전체 방향 설계
프로젝트의 범위와 초기 구조를 직접 정했다.
Kubernetes 장애를 Pod 로그와 애플리케이션 오류만으로 확인하는 데서 나아가 노드와 Linux 계층의 근거를 모으려고 했다.
분석 대상은 다음과 같이 정했다.
NodeNotReadyDiskPressureMemoryPressurePIDPressureNetworkUnavailable- kubelet 장애
- container runtime 장애
- CNI/DNS 문제
- disk I/O 병목
- inode 고갈
- conntrack 고갈
- kernel/systemd 로그
- NIC link flap
CrashLoopBackOff, ImagePullBackOff, Pod OOMKilled, HTTP 5xx는 노드나 네트워크 장애의 결과일 수 있으므로 상위 계층의 보조 증상으로 사용하도록 설계했다.
2. RCA 파이프라인 구조 설계
수집부터 report 생성까지의 책임을 다음 단계로 나눴다.
수집 요청
-> Agent evidence 수집
-> evidence 전처리
-> Rule-based 분석
-> 선택적 LLM 분석
-> Policy Engine 분류
-> RCA report 생성
LLM이 근거 없이 원인을 단정하거나 클러스터를 직접 수정하지 않도록 했다.
맡긴 역할은 다음과 같다.
- evidence 요약
- root cause candidate 설명 보강
- 운영자가 읽기 쉬운 RCA report 문장 생성
- 추가 확인 포인트 제안
다음 작업은 LLM의 권한에서 제외했다.
- 클러스터 직접 수정
- kubelet/containerd 재시작
- 노드 drain/cordon 자동 실행
- 위험 조치 자동 승인
- 운영 데이터 삭제
AI의 진단 보강과 실제 조치 판단을 나눴다. Policy Engine이 위험도를 분류하고 운영자가 조치를 결정하는 구조다.
3. Node Agent 설계
Agent는 각 Kubernetes 노드에서 Linux/Kubernetes evidence를 수집하도록 설계했다.
DaemonSet으로 배포하고 다음 항목을 읽는 구조를 잡았다.
/proc/etc/var/log/run- kubelet 상태
- container runtime 상태
- CNI 설정
- DNS 관련 정보
- disk/inode 상태
- memory/PID pressure
- network/conntrack 상태
- kernel/systemd 로그
Agent는 read-only collector로 제한했다.
노드 상태를 읽고 evidence를 제출하는 역할만 맡겼다. 실제 변경은 수동 runbook, GitOps PR, 승인 흐름에서 처리하도록 설계했다.
4. Backend 구조 전환 설계
Backend는 FastAPI로 시작했다.
cluster 등록, evidence request, RCA report 생성, webhook 처리를 빠르게 구현하고 초기 흐름을 검증할 수 있었다.
이후 인증과 운영 기능을 함께 관리할 필요가 생겼다.
추가로 필요한 기능은 다음과 같았다.
- 인증과 권한 관리
- DB migration
- Web Console
- report export
- incident 관리
- audit event
- metric
- scheduling
- LLM provider 연동
- 운영 설정 관리
이를 한곳에서 관리하려고 Spring Boot 3.5.15 + Java 21 기반 Platform으로 옮기기로 했다.
API, 인증, DB, migration, metric, Web Console serving을 같은 애플리케이션으로 통합했다.
5. Web Console 재구성
운영자가 결과와 근거를 찾을 수 있는 화면도 필요했다.
Web Console을 구성했다.
초기 조회 화면을 이후 React 19, TypeScript, Vite, Bootstrap 5 기반으로 다시 구성했다.
원인 후보에서 근거와 조치 위험도로 이어지는 화면 흐름을 기준으로 삼았다.
주요 화면은 다음과 같다.
- cluster 목록
- Agent 상태
- evidence request
- RCA report 목록
- RCA report 상세
- incident timeline
- policy classification
- export
- audit event
report 상세에서는 원인 후보와 함께 판단에 사용한 evidence를 확인하도록 했다.
6. Codex 활용 방식
반복 구현에는 Codex를 활용했다.
직접 결정한 내용과 구현을 보조받은 범위는 다음과 같다.
직접 수행한 작업이다.
- 프로젝트 주제 선정
- 문제 정의
- 전체 아키텍처 설계
- FastAPI에서 Spring Boot로 전환 판단
- Node/Linux 계층 중심 RCA 방향 설정
- Agent read-only 원칙 설정
- LLM 역할 제한
- Policy Engine 필요성 정의
- 위험 조치 자동 실행 금지 원칙 설정
- 트러블슈팅 방향 판단
- 최종 코드 구조 검토
- README/블로그/포트폴리오 방향 정리
Codex를 활용한 작업이다.
- 반복적인 Controller/Service/Repository 구현
- DTO/model 코드 작성 보조
- React component 초안 작성
- TypeScript type 정리
- Docker/Helm 설정 초안 보강
- Flyway migration 초안 작성
- 테스트 케이스 보강
- README 문장 정리
- 반복적인 에러 처리 코드 작성
설계와 검토는 직접 하고, 반복 코드와 초안 작성에 Codex를 사용했다.
트러블슈팅
1. FastAPI 기반 구조의 확장성 한계
확장 과정에서 드러난 한계
초기 Backend는 FastAPI로 만들었다.
MVP의 API를 빠르게 검증하기에 적합했다.
Python Node Agent와도 쉽게 연결할 수 있었다.
기능이 늘면서 통합 관리할 범위를 다시 정해야 했다.
처음에는 cluster 등록, evidence request, report 생성이 중심이었지만 이후 다음 기능이 필요해졌다.
- 인증
- role 기반 권한 제어
- DB migration
- Web Console serving
- metric
- scheduling
- incident 관리
- audit event
- LLM provider 연동
- report export
API, 화면, DB 변경, 인증과 운영 상태를 함께 관리할 단계가 됐다.
기존 FastAPI Backend와 별도 Console, migration을 유지하면 컴포넌트 연결을 계속 따로 맞춰야 했다.
Spring Boot 통합으로 구조 전환
프레임워크 자체의 오류 때문에 전환한 것은 아니었다.
늘어난 요구사항을 함께 관리할 구조가 필요하다고 판단했다.
다음 구성으로 옮겼다.
기존 구조:
FastAPI Backend
+ SQLAlchemy
+ Alembic
+ 별도 Web Console
+ 별도 API 연동
변경 구조:
Spring Boot Platform
+ Spring Security
+ JDBC
+ Flyway
+ Actuator/Micrometer
+ Spring AI
+ React Web Console
Spring Boot에서 API, 인증, DB, migration, metric, Web Console serving을 함께 관리하도록 했다.
구조가 어떻게 달라졌나
이전 구조
backend/
app/
main.py
models.py
store.py
services/
migrations/
alembic.ini
web-console/
Spring Boot Console
이전에는 API Backend와 Web Console을 별도 컴포넌트로 운영했다.
변경 구조
web-console/
pom.xml
src/main/java/...
src/main/resources/db/migration
frontend/
package.json
vite.config.ts
변경 후에는 Spring Boot Platform이 API, 인증, DB, migration, Web Console을 함께 담당했다.
전환할 때 확인한 기준
초기 MVP에서는 개발 속도를, 이후에는 관련 기능의 통합 관리를 기준으로 선택했다.
FastAPI에서 초기 파이프라인을 검증하고 Spring Boot에서 운영 기능을 통합한 순서다.
프로젝트 단계가 달라지면서 관리 구조도 다시 선택했다.
2. Alembic에서 Flyway로 migration 전환
기존 migration이 남긴 제약
초기 Python Backend에서는 SQLAlchemy와 Alembic을 사용했다.
Spring Boot로 통합하면서 DB 접근도 JDBC로 바뀌었다.
기존 migration을 새 구조에 어떻게 연결할지 정해야 했다.
전환 관계는 다음과 같았다.
기존:
Python Backend
-> SQLAlchemy
-> Alembic
변경:
Spring Boot Platform
-> JDBC
-> Flyway
이미 Alembic schema가 존재하는 DB도 연결할 수 있어야 했다.
새 DB를 만드는 경우와 기존 데이터를 이어받는 경우를 나눠 설계했다.
Flyway baseline 적용
Spring Boot의 migration은 Flyway로 관리했다.
새 DB는 Flyway가 schema를 생성하고, 기존 Alembic DB는 baseline-on-migrate 개념으로 schema를 version 1로 인정하는 방향을 잡았다.
PostgreSQL과 MariaDB를 함께 고려했다.
DB별 JSON 타입 차이를 줄이려고 JSON 데이터를 TEXT로 저장하는 방식을 사용했다.
전환 전후
이전 방식
alembic upgrade head
이전에는 Python Backend 실행 전에 Alembic migration을 실행했다.
변경 방식
Flyway migration
-> Spring Boot startup 과정에서 DB schema 관리
전환 후에는 Spring Boot 안에서 migration 흐름을 관리하도록 했다.
데이터 승계에서 확인한 점
기술 스택 변경과 기존 데이터의 승계는 나눠 검토해야 했다.
기존 schema가 있는 상태에서 새 migration을 어떻게 시작할지 먼저 정했다.
검토 기준은 다음과 같았다.
- migration 도구 전환 시 기존 schema 승계를 고려해야 한다
- PostgreSQL/MariaDB처럼 DB가 달라지면 타입 호환성을 신경 써야 한다
- 운영 데이터는 코드보다 더 신중하게 다뤄야 한다
- migration은 자동화하되, 백업과 검증이 전제되어야 한다
3. Agent 수집 실패와 실제 장애를 구분하는 문제
permission 오류와 runtime 장애가 섞인 문제
Agent는 노드의 Linux/Kubernetes evidence를 수집한다.
실제 환경에서는 파일이나 socket에 접근하지 못할 수 있었다.
containerd socket에서는 다음 실패를 구분할 필요가 있었다.
permission denied
file not found
socket timeout
runtime unavailable
이를 모두 containerd 확인 실패로 합치면 원인을 잘못 표시할 수 있었다.
특히 permission denied를 runtime 장애로 판단하면 잘못된 조치로 이어질 수 있었다.
실패 이유를 evidence로 남기기
실패 이유를 evidence의 일부로 남기도록 설계했다.
containerd socket 접근 실패는 다음처럼 구분했다.
containerd_socket_permission_denied: true
runtime_unhealthy: false 또는 unknown
Agent가 읽지 못한 상태와 실제 runtime 상태를 분리하려는 처리다.
특정 Collector가 실패해도 Agent 전체를 중단하지 않게 했다.
collector status:
success
partial
failed
나머지 Collector의 evidence는 계속 제출할 수 있도록 했다.
Collector 실패 처리 변경
피하고 싶었던 방식
raise RuntimeError("collector failed")
이 방식에서는 Collector 하나의 실패가 전체 실행을 멈출 수 있었다.
개선 방향
{
"collector": "runtime",
"status": "partial",
"error": "permission denied",
"signals": {
"containerd_socket_permission_denied": true
}
}
실패 상태를 구조화해 evidence에 포함하도록 했다.
수집 실패를 다루는 기준
읽지 못한 항목은 확인되지 않은 상태로 남겼다.
이를 서비스 장애라고 단정하지 않도록 실패 처리 기준을 정했다.
기준은 다음과 같다.
- collector 실패와 실제 장애는 구분해야 한다
- permission 문제는 장애가 아니라 수집 환경 문제일 수 있다
- partial evidence도 RCA에 의미가 있다
- 운영 도구는 성공 케이스보다 실패 케이스 설계가 더 중요하다
4. RCA report가 JSON에만 머무르는 문제
JSON 응답만으로 부족했던 점
초기에는 API의 JSON 응답으로 report를 확인했다.
개발 중에는 이 방식으로 동작을 검증할 수 있었다.
실제 사용에는 결과를 훑고 근거를 찾아갈 화면이 필요했다.
화면에서 확인할 정보는 다음과 같았다.
- 어떤 cluster에서 발생했는가
- 어떤 node가 영향을 받았는가
- 원인 후보는 무엇인가
- 어떤 evidence가 근거인가
- 추천 조치는 무엇인가
- 조치 위험도는 어느 정도인가
- report를 export할 수 있는가
이 정보에 접근하는 순서를 Console에 구성하려고 했다.
Web Console에서 판단 흐름 구성
React 19, TypeScript, Vite, Bootstrap 5로 Web Console을 구성했다.
목록과 상세를 나누고, 상세에서 evidence, root cause candidate, policy classification, incident 정보를 확인하도록 했다.
개발 중에는 Vite가 /api, /health 요청을 Spring Boot 8080으로 proxy하고, 빌드 결과는 Spring Boot target에 포함시켰다.
개발 서버에서 화면을 수정하고 배포 시에는 Console과 API를 같은 origin으로 제공하도록 했다.
조회 방식의 변화
이전 방식
curl /api/rca/reports
-> JSON 확인
JSON 응답을 직접 읽으며 판단하던 흐름이었다.
개선 방식
Web Console
-> report 목록
-> report 상세
-> evidence 확인
-> policy level 확인
-> export
목록에서 상세 근거와 조치 위험도를 확인하는 화면으로 바꿨다.
화면에 남겨야 할 정보
API 응답을 제공하는 데 더해 그 결과를 검토할 흐름이 필요했다.
장애 중에 정보가 흩어져 있으면 확인할 내용을 놓칠 수 있어 화면별 역할을 나눴다.
구성 기준은 다음과 같다.
- 운영자는 JSON보다 요약과 근거를 함께 볼 수 있는 화면이 필요하다
- TypeScript는 API 응답 구조 변경을 관리하는 데 도움이 된다
- 같은 origin 구조는 인증, CORS, 배포 문제를 줄이는 데 유리하다
- Web Console은 예쁜 화면보다 판단 가능한 화면이 중요하다
기술 스택
Backend / Platform
| 기술 | 사용 이유 |
|---|---|
| Spring Boot 3.5.15 | API, 인증, DB, migration, metric, Web Console serving을 하나의 Platform으로 통합하기 위해 사용 |
| Java 21 | 장기적인 유지보수성과 최신 Spring Boot 환경에 맞추기 위해 사용 |
| Spring Security | 로그인, 세션, role 기반 API 접근 제어를 구현하기 위해 사용 |
| Spring JDBC | PostgreSQL/MariaDB 중심의 명시적인 DB 접근 구조를 구성하기 위해 사용 |
| Flyway | Spring Boot 구조에 맞춰 DB migration을 관리하기 위해 사용 |
| Spring AI | LLM provider 연동을 Platform 내부에서 관리하기 위해 사용 |
| Actuator / Micrometer | Platform 자체의 health, metric, Prometheus 연동을 제공하기 위해 사용 |
Frontend / Web Console
| 기술 | 사용 이유 |
|---|---|
| React 19 | RCA report, incident, agent 상태 등 동적인 운영 화면을 구성하기 위해 사용 |
| TypeScript | API 응답 구조와 UI 상태를 타입으로 관리해 화면 오류를 줄이기 위해 사용 |
| Vite | React 개발 서버와 빠른 build 환경을 구성하기 위해 사용 |
| Bootstrap 5 | 빠르게 일관된 운영자용 UI를 구성하기 위해 사용 |
| Bootstrap Icons | report, agent, incident, status 표현을 위한 아이콘 구성에 사용 |
Agent / Evidence Collection
| 기술 | 사용 이유 |
|---|---|
| Python 3.10+ | Linux/Kubernetes 환경에서 evidence collector를 빠르게 구현하기 위해 사용 |
| Kubernetes DaemonSet | 각 노드마다 Agent를 배포하기 위해 사용 |
| hostPath mount | 노드의 /proc, /var/log, /run 등 host evidence를 수집하기 위해 사용 |
| Helm Chart | Agent와 Platform 배포 설정을 values.yaml 기반으로 관리하기 위해 사용 |
Database
| 기술 | 사용 이유 |
|---|---|
| PostgreSQL | 운영 환경에서 안정적인 관계형 데이터 저장소로 사용하기 위해 채택 |
| MariaDB | MySQL 계열 환경과의 호환성을 고려하기 위해 지원 |
| H2 | 로컬 개발과 테스트 환경에서 빠르게 실행하기 위해 사용 |
| Flyway | PostgreSQL/MariaDB/H2에서 migration 순서를 관리하기 위해 사용 |
DevOps / Deployment
| 기술 | 사용 이유 |
|---|---|
| Docker | Backend/Platform 실행 환경을 컨테이너로 표준화하기 위해 사용 |
| Docker Compose | 로컬에서 Platform, DB, Web Console 흐름을 쉽게 실행하기 위해 사용 |
| Helm | Kubernetes 환경에서 Agent와 Platform 배포 설정을 관리하기 위해 사용 |
| GitHub | 코드 버전 관리와 커밋 기반 개발 기록 정리에 사용 |
해당 스택을 채택한 이유
기술 스택은 기능이 늘어나는 과정에서 단계적으로 바꿨다.
초기에는 FastAPI로 시작했다.
MVP를 빠르게 만들고 RCA pipeline의 연결을 확인하려는 선택이었다.
이후 다음 요구사항이 추가됐다.
- 인증과 권한이 필요해짐
- Web Console이 중요해짐
- DB migration을 안정적으로 관리해야 함
- 운영 metric이 필요해짐
- incident, audit, retention 같은 운영 기능이 필요해짐
- LLM 연동을 Platform 내부에서 관리해야 함
통합 관리를 위해 Spring Boot 3.5.15와 Java 21로 전환했다.
RCA report와 incident 화면에는 React 19와 TypeScript를 사용하고, 개발 환경은 Vite로 구성했다.
migration은 Flyway로 옮겼다.
호스트 evidence를 수집하는 Node Agent는 Python을 유지했다.
기술 선택에서 검토한 기준은 다음과 같다.
- 초기 개발 속도
- 운영 플랫폼으로의 확장성
- 인증/권한/DB/metric 통합 관리
- Kubernetes 배포 가능성
- evidence 수집의 유연성
- AI 기능을 안전하게 보조 역할로 제한할 수 있는 구조
프로젝트를 통해 배운 점
원인 후보만 제시하는 것으로는 분석 결과를 검토하기 어려웠다.
사용한 evidence와 판단 과정을 함께 보여주고, 조치 위험도는 별도로 분류하도록 했다.
기능이 늘면서 처음 구성했던 Backend와 Console의 분리 구조도 다시 검토했다.
FastAPI로 MVP를 확인한 뒤 Spring Boot로 운영 기능을 통합했다.
구현 과정에서는 Codex로 반복 작업을 줄였다.
필요한 기능, 권한 범위, 자동화에서 제외할 조치는 직접 결정하고 결과 코드를 검토했다.