30 KiB
인프라 주간 모니터링 보고서 시스템 - 기술 리서치
1. 프로젝트 개요
목표: Prometheus API와 Kubernetes API에서 인프라 메트릭 데이터를 수집하여 주간 모니터링 보고서를 자동 생성하는 시스템
배포 환경: Kubernetes 클러스터 내 Pod으로 배포 (namespace: soo)
핵심 모니터링 메트릭:
- CPU 사용률
- Memory 사용률
- Disk 사용률
- NAS (NFS/CIFS) 스토리지
- Network Traffic (송/수신)
핵심 분석 항목:
- 평균(avg) / 최대(max) / 최소(min) 값
- Peak 구간 감지 (이상 탐지)
- 주의가 필요한 데이터 구간 하이라이트
2. 데이터 소스 분석
2.1 Prometheus HTTP API
Prometheus는 REST API를 통해 메트릭 데이터를 조회할 수 있다.
주요 엔드포인트
| 엔드포인트 | 용도 | 설명 |
|---|---|---|
GET /api/v1/query |
즉시 쿼리 | 현재 시점의 메트릭 조회 |
GET /api/v1/query_range |
범위 쿼리 | 주간 보고서의 핵심 - 시작/종료 시간 + step 간격으로 시계열 데이터 조회 |
GET /api/v1/labels |
레이블 목록 | 사용 가능한 메트릭 레이블 조회 |
GET /api/v1/label/<name>/values |
레이블 값 | 특정 레이블의 값 조회 |
GET /api/v1/metadata |
메트릭 메타데이터 | 메트릭 설명 및 타입 정보 |
query_range API 호출 예시
GET /api/v1/query_range?query=<PromQL>&start=<rfc3339>&end=<rfc3339>&step=<duration>
- 최대 조회 범위: 32일 (주간 보고서에 충분)
- step: 데이터 해상도 (예:
5m,15m,1h) - 주간 보고서용 권장 step:
5m~15m(세밀한 peak 감지를 위해)
핵심 PromQL 쿼리
CPU 사용률 (%):
# 노드별 CPU 사용률
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 또는
sum by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[5m])) * 100
Memory 사용률 (%):
# 노드별 메모리 사용률
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
Disk 사용률 (%):
# 파일시스템별 디스크 사용률
(1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100
NAS/NFS 모니터링:
# NFS 마운트 디스크 사용률
(1 - node_filesystem_avail_bytes{fstype="nfs"} / node_filesystem_size_bytes{fstype="nfs"}) * 100
# NFS 마운트 디스크 사용률 (nfs4 포함)
(1 - node_filesystem_avail_bytes{fstype=~"nfs|nfs4|cifs"} / node_filesystem_size_bytes{fstype=~"nfs|nfs4|cifs"}) * 100
참고: NAS 모니터링은 node_exporter의 filesystem collector가 NFS/CIFS 마운트도 수집함. Synology 등 전용 NAS는 SNMP exporter(
snmp_exporter)를 통해 더 상세한 메트릭 수집 가능.
Network Traffic (bytes/sec):
# 수신 트래픽 (bytes/sec)
sum by (instance) (rate(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))
# 송신 트래픽 (bytes/sec)
sum by (instance) (rate(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))
# bps 단위로 변환
sum by (instance) (rate(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m])) * 8
통계 분석용 PromQL (avg / max / peak 감지)
평균 (avg_over_time):
# 주간 평균 CPU 사용률
avg_over_time(
(100 - avg by (instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)[7d:5m]
)
최대 (max_over_time):
# 주간 최대 CPU 사용률
max_over_time(
(100 - avg by (instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)[7d:5m]
)
Peak/이상 탐지 (Z-Score 기반):
# Z-Score = (현재값 - 평균) / 표준편차
# |Z| > 2 이면 이상 구간으로 판단
(
rate(node_cpu_seconds_total{mode!="idle"}[5m])
- avg_over_time(rate(node_cpu_seconds_total{mode!="idle"}[5m])[1d])
) / stddev_over_time(rate(node_cpu_seconds_total{mode!="idle"}[5m])[1d])
표준편차 기반 이상 탐지:
# 평균 + 2*표준편차를 초과하는 구간 감지
<metric> > (avg_over_time(<metric>[7d:5m]) + 2 * stddev_over_time(<metric>[7d:5m]))
2.2 Kubernetes API
노드 정보 조회
| 엔드포인트 | 용도 |
|---|---|
GET /api/v1/nodes |
전체 노드 목록 + 스펙(CPU, Memory, OS 등) |
GET /api/v1/nodes/<name> |
특정 노드 상세 정보 |
GET /apis/metrics.k8s.io/v1beta1/nodes |
노드별 실시간 리소스 사용량 (metrics-server 필요) |
GET /apis/metrics.k8s.io/v1beta1/nodes/<name> |
특정 노드 실시간 사용량 |
노드 정보에서 얻을 수 있는 데이터
{
"metadata": { "name": "node-1", "labels": { "role": "worker" } },
"status": {
"capacity": { "cpu": "16", "memory": "65536Mi" },
"allocatable": { "cpu": "15800m", "memory": "63000Mi" },
"nodeInfo": {
"osImage": "Ubuntu 22.04",
"kubeletVersion": "v1.28.0",
"containerRuntimeVersion": "containerd://1.7.0"
},
"conditions": [
{ "type": "Ready", "status": "True" },
{ "type": "MemoryPressure", "status": "False" },
{ "type": "DiskPressure", "status": "False" }
]
}
}
인증 방식 (Pod 내부 배포 기준)
Pod으로 배포되므로 In-Cluster Config를 사용한다. K8s가 자동으로 ServiceAccount 토큰을 Pod에 마운트해준다.
/var/run/secrets/kubernetes.io/serviceaccount/token ← Bearer Token
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt ← CA 인증서
KUBERNETES_SERVICE_HOST / KUBERNETES_SERVICE_PORT ← API 서버 주소 (자동 주입)
@kubernetes/client-node 라이브러리 사용 시:
import * as k8s from '@kubernetes/client-node';
const kc = new k8s.KubeConfig();
kc.loadFromCluster(); // ← in-cluster config 자동 로드
const coreApi = kc.makeApiClient(k8s.CoreV1Api);
const nodes = await coreApi.listNode();
참고: 외부 개발 시에는
kc.loadFromDefault()로 로컬 kubeconfig 사용 가능
3. 아키텍처 (K8s Pod 배포)
3.1 배포 아키텍처
K8s Pod으로 배포되므로 클러스터 내부 통신을 활용한 Next.js 풀스택 (BFF 패턴) 단일 구성이 최적이다.
┌─── K8s Cluster ──────────────────────────────────────────────┐
│ │
│ ┌─── Pod: infra-report (ns: soo) ────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Next.js (App Router) │ │ │
│ │ │ ┌───────────┐ ┌────────────┐ │ │ │
│ │ │ │ Frontend │ │ API Routes │──┼──→ Prometheus │ │
│ │ │ │ (React) │ │ (BFF) │──┼──→ K8s API Server │ │
│ │ │ └───────────┘ └────────────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ ServiceAccount: infra-report-sa │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Service ──┐ │
│ │ ClusterIP │ ← Ingress / NodePort로 외부 접근 │
│ │ :3000 │ │
│ └─────────────┘ │
│ │
│ Prometheus: http://prometheus-server.monitoring │
│ K8s API: https://kubernetes.default.svc (in-cluster) │
└──────────────────────────────────────────────────────────────┘
3.2 K8s Pod 배포의 이점
| 이점 | 설명 |
|---|---|
| CORS 문제 없음 | API Routes가 서버 사이드에서 Prometheus 호출 (Pod 간 통신) |
| 인증 자동 처리 | ServiceAccount 토큰이 Pod에 자동 마운트 → K8s API 인증 |
| Prometheus 내부 접근 | prometheus-server.monitoring으로 클러스터 내부 DNS 호출 |
| 설정 관리 | ConfigMap/Secret으로 환경변수 주입 |
| 헬스체크 | K8s liveness/readiness probe 활용 |
| 자동 복구 | Pod 장애 시 자동 재시작 |
| 수평 확장 | 필요시 replica 증가 가능 (보고서 용도라 보통 1개면 충분) |
3.3 프론트엔드 Only 가능 여부
K8s Pod으로 배포하는 이상 BFF 패턴이 자연스러운 선택이다. Next.js 자체가 서버 런타임을 포함하므로 "프론트만 구현"해도 API Routes로 백엔드 로직을 가진 풀스택 앱이 된다. 즉, 프론트엔드 코드만 작성해도 사실상 백엔드가 포함된 구조이므로 프론트 개발자 혼자서 충분히 구현 가능하다.
4. 기술 스택 상세
4.1 프론트엔드
| 카테고리 | 추천 기술 | 대안 | 선택 이유 |
|---|---|---|---|
| 프레임워크 | Next.js (App Router) | Vite + React | API Routes로 BFF 패턴, standalone 빌드로 K8s 최적화 |
| 언어 | TypeScript | JavaScript | 타입 안정성, API 응답 타입 정의 |
| 차트 라이브러리 | Apache ECharts (echarts-for-react) |
Recharts, Chart.js | 대량 데이터 처리 성능 우수, 다양한 차트 타입, 인터랙티브 기능 |
| UI 프레임워크 | Tailwind CSS + shadcn/ui | Ant Design, MUI | 경량, 커스터마이징 용이, 보고서 레이아웃에 적합 |
| 테이블 | TanStack Table | AG Grid | 정렬/필터링, 경량 |
| 상태관리 | TanStack Query (React Query) | SWR, Zustand | API 데이터 캐싱/재조회 최적화 |
| 날짜 처리 | date-fns 또는 dayjs | moment.js (deprecated) | 경량, 트리쉐이킹 지원 |
| PDF 생성 | html2canvas + jsPDF (클라이언트) 또는 Puppeteer (서버) | react-pdf | 보고서 레이아웃 그대로 PDF 변환 |
차트 라이브러리 비교 (보고서 용도 관점)
| 기준 | ECharts | Recharts | Chart.js |
|---|---|---|---|
| 대량 데이터 (1만+ 포인트) | WebGL 렌더링으로 최고 | SVG 기반, 느려짐 | Canvas 기반, 양호 |
| 시계열 차트 | 내장 dataZoom, 브러시 선택 | 기본적 | 줌 플러그인 필요 |
| 보고서 스타일 | 풍부한 옵션 | 심플 | 심플 |
| 툴팁/인터랙션 | 매우 풍부 | 기본적 | 기본적 |
| 번들 사이즈 | ~1MB (트리쉐이킹 가능) | ~200KB | ~60KB |
| React 통합 | echarts-for-react 래퍼 | 네이티브 React | react-chartjs-2 래퍼 |
권장: 인프라 모니터링 보고서는 데이터 포인트가 많고 시계열 분석이 핵심이므로 Apache ECharts 추천. 데이터가 적고 단순한 보고서라면 Recharts도 충분.
4.2 백엔드 (경량)
| 카테고리 | 추천 기술 | 대안 | 선택 이유 |
|---|---|---|---|
| 런타임 | Node.js | Python (FastAPI) | 프론트와 언어 통일, Next.js API Routes 활용 가능 |
| HTTP 클라이언트 | axios 또는 fetch (Node 18+) | got, node-fetch | Prometheus/K8s API 호출 |
| K8s 클라이언트 | @kubernetes/client-node | kubectl exec | 공식 JS 클라이언트, in-cluster config 지원 |
| 스케줄링 | node-cron 또는 K8s CronJob | Bull Queue | Pod 내부 cron 또는 K8s 네이티브 CronJob |
| PDF (서버) | Puppeteer | Playwright | 헤드리스 브라우저로 pixel-perfect PDF |
4.3 Python 백엔드 대안 (데이터 분석 강점)
| 카테고리 | 기술 | 장점 |
|---|---|---|
| 프레임워크 | FastAPI | 비동기, 자동 API 문서, 타입 힌트 |
| Prometheus 클라이언트 | prometheus-api-client |
PromQL 결과를 Pandas DataFrame으로 변환 |
| K8s 클라이언트 | kubernetes (공식) |
완성도 높은 공식 클라이언트 |
| 데이터 분석 | Pandas, NumPy | 통계 분석(평균/최대/표준편차/이상탐지) 강력 |
| PDF 생성 | WeasyPrint, ReportLab | HTML → PDF 변환 |
참고: 데이터 분석/통계에 중점을 둔다면 Python 백엔드가 더 강력하지만, 프론트엔드와의 통합성과 단일 프로젝트 관리를 고려하면 Next.js + API Routes가 더 실용적.
5. 보고서 데이터 가공 로직
5.1 데이터 수집 흐름
1. 보고 기간 설정 (예: 지난 7일)
├─ start: 2026-03-05T00:00:00Z
└─ end: 2026-03-12T00:00:00Z
2. Prometheus query_range API 호출
├─ CPU 사용률 쿼리 (step=5m → 2,016 데이터포인트/노드)
├─ Memory 사용률 쿼리
├─ Disk 사용률 쿼리
├─ NAS 사용률 쿼리
└─ Network 트래픽 쿼리
3. K8s API 호출
├─ 노드 목록 + 스펙 (CPU cores, RAM 총량)
└─ 노드 상태 (conditions)
4. 데이터 가공
├─ 노드별 통계 계산 (avg, max, min, p95, p99)
├─ Peak 구간 감지 (Z-Score 기반)
├─ 임계값 초과 구간 마킹
└─ 트렌드 분석 (전주 대비 증감)
5. 보고서 렌더링
├─ 요약 대시보드 (핵심 지표 카드)
├─ 시계열 차트 (peak 구간 하이라이트)
├─ 노드별 상세 테이블
└─ PDF 내보내기
5.2 Peak 감지 알고리즘
방법 1: PromQL 서버 사이드 (Prometheus에서 계산)
# avg_over_time + stddev_over_time 조합
# 평균 + 2σ 초과 시 peak으로 판정
# CPU peak 감지
(100 - avg by (instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
>
(
avg_over_time((100 - avg by (instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)[7d:5m])
+ 2 * stddev_over_time((100 - avg by (instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)[7d:5m])
)
방법 2: 클라이언트/백엔드 사이드 (JavaScript/Python)
// Z-Score 기반 peak 감지
function detectPeaks(dataPoints, threshold = 2) {
const values = dataPoints.map(d => d.value);
const mean = values.reduce((a, b) => a + b) / values.length;
const stddev = Math.sqrt(
values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / values.length
);
return dataPoints.map(d => ({
...d,
zScore: (d.value - mean) / stddev,
isPeak: Math.abs((d.value - mean) / stddev) > threshold,
}));
}
5.3 보고서 구성 요소
┌─────────────────────────────────────────────────┐
│ 인프라 주간 모니터링 보고서 │
│ 2026.03.05 ~ 2026.03.12 │
├─────────────────────────────────────────────────┤
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ CPU │ │ MEM │ │ DISK │ │ NET │ ← 요약 │
│ │ 평균 │ │ 평균 │ │ 평균 │ │ 평균 │ 카드 │
│ │ 최대 │ │ 최대 │ │ 최대 │ │ 최대 │ │
│ │ 최소 │ │ 최소 │ │ 최소 │ │ │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
├─────────────────────────────────────────────────┤
│ [CPU 사용률 시계열 차트] │
│ ████████░░░░████████████████░░░░████████ │
│ ↑ peak 구간 하이라이트 │
├─────────────────────────────────────────────────┤
│ [Memory 사용률 시계열 차트] │
├─────────────────────────────────────────────────┤
│ [Disk/NAS 사용률 차트] │
├─────────────────────────────────────────────────┤
│ [Network Traffic 차트 (In/Out)] │
├─────────────────────────────────────────────────┤
│ 노드별 상세 │
│ ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │
│ │ 노드 │ CPU │ CPU │ CPU │ MEM │ MEM │ MEM │ DISK │ │
│ │ │ avg │ max │ min │ avg │ max │ min │ max │ │
│ ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤ │
│ │node-1│ 45% │ 92% │ 12% │ 67% │ 85% │ 41% │ 72% │ │
│ │node-2│ 38% │ 78% │ 8% │ 55% │ 70% │ 35% │ 45% │ │
│ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ │
├─────────────────────────────────────────────────┤
│ ⚠ 주의 구간 │
│ - node-1: 03/07 14:00~16:30 CPU 92% 도달 │
│ - node-2: 03/09 02:00~03:00 Memory 85% 초과 │
│ - NAS-01: 디스크 사용률 85% 초과 (증설 검토 필요) │
└─────────────────────────────────────────────────┘
6. 기술 스택 최종 추천
6.1 추천 구성: Next.js 풀스택 + K8s 배포
infra-report/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── page.tsx # 메인 보고서 페이지
│ │ ├── api/ # API Routes (BFF)
│ │ │ ├── metrics/ # Prometheus 데이터 프록시 + 가공
│ │ │ │ ├── cpu/route.ts
│ │ │ │ ├── memory/route.ts
│ │ │ │ ├── disk/route.ts
│ │ │ │ ├── nas/route.ts
│ │ │ │ └── network/route.ts
│ │ │ ├── nodes/route.ts # K8s 노드 정보
│ │ │ └── report/route.ts # 보고서 데이터 통합
│ │ └── report/
│ │ └── [id]/page.tsx # 개별 보고서 상세
│ ├── components/
│ │ ├── charts/ # 차트 컴포넌트
│ │ │ ├── CpuChart.tsx
│ │ │ ├── MemoryChart.tsx
│ │ │ ├── DiskChart.tsx
│ │ │ ├── NetworkChart.tsx
│ │ │ └── PeakHighlight.tsx
│ │ ├── report/ # 보고서 레이아웃 컴포넌트
│ │ │ ├── SummaryCards.tsx
│ │ │ ├── NodeTable.tsx
│ │ │ └── AlertSection.tsx
│ │ └── ui/ # 공통 UI 컴포넌트
│ ├── lib/
│ │ ├── prometheus.ts # Prometheus API 클라이언트
│ │ ├── kubernetes.ts # K8s API 클라이언트 (in-cluster config)
│ │ ├── analytics.ts # 통계 계산 (avg, max, peak 감지)
│ │ └── formatters.ts # 데이터 포맷팅 (bytes→GB 등)
│ └── types/
│ ├── metrics.ts # 메트릭 데이터 타입
│ └── report.ts # 보고서 데이터 타입
├── k8s/ # K8s 매니페스트
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── serviceaccount.yaml
│ ├── rbac.yaml # ClusterRole + ClusterRoleBinding
│ └── configmap.yaml
├── Dockerfile
├── .dockerignore
├── package.json
├── tailwind.config.ts
├── tsconfig.json
└── .env.local # 로컬 개발용 (Pod에서는 ConfigMap/Secret 사용)
6.2 핵심 패키지 목록
{
"dependencies": {
"next": "^14.x",
"react": "^18.x",
"typescript": "^5.x",
"echarts": "^5.x",
"echarts-for-react": "^3.x",
"@tanstack/react-query": "^5.x",
"@tanstack/react-table": "^8.x",
"tailwindcss": "^3.x",
"@radix-ui/react-*": "latest",
"axios": "^1.x",
"@kubernetes/client-node": "^0.20.x",
"date-fns": "^3.x",
"jspdf": "^2.x",
"html2canvas": "^1.x",
"zod": "^3.x"
}
}
7. K8s 배포 상세
7.1 Dockerfile
# ── Build Stage ──
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ── Production Stage ──
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
next.config.js에output: 'standalone'설정 필요
7.2 K8s 매니페스트
ServiceAccount + RBAC (노드 조회 권한)
# k8s/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: infra-report-sa
namespace: soo
---
# k8s/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: infra-report-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: infra-report-reader-binding
subjects:
- kind: ServiceAccount
name: infra-report-sa
namespace: soo
roleRef:
kind: ClusterRole
name: infra-report-reader
apiGroup: rbac.authorization.k8s.io
ConfigMap (환경변수)
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: infra-report-config
namespace: soo
data:
PROMETHEUS_URL: "http://prometheus-server.monitoring"
REPORT_STEP: "5m"
REPORT_RANGE_DAYS: "7"
TZ: "Asia/Seoul"
Deployment
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: infra-report
namespace: soo
labels:
app: infra-report
spec:
replicas: 1
selector:
matchLabels:
app: infra-report
template:
metadata:
labels:
app: infra-report
spec:
serviceAccountName: infra-report-sa
containers:
- name: infra-report
image: harbor.inje-private.com/soo/infra-report:latest
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: infra-report-config
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
Service + Ingress
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: infra-report
namespace: soo
spec:
type: ClusterIP
selector:
app: infra-report
ports:
- port: 80
targetPort: 3000
protocol: TCP
---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: infra-report
namespace: soo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: infra-report.gpulive.cloud # 실제 도메인으로 변경
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: infra-report
port:
number: 80
7.3 환경변수 관리
| 구분 | 로컬 개발 | K8s Pod |
|---|---|---|
| Prometheus URL | .env.local |
ConfigMap |
| K8s 인증 | kubeconfig (자동) | ServiceAccount (자동) |
| 민감 정보 | .env.local |
Secret |
| 타임존 | OS 설정 | ConfigMap (TZ=Asia/Seoul) |
7.4 빌드/배포 파이프라인
1. 코드 Push → Gitea (gitea.inje-private.com)
2. CI (Gitea Runner)
├─ npm ci && npm run build
├─ docker build → harbor.inje-private.com/soo/infra-report:${TAG}
└─ docker push
3. CD (ArgoCD: argocd.gpulive.cloud)
├─ k8s/ 매니페스트 변경 감지
└─ 자동 배포 (sync)
7.5 Next.js 설정 (standalone 빌드)
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone', // Docker 최적화 필수
experimental: {
// 서버 컴포넌트에서 K8s 클라이언트 사용 시
serverComponentsExternalPackages: ['@kubernetes/client-node'],
},
};
module.exports = nextConfig;
8. 구현 우선순위 로드맵
Phase 1: 프로젝트 세팅 + K8s 배포 기반
- Next.js 프로젝트 초기 구성 (TypeScript, Tailwind, standalone 빌드)
- Dockerfile 작성 + 로컬 빌드 테스트
- K8s 매니페스트 작성 (ServiceAccount, RBAC, Deployment, Service)
- Harbor 이미지 Push + K8s 클러스터 배포 확인
- Health check API (
/api/health) 구현
Phase 2: 데이터 수집 MVP
- Prometheus API 클라이언트 구현 (lib/prometheus.ts)
- K8s 노드 정보 조회 (lib/kubernetes.ts, in-cluster config)
- CPU/Memory 메트릭 API Routes 구현
- 기본 시계열 차트 (ECharts)
- 요약 카드 컴포넌트
Phase 3: 데이터 확장
- Disk/NAS/Network 메트릭 추가
- 노드별 상세 테이블
- 통계 계산 로직 (avg, max, p95)
Phase 4: 분석 기능
- Peak 구간 감지 (Z-Score)
- 차트에 peak 구간 하이라이트
- 주의 구간 알림 섹션
- 전주 대비 트렌드
Phase 5: 보고서 기능
- PDF 내보내기
- 보고서 기간 선택 UI
- Ingress 설정 + 외부 접근
Phase 6: 자동화 (추후)
- 주간 자동 보고서 생성 (CronJob 또는 node-cron)
- Slack/Email 발송
- Gitea Runner CI/CD 파이프라인 연동
- ArgoCD 자동 배포
9. 참고 자료
Prometheus
- Prometheus Query Examples
- Prometheus API Guide - Last9
- PromQL Cheat Sheet - SigNoz
- PromQL Cheat Sheet - PromLabs
- Anomaly Detection with PromQL
- Z-Score in PromQL
- Prometheus Over Time Analysis
- PromQL Subqueries and Aggregations
Kubernetes
- K8s Resource Metrics Pipeline
- K8s Node Metrics Data
- Metrics Server
- kubectl proxy
- @kubernetes/client-node
- K8s RBAC Authorization