배너 이미지

Prometheus & Grafana 기반 Springboot 모니터링 구축(with 401에러)

2025. 5. 8. 22:46·CS공부/인프라

🎯 목표

Spring Boot 기반 서버의 메트릭 데이터를 Prometheus로 수집하고, Grafana를 통해 시각화 및 대시보드를 구성합니다. 본 구축기는 도커 컴포즈(Docker Compose)를 사용하여 Prometheus + Grafana를 빠르게 구축하는 과정을 다룹니다.


✅ 시스템 구성 개요

구성 요소 역할

Prometheus Spring Boot 애플리케이션의 메트릭을 수집 및 저장 (Pull 방식)
Grafana Prometheus에서 수집된 메트릭을 시각화하는 대시보드 툴
Spring Boot /actuator/prometheus 엔드포인트를 통해 메트릭을 노출

⚙️ Docker Compose 설정

docker-compose.yml
version: '3.3'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus-entrypoint.sh:/prometheus-entrypoint.sh
    entrypoint: ["/prometheus-entrypoint.sh"]
    environment:
      - BASIC_AUTH_USERNAME=${PROMETHEUS_USERNAME}
      - BASIC_AUTH_PASSWORD=${PROMETHEUS_PASSWORD}
      - PROMETHEUS_RETENTION_TIME=${PROMETHEUS_RETENTION_TIME}
    extra_hosts:
      - "host.docker.internal:host-gateway"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana-datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-ssafy}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-ssafypw}
      - GF_USERS_ALLOW_SIGN_UP=false
    depends_on:
      - prometheus

volumes:
  grafana-data: {}

🔧 Prometheus 설정 파일

prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'spring-boot'
    metrics_path: '/actuator/prometheus'
    basic_auth:
      username: '********'
      password: '********'
    static_configs:
      - targets: ['host.docker.internal:8080']
  • scrape_interval: 메트릭 수집 주기
  • spring-boot job에서는 Spring Boot Actuator 엔드포인트로부터 메트릭을 가져옵니다.

📁 Grafana 데이터 소스 설정

grafana-datasources.yml
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true

🛠 Spring Boot 설정 방법

Spring Boot에서 Prometheus가 메트릭을 수집할 수 있도록 하기 위해 다음과 같은 설정이 필요합니다.

1. 의존성 추가

build.gradle

dependencies {
    implementation 'io.micrometer:micrometer-registry-prometheus'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

2. application.yml 설정

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  endpoint:
    prometheus:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
server:
  port: 8080

보안 설정이 필요한 경우 Spring Security 또는 nginx 리버스 프록시에서 기본 인증을 적용할 수 있습니다.


🚀 실행 방법

docker-compose up -d
  • http://localhost:9090 → Prometheus 접속
  • http://localhost:3000 → Grafana 접속

🔍 대시보드 구성 예시

Grafana 접속 후:

  1. 좌측 메뉴 → Dashboards → New Dashboard
  2. Panel 추가 → PromQL 쿼리 입력 예시:
    • rate(http_server_requests_seconds_count[1m])
    • jvm_memory_used_bytes{area="heap"}

❌ 문제 발생 과정 및 해결 정리

1. ❗ Prometheus에서 /actuator/prometheus 요청 → 401 Unauthorized

  • 원인: Spring Boot에 Spring Security Basic 인증이 설정되어 있어 인증 필요

2. JWT 필터 충돌

  • 원인: JwtAuthenticationFilter가 모든 요청에 적용되고 있었음
  • 설명: Prometheus 요청은 Basic Auth를 사용하지만, JWT 필터가 먼저 실행되면서 인증 실패 처리됨
  • 해결 방법: 필터의 예외 처리 조건 추가
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    String path = request.getRequestURI();
    String authHeader = request.getHeader("Authorization");

    return path.equals("/actuator/prometheus") ||
           (authHeader != null && authHeader.startsWith("Basic "));
}

🔄 문제 해결 흐름 정리 (정확한 순서 기반)

단계 문제 또는 원인 조치 또는 해결 방법

1 JWT 필터가 Basic 인증 요청까지 가로챔 JwtAuthenticationFilter.shouldNotFilter()에서 /actuator/prometheus 또는 Basic 헤더 요청을 우회 처리
2 Spring Security의 BCrypt 인코딩 비밀번호와 Prometheus 평문이 일치하지 않음 securepassword를 BCrypt로 인코딩하여 .env에 등록하고 application.yml에서 환경변수로 사용
3 인증 성공 curl -u admin:securepassword http://localhost:8080/actuator/prometheus → 200 OK 확인. Prometheus 정상 수집, Grafana 시각화 정상 작동

