IT/.NET

[.NET] - 서버 모니터링 및 데이터 시각화(Prometheus, Jaeger, Grafana) 구현 - 1

justdo2t 2024. 12. 13. 16:26

개요

  이 글에서는 OpenTelemetry를 통해 시스템에서 발생하는 트레이스와 메트릭 데이터를 수집하고, 이 를 PrometheusJaeger로 각각 관리한 후, Grafana를 활용해 데이터를 시각화하는 과정을 설명하려고 한다.

이 과정은 시스템 성능의 전반적인 모니터링과 더불어 API 요청의 병목 현상을 효과적으로 분석하는 데 필수적인 역할을 한다.

OpenTelemetry를 통해 .NET Core 앱에서 발생하는 Metric 및 Trace를 수집 및 변환하여 Prometheus 및 Jaeger에 exporting 한다.

이후 exporting된 데이터들을 Grafana를 통해 시각화하여 직관적으로 추적 가능하게 한다.

 

전체적인 흐름은 아래와 같다.

 

 

 

 

1. NET CORE App 구성

1-1. Nuget 패키지 구성

기본 설정으로 구성된 초기 상태에서 Nuget 패키지를 설치한다.

 

 

위 리스트에 있는 OpenTelemetry, Prometheus 패키지를 내려받는다.

 

패키지 구성

더보기

OpenTelemetry

OpenTelemetry OpenTelemetry .NET SDK로 메트릭과 트레이스를 수집하기 위한 기본 패키지.

 

OpenTelemetry.Exporter.Jaeger

→ OpenTelemetry 데이터를 Jaeger로 내보내는 패키지 (현재 더 이상 사용되지 않음, 다른 프로토콜 사용 권장).

 

OpenTelemetry.Extensions.Hosting

→ Microsoft.Extensions.Hosting 기반 애플리케이션에서 OpenTelemetry를 시작하는 확장 도구.

 

OpenTelemetry.Instrumentation.AspNetCore

ASP.NET Core 애플리케이션에서 OpenTelemetry 트레이싱을 추가하는 도구.

 

OpenTelemetry.Instrumentation.Http

→ HTTP 클라이언트 요청을 트레이싱하기 위한 OpenTelemetry 도구.

 

OpenTelemetry.Instrumentation.Runtime

→ .NET 런타임에 대한 성능 메트릭과 트레이싱을 추가하는 도구.

 

prometheus-net.AspNetCore

ASP.NET Core 애플리케이션에서 Prometheus 메트릭을 수집하고 Prometheus 서버와 연동할 수 있도록 하는 도구.

 

 

2. 미들웨어 설정

// 커스텀 미들웨어
public static void ConfigMetricAndTrace(this IServiceCollection services)
{
    // OpenTelemetry 설정을 추가 (Tracing과 Metrics 기능 포함)
    services.AddOpenTelemetry()
        // Tracing 설정 부분
        .WithTracing(tracerProviderBuilder =>
        {
            tracerProviderBuilder
                // 리소스 빌더를 사용해 트레이싱 데이터를 보낼 때 서비스 이름을 설정
                .SetResourceBuilder(
                    ResourceBuilder.CreateDefault()
                                   .AddService("my-service-name")  
                )
                // ASP.NET Core에서 발생하는 HTTP 요청 및 응답 트레이싱을 추가
                .AddAspNetCoreInstrumentation()
                // HttpClient에서 발생하는 요청에 대한 트레이싱을 추가
                .AddHttpClientInstrumentation()
                // 샘플러를 AlwaysOnSampler로 설정하여 모든 트레이스를 수집
                .SetSampler(new AlwaysOnSampler())
                // Jaeger로 트레이스 데이터를 전송하는 설정
                .AddJaegerExporter(o =>
                {
                    // Jaeger의 호스트 주소를 설정 (로컬호스트로 설정)
                    o.AgentHost = "localhost"; 
                    // Jaeger의 에이전트 포트 설정 (기본값: 6831)
                    o.AgentPort = 6831;         
                });
        })
        // Metrics 설정 부분
        .WithMetrics(metricProviderBuilder =>
        {
            // 리소스 빌더를 사용해 메트릭 데이터를 보낼 때 서비스 이름을 설정
            metricProviderBuilder
                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("my-service-name"))
                // ASP.NET Core에서 발생하는 메트릭 데이터를 수집
                .AddAspNetCoreInstrumentation() 
                // HttpClient에서 발생하는 메트릭 데이터를 수집
                .AddHttpClientInstrumentation()  
                // .NET 런타임에서 발생하는 메트릭 데이터를 수집
                .AddRuntimeInstrumentation()    
                // Prometheus Exporter를 사용해 메트릭 데이터를 Prometheus로 전송
                .AddPrometheusExporter();        
        });
}  

