Agentic AI 구축/Agentic AI Intelligence Plane 구축

Prometheus & Grafana & Loki를 활용한 RAN-CN E2E 모니터링 스택 구축

gksyb4235 2026. 6. 10. 15:01

지금까지 Kubernetes 1.35 기반으로 쿠버네티스 클러스터를 구축하고 Helm Chart를 이용해 Free5GC를 설치했다.

여기에 OpenAirInterface의 Flexric과 gNB, UE도 Docker 기반으로 K8s Pod에 통합시켰다.

이제 Free5GC의 각종 metric과 로그를 실시간으로 확인할 차례이다.

 

이전 글에서 Free5GC를 모니터링하는 Promethes & Loki & Grafana 기반의 모니터링 스택을 구축했었다.

https://gksyb4235.tistory.com/78

 

Prometheus & Loki & Grafana를 활용한 Free5GC Metrics 모니터링하기

Outline 지금까지 쿠버네티스 클러스터를 구축하고, 여기에 Helm 차트를 이용해 Free5GC를 설치했다.이제 Step 3의 모니터링 툴을 이용해서 Free5GC의 각종 Metric을 확인해볼 차례이다.우선, Prometheus와 Graf

gksyb4235.tistory.com

 

이번에는 Prometheus, Grafana, 그리고 Grafana에 통합된 Grafana Loki를 살펴보고,

최신 Observability 도구인 Grafana Alloy를 활용해 이들을 쿠버네티스 클러스터에 배포하여 5G 네트워크의 상태를 통합 모니터링하는 모니터링 스택을 구축한다.

 

모니터링 스택을 배포하기에 앞서, 현재 테스트베드 클러스터 구성은 다음과 같다.

노드 역할 IP OS
mater-node (서버) control-plane 192.168.56.50 Ubuntu 22.04 live-server
free5gc-cp worker (Core NF) 192.168.56.51 Ubuntu 22.04
free5gc-up worker (UPF) 192.168.56.52 Ubuntu 20.04
oai-ran worker (RAN) 192.168.56.30 Ubuntu 24.04

 

모든 노드에서 Kubernetes v1.35.5, Container Runtime은 CRI-O 1.35.4를 사용한다.

 

 

 

모니터링 Tool 소개


Prometheus 시계열 Metrics 수집


Prometheus는 CNCF Graduate 프로젝트로, 인프라와 애플리케이션의 metric 데이터를 시계열 형태로 수집, 저장하는 오픈소스 모니터링 시스템이다.

 

핵심 특징은 다음과 같다.

  • Pull 기반 수집: 타겟 endpoint의 `/metrics`를 주기적으로 scraping하여 데이터를 가져온다.
  • PromQL: 전용 쿼리 언어로 실시간 데이터 분석과 시각화가 가능하다.
  • AlertManager 연동: 사용자 정의 규칙에 따라 자동 알림 발송이 가능하다. (mail, slack 등)
  • ServiceMonitor/PodMonitor: Kubernetes 환경에서 선언적으로 scraping 대상을 관리한다.

모니터링 스택에서는 Prometheus Operator를 통해 Kubernetes 시스템 컴포넌트(kubelet, kube-apiserver, etcd 등)부터 Free5GC NF Pod, MongoDB, FlexRIC으로부터 수집되는 RAN의 metric까지 통합 수집한다.

 

 

Loki  로그 수집 및 조회


Loki는 Grafana Labs가 개발한 로그 집계 시스템이다.

Prometheus가 메트릭을 수집하듯, Loki는 로그를 수집·인덱싱·저장한다.

 

핵심 특징:

  • LogQL: PromQL과 유사한 쿼리 언어로 로그를 필터링·집계·분석한다
  • label 기반 indexing: 로그 내용 전체를 indexing하지 않고 라벨(namespace, pod, container 등)만 인덱싱하여 저장 비용을 절감한다.
  • Grafana 네이티브 통합: Grafana의 Explore 탭에서 바로 로그를 조회할 수 있다

과거에는 로그 수집기로 Promtail을 사용했으나, 현재는 deprecated되었다.

최신 스택에서는 Grafana Alloy가 그 역할을 대체한다.

 

 