✅ 학습 정리

  • Prometheus는 Exporter가 노출하는 메트릭을 Pull 방식으로 수집합니다.
  • Grafana는 다양한 시각화 Panel과 경고(Alert)를 구성할 수 있는 강력한 도구입니다.
  • 도커 컴포즈를 활용하면 Prometheus와 Grafana 환경을 빠르게 구축하고 관리할 수 있습니다.

📊 Prometheus & Grafana 모니터링 시스템 구축기


🎯 목표

Spring Boot 기반 서버의 메트릭 데이터를 Prometheus로 수집하고, Grafana를 통해 시각화 및 대시보드를 구성합니다. 본 구축기는 도커 컴포즈(Docker Compose)를 사용하여 Prometheus + Grafana를 빠르게 구축하는 과정을 다룹니다.


✅ 시스템 구성 개요

구성 요소 역할

Prometheus Spring Boot 애플리케이션의 메트릭을 수집 및 저장 (Pull 방식)
Grafana Prometheus에서 수집된 메트릭을 시각화하는 대시보드 툴
Spring Boot /actuator/prometheus 엔드포인트를 통해 메트릭을 노출

⚙️ Docker Compose 설정

docker-compose.yml
version: '3.3'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml.template:/etc/prometheus/prometheus.yml.template
      - ./prometheus-entrypoint.sh:/prometheus-entrypoint.sh
    entrypoint: ["/prometheus-entrypoint.sh"]
    environment:
      - BASIC_AUTH_USERNAME=${PROMETHEUS_USERNAME}
      - BASIC_AUTH_PASSWORD=${PROMETHEUS_PASSWORD}
      - PROMETHEUS_RETENTION_TIME=${PROMETHEUS_RETENTION_TIME}
    extra_hosts:
      - "host.docker.internal:host-gateway"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana-datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-ssafy}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-ssafypw}
      - GF_USERS_ALLOW_SIGN_UP=false
    depends_on:
      - prometheus

volumes:
  grafana-data: {}

🔧 Prometheus 설정 파일 (템플릿)

prometheus.yml.template
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'spring-boot'
    metrics_path: '/actuator/prometheus'
    basic_auth:
      username: '********'
      password: '********'
    static_configs:
      - targets: ['host.docker.internal:8080']
  • scrape_interval: 메트릭 수집 주기
  • spring-boot job에서는 Spring Boot Actuator 엔드포인트로부터 메트릭을 가져옵니다.

📁 Grafana 데이터 소스 설정

grafana-datasources.yml
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true

🛠 Spring Boot 설정 방법

Spring Boot에서 Prometheus가 메트릭을 수집할 수 있도록 하기 위해 다음과 같은 설정이 필요합니다.

1. 의존성 추가

build.gradle

dependencies {
    implementation 'io.micrometer:micrometer-registry-prometheus'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

2. application.yml 설정

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  endpoint:
    prometheus:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
server:
  port: 8080

보안 설정이 필요한 경우 Spring Security 또는 nginx 리버스 프록시에서 기본 인증을 적용할 수 있습니다.


🚀 실행 방법

docker-compose up -d
  • http://localhost:9090 → Prometheus 접속
  • http://localhost:3000 → Grafana 접속 (기본 계정: ******** / ********)

🔍 대시보드 구성 예시

Grafana 접속 후:

  1. 좌측 메뉴 → Dashboards → New Dashboard
  2. Panel 추가 → PromQL 쿼리 입력 예시:
    • rate(http_server_requests_seconds_count[1m])
    • jvm_memory_used_bytes{area="heap"}

❌ 문제 발생 과정 및 해결 정리

1. ❗ Prometheus에서 /actuator/prometheus 요청 → 401 Unauthorized

  • 원인: Spring Boot에 Spring Security Basic 인증이 설정되어 있어 인증 필요

2. ❗ JWT 필터 충돌로 Prometheus 요청이 인증 실패

  • 원인: Spring Boot에 JwtAuthenticationFilter가 전역 설정되어 있음
  • 문제: Prometheus는 Basic Auth를 사용하지만, Authorization 헤더가 Bearer 토큰이 아니라서 JWT 필터에서 인증 실패 처리됨
  • 해결 방법: JwtAuthenticationFilter에서 Basic 요청을 예외 처리
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    String path = request.getRequestURI();
    String authHeader = request.getHeader("Authorization");

    return path.equals("/actuator/prometheus") ||
           (authHeader != null && authHeader.startsWith("Basic "));
}