// 추가 미들웨어
// Prometheus 엔드포인트를 제공하는 미들웨어
app.UseOpenTelemetryPrometheusScrapingEndpoint();

위와 같이 미들웨어를 설정함으로써 Metric과 trace 데이터를 수집할 준비가 완료되었다.

 

 

3. Jaeger, Prometheus, Grafana 컨테이너 생성

3-1. Docker Compose 설치

  1 ~ 2번 과정에서 Metric, Trace 데이터를 전송을 했다면, 위 3번 과정에서는 데이터를 받는 작업을 진행한다. Jaeger와 Prometheus를 통해 각각의 수집 데이터를 확인한다.

 

먼저 윈도우 운영체제에서 Docker Desktop을 설치하면 dockerdocker-compose가 모두 설치된다. 설치는 여기에서 하면 된다.

 

만약, 개발 환경 운영체제가 다르다면 여기를 참고해서 설치해.

 

설치가 되었다면 아래와 같이 버전을 확인해보자.

 

3-2. Docker Compose 설정

  Docker-compose.yaml 파일은 기본적으로 설정 파일이며, 사용하길 원하는 디렉토리에 위치 시키면 된다.

services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - ./prometheus/config/:/etc/prometheus/
      - ./prometheus/prometheus-volume:/prometheus
    ports:
      - 9090:9090
    command: 
      - '--web.enable-lifecycle'
      - '--config.file=/etc/prometheus/prometheus.yml'
    restart: always
    networks:
      - promnet
  grafana:
    image: grafana/grafana
    container_name: grafana
    depends_on:
      - prometheus
    ports:
      - 3000:3000
    volumes:
      - ./grafana/grafana-volume:/var/lib/grafana # volumes 설정한다면 이부분 주석처리
      - ./grafana/grafana-init.ini:/etc/grafana/grafana.ini
    restart: always
    networks:
      - promnet
  jaeger:
    image: jaegertracing/all-in-one:1.6
    container_name: jaeger
    environment:
      - COLLECTOR_ZIPKIN_HTTP_PORT=9411
    ports:
      - "5775:5775/udp"
      - "6831:6831/udp"
      - "6832:6832/udp"
      - "5778:5778"
      - "16686:16686"
      - "14268:14268"
      - "9411:9411"
    restart: always
    networks:
      - promnet
networks:
  default:
    name: gopaddle_gopaddle-extension-desktop-extension_default
  promnet:
    driver: bridge

이미지 버전, 마운트 디렉터리 경로, 재시작 옵션 등은 본인의 프로젝트에 맞게 바꿔서 설정해도 상관없다.

 

설정이 잘 적용 되었는지 확인이 필요할 경우, 아래 커맨드로 쉽게 접근이 가능하다.

$ docker-compose config

파일 생성이 완료되었다면, 이제 컨테이너를 실행시키면 된다.

 

# 모든 서비스 실행
$ docker-compose up -d[선택사항] 

# 특정 서비스 실행
$ docker-compose up -d[선택사항] [실행시킬 서비스 이름]

-d는 컨테이너 백그라운드에서 실행시켜준다. 위 설정을 생략하게 된다면, 실행 로그들이 무수히 출력 되는 상황을 마주할 수 있게 될 것 이다.

 

서비스들을 다 실행시켰으면, 잘 실행이 되고 있는지 확인을 해보자.

 

$ docker ps

 위 커맨드는 현재 실행되고 있는 컨테이너들의 리스트를 확인할 수 있다.

모든 상태(멈춤, 재시작, 실행, … 등)를 확인하고 싶으면 $ docker ps -a 커맨드를 활용하자.

 

정상적으로 실행되고 있는 모습을 확인할 수 있다.