Grafana Alloy 통합 텔리미트리 수집기


Grafana Alloy는 Promtail과 OpenTelemetry Collector의 기능을 통합한 차세대 Observability 파이프라인이다.

다음과 같은 역할을 수행한다.

  • 로그 수집 (기존 Promtail 역할)
  • OTLP 수신 및 라우팅 (기존 OpenTelemetry Collector 역할)
  • Prometheus remote write
  • 선언적 구성 (River 문법 기반)

 

DaemonSet으로 배포되어 모든 노드에서 로그를 수집하고,

OTLP 프로토콜을 통해 메트릭과 로그를 Prometheus/Loki로 라우팅한다.

 

https://grafana.com/blog/grafana-alloy-opentelemetry-collector-with-prometheus-pipelines/

 

Introducing an OpenTelemetry Collector distribution with built-in Prometheus pipelines: Grafana Alloy | Grafana Labs

Grafana Alloy is a telemetry collector that is 100% OTLP compatible and offers native pipelines for OpenTelemetry and Prometheus telemetry formats, supporting metrics, logs, traces, and profiles.

grafana.com

 

 

 

Grafana — 통합 시각화 대시보드


Grafana는 메트릭과 로그를 통합 대시보드로 시각화하는 오픈소스 모니터링 플랫폼이다.

  • Prometheus, Loki를 비롯한 다양한 데이터소스를 지원한다.
  • 커스텀 대시보드를 자유롭게 구성할 수 있다.
  • 내장 AlertManager 기능으로 알림까지 통합 관리가 가능하다.

 

 

아키텍처 설계


전체 모니터링 스택은 `monitoring` namespace에 배포되며, Prometheus/Grafana/Loki는 master-node에,

Alloy는 DaemonSet으로 모든 노드에 배포된다.