❗ 3. BCrypt 비밀번호 미스매치로 인증 실패


📌 문제 요약

Prometheus에서 /actuator/prometheus 엔드포인트에 Basic 인증을 시도했지만 401 Unauthorized 응답이 발생함.


🔍 원인 상세

문제의 핵심은 Spring Boot의 기본 설정 때문이 아닌, BCryptPasswordEncoder를 명시적으로 등록했기 때문.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // ⬅ 이 설정
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // ...
    }
}

Spring Boot는 기본적으로 DelegatingPasswordEncoder를 사용하여 {noop}, {bcrypt} 등의 prefix를 인식합니다.
하지만 위처럼 BCryptPasswordEncoder를 직접 설정하면 해시된 비밀번호만 허용하고 평문은 무조건 실패하게 됩니다.

즉, .env에 securepassword처럼 평문 비밀번호를 넣으면 인증 실패가 발생합니다.


✅ 해결 방법

1. securepassword를 BCrypt 해시로 인코딩

System.out.println(new BCryptPasswordEncoder().encode("securepassword"));

2. .env에 인코딩된 해시값 등록

PROMETHEUS_PASSWORD=$2a$10$QzMOCvObdKx34ovliGn4qO9EcRMLMpFGJBaZKD5UsO2ZfJP5GABcu

3. application.yml에서 환경 변수 참조

spring:
  security:
    user:
      name: ${PROMETHEUS_USERNAME}
      password: ${PROMETHEUS_PASSWORD}
      roles: PROMETHEUS

🔁 Prometheus 설정은 그대로 유지

basic_auth:
  username: 'admin'
  password: 'securepassword'  # 평문 그대로 유지 (Prometheus는 해시를 모름)

🔍 정상 동작 확인

Prometheus가 securepassword를 평문으로 전송하면,
Spring Boot에서 BCryptPasswordEncoder.matches()를 통해 해시와 비교하여 인증 성공.

curl -u admin:securepassword http://localhost:8080/actuator/prometheus
# 응답: 200 OK

✅ 이렇게 하면 Spring Boot에서 Prometheus의 Basic 인증 요청을 올바르게 처리할 수 있습니다.

 

🧾 최종 마무리 및 운영 팁

  • Prometheus는 Pull 방식으로 /actuator/prometheus에서 메트릭을 수집하므로, 해당 엔드포인트는 반드시 외부 접근 가능해야 하고, 인증도 적절히 처리되어야 합니다 .
  • Spring Security를 사용하는 경우, Basic 인증과 JWT 인증 필터의 우선순위 충돌을 명확히 제어해야 합니다 .
  • BCryptPasswordEncoder를 명시적으로 사용하는 경우, Prometheus 쪽은 평문, Spring Boot 쪽은 해시를 사용해야 한다는 점을 반드시 구분해서 관리해야 합니다.
  • docker-compose, .env, application.yml, prometheus.yml 설정들이 모두 맞물려 있어야 인증과 메트릭 수집이 원활하게 동작합니다 .

'CS공부 > 인프라' 카테고리의 다른 글

VS Code 원격 개발 환경 구성: SSH 키로 원격 서버 접속하기  (1) 2025.09.01
모니터링 시스템 비교: ELK vs Prometheus & Grafana  (0) 2025.05.08
동기 vs 비동기 & 메시지 브로커 개념 정리  (0) 2025.05.01
OAuth2 인증 로직 및 Google 기반 구현  (0) 2025.04.27
GitHub 웹훅 기반 Jenkins CI/CD 파이프라인 설계  (0) 2025.04.23
'CS공부/인프라' 카테고리의 다른 글
  • VS Code 원격 개발 환경 구성: SSH 키로 원격 서버 접속하기
  • 모니터링 시스템 비교: ELK vs Prometheus & Grafana
  • 동기 vs 비동기 & 메시지 브로커 개념 정리
  • OAuth2 인증 로직 및 Google 기반 구현
quokkaST
quokkaST
  • quokkaST
    stquokka
    quokkaST
    • 개발자 (77)
      • n8n (2)
      • CS공부 (46)
        • Java & Spring (15)
        • 인프라 (7)
        • 운영체제 & 시스템 (9)
        • 기타 CS지식 (7)
        • 네트워크 (6)
        • 데이터베이스 (2)
      • 알고리즘 (16)
      • 프로젝트 (8)
        • 감정&금융챗봇 (8)
      • 리팩토링 (5)
        • horong (5)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
상단으로

티스토리툴바