💻 PROJECT/Team Projects

[ 🚚 ONESTOP ] Spring Boot 모니터링(Prometheus + Grafana) + Swagger JWT 인증 설정

eunjiom 2026. 5. 21. 20:10

1. 모니터링 — Prometheus + Grafana

왜 모니터링이 필요한가?

  • 서비스 운영 중에 CPU, 메모리, HTTP 요청 수, 응답 시간, DB 커넥션 풀 상태 등을 수치로 파악하지 못하면 장애가 발생했을 때 원인을 찾기 어렵다.
  • 특히 커머스 서비스는 주문/결제 흐름이 복잡해서 병목 지점을 모니터링으로 사전에 파악하는 게 중요하다.

기술 선택 이유 — Prometheus + Grafana

  • Spring Boot Actuator가 /actuator/prometheus 엔드포인트로 메트릭을 Prometheus 포맷으로 노출하면, Prometheus가 주기적으로 수집(scrape)하고, Grafana가 시각화하는 구조다.
  • Spring Boot와 공식 연동: micrometer-registry-prometheus 의존성 하나로 JVM, HikariCP, HTTP 요청, Spring Security 필터 체인까지 별도 코드 없이 자동 수집된다.
  • 오픈소스 무료: 상용 APM(New Relic, Datadog)은 트래픽 기반 과금이라 사이드 프로젝트에서 부담스럽다. Prometheus + Grafana는 완전 무료다.
  • 대시보드 생태계: Grafana 커뮤니티에 Spring Boot 전용 대시보드(Dashboard ID: 4701, 12900 등)가 공유되어 있어 import 한 번으로 바로 쓸 수 있다.

다른 선택지와 비교

도구 특징 적합한 상황
Prometheus + Grafana 오픈소스, 풀링 방식, 시계열 DB 자체 서버 운영, 비용 절감
Datadog SaaS, 에이전트 방식, 풍부한 기능 팀 규모가 크고 예산 있을 때
New Relic SaaS, APM 특화 코드 레벨 성능 분석 필요할 때
CloudWatch AWS 네이티브 AWS 인프라에 올인한 경우
ELK Stack 로그 분석 특화 메트릭보다 로그 중심 모니터링

설정 코드

  • application-local.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics, prometheus
  endpoint:
    prometheus:
      enabled: true
    health:
      show-details: when-authorized
  • monitoring/prometheus.yml (프로젝트 루트)
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'one-stop'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['host.docker.internal:8080']
  • docker-compose.yml 추가
prometheus:
  image: prom/prometheus:latest
  container_name: one-stop-prometheus
  ports:
    - "9090:9090"
  volumes:
    - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
  extra_hosts:
    - "host.docker.internal:host-gateway"

grafana:
  image: grafana/grafana:latest
  container_name: one-stop-grafana
  ports:
    - "3000:3000"
  environment:
    - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER}
    - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
  volumes:
    - grafana-data:/var/lib/grafana
  depends_on:
    - prometheus

prometheus.yml을 src 안에 넣지 않은 이유

  • prometheus.yml은 Java 코드가 아니라 Prometheus 컨테이너가 읽는 인프라 설정 파일이다
  • Spring 앱과 관계가 없으므로 docker-compose.yml과 같은 레벨에 monitoring/ 폴더를 만들어 관리했다
  • 인프라 설정과 애플리케이션 코드를 분리하는 게 유지보수에 좋다.

코드 리뷰봇 피드백 반영

1. Grafana 계정 하드코딩 → 환경변수 분리

  • 처음에 GF_SECURITY_ADMIN_USER=admin, GF_SECURITY_ADMIN_PASSWORD=admin을 docker-compose.yml에 직접 작성했다
  • 리뷰봇이 보안 취약점으로 지적했고, .env 파일로 분리했다. .env는 .gitignore에 포함되어 있어 깃허브에 올라가지 않고 팀 내에서 슬랙으로 공유했다.
# 수정 전
environment:
  - GF_SECURITY_ADMIN_USER=admin
  - GF_SECURITY_ADMIN_PASSWORD=admin

# 수정 후
environment:
  - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER}
  - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}

 

2. management.metrics.export.prometheus.enabled Deprecated 경고 제거

  • Spring Boot 3.x에서 해당 설정이 Deprecated됐다. micrometer-registry-prometheus 의존성만 있으면 자동 활성화되므로 해당 설정 라인을 제거했다.

3. health.show-details: always → when-authorized

  • always로 설정하면 비인증 사용자도 DB, Redis 연결 상태 등 내부 정보를 볼 수 있다. 운영 환경 보안을 위해 JWT 토큰을 보유한 인증된 사용자만 상세 정보를 조회할 수 있도록 when-authorized로 변경했다.

2. Swagger — JWT 인증 버튼 추가 (SpringDoc OpenAPI)

왜 필요했는가?

  • 팀원이 Swagger UI에서 API를 테스트할 때 JWT 토큰을 어디에 입력해야 하는지 몰라 혼선이 생겼다
  • SwaggerConfig에 SecurityScheme을 추가하면 우측 상단에 🔒 Authorize 버튼이 생기고, 토큰을 한 번 입력하면 모든 API 요청 헤더에 Authorization: Bearer {token}이 자동으로 붙는다.

기술 선택 — SpringDoc OpenAPI

  • Spring Boot 3.x에서 Swagger를 사용하는 방법은 두 가지다.
라이브러리 특징
SpringDoc OpenAPI Spring Boot 3.x 공식 지원, 활발한 유지보수
Springfox Spring Boot 2.x 시대 주류, 3.x 미지원
  • Spring Boot 3.x 프로젝트이므로 SpringDoc을 선택했다.

설정 코드

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI openAPI() {
        SecurityScheme securityScheme = new SecurityScheme()
            .type(SecurityScheme.Type.HTTP)
            .scheme("bearer")
            .bearerFormat("JWT")
            .in(SecurityScheme.In.HEADER)
            .name("Authorization");

        SecurityRequirement securityRequirement = new SecurityRequirement()
            .addList("bearerAuth");

        return new OpenAPI()
            .info(new Info()
                .title("OneStop API")
                .description("쿠팡 클론 커머스 플랫폼 API")
                .version("v1.0"))
            .addSecurityItem(securityRequirement)
            .components(new Components()
                .addSecuritySchemes("bearerAuth", securityScheme));
    }
}

 

각 설정의 의미

  • SecurityScheme.Type.HTTP + scheme("bearer") — HTTP Bearer 토큰 방식임을 명시
  • bearerFormat("JWT") — 문서 표시용 힌트 (실제 검증에 영향 없음)
  • SecurityRequirement.addList("bearerAuth") — 전역으로 모든 API에 인증 적용
  • components().addSecuritySchemes(...) — Swagger UI에 Authorize 버튼 등록

토큰 입력 방법

  1. http://localhost:8080/swagger-ui/index.html 접속
  2. 우측 상단 🔒 Authorize 클릭
  3. 로그인 API 응답으로 받은 accessToken 입력 (Bearer 없이 토큰만)
  4. Authorize 클릭 후 닫기