┌───────────────────────────────────────────────────────────────────┐
│                  Master Node (192.168.56.50)                      │
│  ┌────────────────────────────────────────────────────────────┐   │
│  │                  monitoring namespace                      │   │
│  │  ┌──────────────┐  ┌──────────┐  ┌─────────────────────┐   │   │
│  │  │  Prometheus  │  │   Loki   │  │  Grafana (:30000)   │   │   │
│  │  │  (Operator)  │  │(SingleBin│  │  - Prometheus DS    │   │   │
│  │  └──────┬───────┘  └────┬─────┘  │  - Loki DS          │   │   │
│  │         │               │        │  - FlexRIC DS       │   │   │
│  │  ┌──────┴───────────────┴─────┐  └─────────────────────┘   │   │
│  │  │   Grafana Alloy (DaemonSet)│                            │   │
│  │  └──────────────┬─────────────┘                            │   │
│  │  ┌──────────────┴─────────────┐                            │   │
│  │  │   MongoDB Exporter         │                            │   │
│  │  │   + ServiceMonitor         │                            │   │
│  │  └────────────────────────────┘                            │   │
│  └────────────────────────────────────────────────────────────┘   │
└───────────────────────────────────────────────────────────────────┘

┌──────────────────────┐  ┌──────────────────────┐  ┌─────────────────┐
│  oai-ran (Worker)    │  │ free5gc-cp (Worker)  │  │ free5gc-up      │
│  - Alloy DaemonSet   │  │ - Alloy DaemonSet    │  │ - Alloy DmSet   │
│  - FlexRIC (:3000)   │  │ - AMF, SMF, NRF...   │  │ - UPF           │
│  - gNB, UE           │  │ - MongoDB            │  │                 │
└──────────────────────┘  └──────────────────────┘  └─────────────────┘

 

 

데이터 흐름:


1. Alloy DaemonSet → 각 노드의 Pod 로그를 수집 → Loki로 전송

2. Alloy OTLP Receiver → 애플리케이션 텔레메트리를 수신 → Prometheus/Loki로 라우팅

3. Prometheus Operator → ServiceMonitor/PodMonitor 기반으로 메트릭 스크래핑

4. MongoDB Exporter → Free5GC MongoDB 메트릭을 Prometheus 형식으로 노출

5. Grafana → Prometheus + Loki + FlexRIC 데이터소스를 통합 시각화

 

 

모니터링 스택 설치


# 사전 준비: Helm Repository 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
# Step 1: Loki 배포 (로그 저장소)
## `loki-values.yaml`:
deploymentMode: SingleBinary

loki:
  auth_enabled: false
  commonConfig:
    replication_factor: 1
    path_prefix: /tmp/loki
  storage:
    type: filesystem
    filesystem:
      chunks_directory: /tmp/loki/chunks
      rules_directory: /tmp/loki/rules
  limits_config:
    retention_period: 168h  # 7일 보존
  schemaConfig:
    configs:
      - from: "2024-01-01"
        store: tsdb
        object_store: filesystem
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

singleBinary:
  replicas: 1
  nodeSelector:
    kubernetes.io/hostname: "master-node"
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"
  persistence:
    enabled: false

gateway:
  enabled: false

backend:
  replicas: 0
read:
  replicas: 0
write:
  replicas: 0

chunksCache:
  enabled: false
resultsCache:
  enabled: false

# 배포
helm upgrade --install loki grafana/loki \
  -n monitoring --create-namespace \
  -f loki-values.yaml \
  --wait --timeout 5m

 

  •  `auth_enabled: false` — 테스트 환경에서 인증 비활성화
  •  `SingleBinary` 모드 — read/write/backend를 분리하지 않고 단일 인스턴스로 운영
  •  `retention_period: 168h` — 로그를 7일간 보존
  •  `nodeSelector`와 `tolerations` — master 노드의 control-plane taint를 허용하여 스케줄링
# Step 2: Grafana Alloy 배포 (로그 수집 + OTLP 라우팅)
## Alloy는 기존 Promtail + OpenTelemetry Collector를 하나로 통합한 에이전트다.
##`alloy-values.yaml`:

alloy:
  configMap:
    content: |
      // ============================================================
      // Log Collection (replaces Promtail)
      // ============================================================
      discovery.kubernetes "pods" {
        role = "pod"
      }

      discovery.relabel "pods" {
        targets = discovery.kubernetes.pods.targets

        rule {
          source_labels = ["__meta_kubernetes_namespace"]
          target_label  = "namespace"
        }
        rule {
          source_labels = ["__meta_kubernetes_pod_name"]
          target_label  = "pod"
        }
        rule {
          source_labels = ["__meta_kubernetes_pod_container_name"]
          target_label  = "container"
        }
      }

      loki.source.kubernetes "pods" {
        targets    = discovery.relabel.pods.output
        forward_to = [loki.write.default.receiver]
      }

      loki.write "default" {
        endpoint {
          url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push"
        }
      }

      // ============================================================
      // OTLP Receiver (replaces OTel Collector)
      // ============================================================
      otelcol.receiver.otlp "default" {
        grpc { endpoint = "0.0.0.0:4317" }
        http { endpoint = "0.0.0.0:4318" }

        output {
          metrics = [otelcol.processor.batch.default.input]
          logs    = [otelcol.processor.batch.default.input]
        }
      }

      otelcol.processor.batch "default" {
        timeout = "10s"

        output {
          metrics = [otelcol.exporter.prometheus.default.input]
          logs    = [otelcol.exporter.loki.default.input]
        }
      }

      otelcol.exporter.prometheus "default" {
        forward_to = [prometheus.remote_write.default.receiver]
      }

      prometheus.remote_write "default" {
        endpoint {
          url = "http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090/api/v1/write"
        }
      }

      otelcol.exporter.loki "default" {
        forward_to = [loki.write.default.receiver]
      }

controller:
  type: daemonset

tolerations:
  - key: "node-role.kubernetes.io/control-plane"
    operator: "Exists"
    effect: "NoSchedule"
    
 # 배포
 helm upgrade --install alloy grafana/alloy \
  -n monitoring \
  -f alloy-values.yaml \
  --wait --timeout 5m

 

 

  • Log Collection 파이프라인: Kubernetes Pod를 디스커버리하고, namespace/pod/container 라벨을 부착한 뒤 Loki로 전송
  • OTLP 파이프라인: gRPC(4317)/HTTP(4318)로 텔레메트리를 수신하여 메트릭은 Prometheus로, 로그는 Loki로 라우팅
  • DaemonSet 배포: 모든 노드에서 동작하여 로그 누락 없이 수집
# Step 3: kube-prometheus-stack 배포 (Prometheus + Grafana)
## kube-prometheus-stack은 Prometheus Operator, Prometheus 인스턴스, Grafana, AlertManager, Node Exporter, kube-state-metrics를 한 번에 배포하는 통합 차트이다.
## `kube-prometheus-stack-values.yaml`:

# Prometheus Operator
prometheusOperator:
  nodeSelector:
    kubernetes.io/hostname: "master-node"
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"

# Prometheus
prometheus:
  prometheusSpec:
    retention: "15d"
    nodeSelector:
      kubernetes.io/hostname: "master-node"
    tolerations:
      - key: "node-role.kubernetes.io/control-plane"
        operator: "Exists"
        effect: "NoSchedule"

# Grafana
grafana:
  adminPassword: "admin"
  nodeSelector:
    kubernetes.io/hostname: "master-node"
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"
  service:
    type: NodePort
    nodePort: 30000
  additionalDataSources:
    - name: Loki
      type: loki
      url: "http://loki.monitoring.svc.cluster.local:3100"
      access: proxy
      isDefault: false
    - name: FlexRIC
      type: grafana
      url: "http://192.168.56.30:3000"
      access: proxy
      isDefault: false

# Alertmanager
alertmanager:
  alertmanagerSpec:
    nodeSelector:
      kubernetes.io/hostname: "master-node"
    tolerations:
      - key: "node-role.kubernetes.io/control-plane"
        operator: "Exists"
        effect: "NoSchedule"

# kube-state-metrics
kube-state-metrics:
  nodeSelector:
    kubernetes.io/hostname: "master-node"
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"

# Node Exporter (DaemonSet - 모든 노드에서 실행)
nodeExporter:
  tolerations:
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"

# Kubernetes 시스템 컴포넌트 모니터링
kubelet:
  enabled: true
kubeApiServer:
  enabled: true
kubeControllerManager:
  enabled: true
kubeScheduler:
  enabled: true
kubeEtcd:
  enabled: true
  
# 배포
helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  -n monitoring \
  -f kube-prometheus-stack-values.yaml \
  --wait --timeout 10m

 

  • retention: 15d — 메트릭 데이터 15일 보존
  • Grafana NodePort 30000 — 외부에서 `http://192.168.56.50:30000`으로 접근
  • additionalDataSources — Grafana에 Loki와 FlexRIC 데이터소스를 자동 프로비저닝
  • nodeSelector/tolerations — 모든 Stateful 컴포넌트를 master 노드에 배치
  • Kubernetes 시스템 모니터링 — kubelet, apiserver, scheduler, etcd ServiceMonitor 자동
# Step 4: MongoDB Exporter 배포
## Free5GC의 MongoDB 인스턴스 메트릭을 수집하기 위한 Exporter이다.
## `mongodb-exporter-values.yaml`:

mongodb:
  uri: "mongodb://mongodb.free5gc.svc.cluster.local:27017"

serviceMonitor:
  enabled: true
  namespace: monitoring
  interval: 30s
  additionalLabels:
    release: kube-prometheus-stack

nodeSelector:
  kubernetes.io/hostname: "master-node"

tolerations:
  - key: "node-role.kubernetes.io/control-plane"
    operator: "Exists"
    effect: "NoSchedule"

# 배포

helm upgrade --install mongodb-exporter prometheus-community/prometheus-mongodb-exporter \
  -n monitoring \
  -f mongodb-exporter-values.yaml \
  --wait --timeout 3m

 

  • `additionalLabels`에 `release: kube-prometheus-stack`을 설정하면,
    Prometheus Operator가 이 ServiceMonitor를 자동으로 인식하여 스크래핑 대상에 추가한다.
# Step 5: Free5GC PodMonitor 적용
## ree5GC NF Pod 중 `/metrics` 엔드포인트를 노출하는 Pod들의 메트릭을 자동 수집하기 위한 PodMonitor를 적용한다.
## `free5gc-podmonitor.yaml`:

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: free5gc-nf-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  namespaceSelector:
    matchNames:
      - free5gc
  selector:
    matchLabels:
      project: free5gc
  podMetricsEndpoints:
    - port: metrics
      path: /metrics
      interval: 30s

# 적용:
kubectl apply -f free5gc-podmonitor.yaml

 

 

위를 기반으로 yaml 파일과 배포 자동화 스크립트(.sh)를 생성하였다.

 

 

최종적으로 배포 결과는 다음과 같다.

 

모든 Pod가 Running 상태이며, Alloy가 4개 노드에 각각 DaemonSet으로 배포된 것을 확인할 수 있다.

 

Service의 목록은 다음과 같다.

 

 

Grafana 대시보드 접속 및 메트릭 조회


Grafana가 NodePort 30000으로 외부에 노출되어 있다.

 

따라서 <서버IP>:30000으로 Grafana로 접속할 수 있다.

기본 아이디와 패스워드는 - ID: admin, - PW: admin이다.

 

 

데이터소스 확인


Settings > Data Sources에서 다음 3개의 데이터소스가 자동 프로비저닝되어 있다.

 

1. Prometheus (default) — `http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090`

2. Loki — `http://loki.monitoring.svc.cluster.local:3100`

3. FlexRIC — `http://192.168.56.30:3000`

 

 

메트릭 조회 (Explore)


Home > Explore에서 Prometheus 데이터소스를 선택하고 Metric browser를 클릭하면 수백 개의 메트릭을 조회할 수 있다.

주요 메트릭 예시는 아래와 같다.

  • `node_cpu_seconds_total` — 각 노드의 CPU 사용 시간
  • `node_memory_MemAvailable_bytes` — 가용 메모리
  • `container_cpu_usage_seconds_total` — 컨테이너별 CPU 사용량
  • `kubelet_running_pods` — 노드별 실행 중인 Pod 수

 

이때 특정 노드를 필터링하려면 라벨을 조건으로 추가한다. 

node_cpu_seconds_total{instance="192.168.56.51:9100", mode="idle"}

 

 

 

로그 조회 (Loki)


Explore에서 Loki 데이터소스를 선택하고 LogQL로 조회한다:

 

이처럼 PromQL과 LogQL 명령어를 사용해서,

Free5GC와 관련된 Pod들의 메트릭을 한눈에 확인하기 위한 대시보드를 구성할 수 있다.

  1. CPU/Memory Usage per NF: 각 NF(AMF, SMF, UPF 등)의 리소스 사용량
  2. MongoDB Operations: connections, opcounters, storage 메트릭
  3. Network I/O: 각 NF Pod의 네트워크 트래픽
  4. Pod Restart Count: NF Pod의 재시작 횟수 (안정성 모니터링)

 

 

FlexRIC KPM 데이터 연동


마지막으로 OAI FlexRIC의 KPM(Key Performance Measurement) 데이터를 중앙 Grafana에서 함께 확인할 수 있다.

연동 방식은 FlexRIC 내장 Grafana(`192.168.56.30:3000`)를 중앙 Grafana의 Grafana 타입 데이터소스로 등록하는 것이다.

이를 통해 FlexRIC의 기존 대시보드와 패널을 그대로 활용하면서,

코어 네트워크 메트릭과 RAN 메트릭을 한 화면에서 비교할 수 있다.

 

 

따라서 이번에 구성한 모니터링 스택의 구성 요소와 역할을 정리하면 다음과 같다.

구성 요소 역할 Chart Version
kube-prometheus-stack Prometheus + Grafana + Alertmanager 통합 배포 86.2.0
Loki 로그 저장 및 인덱싱 (SingleBinary 모드) 7.0.0
Grafana Alloy 로그 수집 + LTOP 수신/라우팅
(DaemonSet)
1.8.2
MongoDB Exporter Free5GC MongoDB 메트릭 노출 3.20.0
PodMonitor Free5GC NF/metrics 엔드포인트
자동 scraping
-

 

기존 모니터링 스택인 Promtail + OpenTelemetry Collector 조합에서,

최신 아키텍처인 Grafana Alloy로 통합하여 관리 포인트를 줄이고 설정을 단순화했다.

모든 컴포넌트는 Helm 차트와 자동화 스크립트를 통해 재현 가능하게 배포되며, 단일 명령으로 설치/삭제가 가능하다.