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 버튼 등록
토큰 입력 방법
- http://localhost:8080/swagger-ui/index.html 접속
- 우측 상단 🔒 Authorize 클릭
- 로그인 API 응답으로 받은 accessToken 입력 (Bearer 없이 토큰만)
- Authorize 클릭 후 닫기
'💻 PROJECT > Team Projects' 카테고리의 다른 글
| [ 🚚 ONESTOP ] Spring Data JPA 집계 쿼리 - @Query, JPQL, N+1 트레이드오프 (0) | 2026.05.19 |
|---|---|
| [ 🚚 ONESTOP ] CI/CD부터 관리자 API까지 - 기술 선택의 이유 (0) | 2026.05.18 |
| [ 🚚 ONESTOP ] 정책 설계 — 옵션 중복 방지와 상태 관리 (0) | 2026.05.15 |
| [ 🚚 ONESTOP ] Docker Compose + GitHub Actions로 팀 개발 환경 & CI 구축하기 (0) | 2026.05.14 |
| [ 🚚 ONESTOP ] Spring Boot 프로젝트 기술 선택 이유 정리 (0) | 2026.05.13 |