1. Spring Boot 운영 환경 설정
https://docs.spring.io/spring-boot/reference/actuator/enabling.html
Enabling Production-ready Features :: Spring Boot
To add the actuator to a Maven-based project, add the following starter dependency:
docs.spring.io
스프링 공식 문서에는 운영 환경에서 스프링에 무엇을 세팅해야 하는지 소개하고 있다.
첫 문서에서는 spring actuator 가 등장한다.
spring actuator 를 사용하면 스프링 부트에서 지원하는 운영 환경 설정을 쉽게 할 수 있다고 한다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
공식 문서 안내에 따라 의존성을 추가한다.
actuator 를 활성화하면 스프링 어플리케이션을 모니터링 하는데 필요한 여러 기능을 사용할 수 있다.
다음으로 스프링 메트릭 모니터링을 위해서 모니터링 도구에 맞는 메트릭 설정을 추가한다.
(메트릭 = 모니터링하는데 필요한 지표 데이터들)
스프링 부트에서 지원하는 모니터링 도구는 매우 다양한데, 그 중에서 prometheus 를 사용해보기로 했다.
다른 프로젝트에서 프로메테우스를 쓰고 있는데, 중간에 합류했다보니 왜 사용하는지도 궁금했고,
직접 세팅해보는 것도 처음이라서 공부해보고 싶었기 때문이다.
Metrics :: Spring Boot
Spring Boot auto-configures a composite MeterRegistry and adds a registry to the composite for each of the supported implementations that it finds on the classpath. Having a dependency on micrometer-registry-{system} in your runtime classpath is enough for
docs.spring.io
Metrics 문서의 Prometheus 섹션을 참고하여 설정하였다.
우선, 프로메테우스는 기본적으로 스프링의 actuator endpoint 를 주기적으로 호출하여 metrics 데이터를 수집하는데
이 endpoint 는 기본적으로 닫혀있어서 직접 열어주어야 한다고 한다.
이 문서를 참고하여 endpoint 를 열어주자.
우선 엔드포인트의 경우, HTTP 또는 JMX 를 통해 노출되며, 이 엔트포인트를 통해 특정 정보들을 조회할 수 있도록 만들 수 있다.
다만 이 정보들은 서버의 민감한 정보를 포함하므로 외부에서 접근할 수 없도록 막는 것이 중요하다.
(JMX는 Java Monitoring eXtensions 의 줄임말로, 자바에서 제공하는 모니터링 툴을 말한다)
management:
endpoints:
web:
exposure:
include: "prometheus"
위와 같이 application.yml 에 작성하여 프로메테우스 엔트포인트를 활성화시켜준다.
그리고 /actuator/prometheus 엔트포인트에 접근할 수 있도록 스프링 시큐리티에서 허용해준다.

다음으로 공식문서에 따르면 prometheus 엔드포인트를 열기 위해서는 micrometer-registry-prometheus 의존성이 필요하다고 한다.
Maven Repository 에서 의존성을 찾아 추가해준다.
dependencies {
implementation 'io.micrometer:micrometer-registry-prometheus'
}
버전은 자동으로 호환되는 버전을 가져오도록 명시하지 않았다.
이제 어플리케이션을 실행하고 http://localhost:8080/actuator/prometheus 경로로 접속해보면

다음과 같이 메트릭 정보를 조회할 수 있다.
2. Actuator 보안 설정
actuator 는 서버의 민감한 정보를 포함할 수 있기 때문에 보안 설정을 추가로 달아두는 것이 좋다.
보안 설정은 이 링크와 GPT 코드를 양쪽으로 참고하면서 작성하였다.
management:
server:
port: 8081
endpoints:
access:
default: none
web:
exposure:
include: "health, prometheus"
jmx:
exposure:
exclude: "*"
endpoint:
health:
access: read_only
prometheus:
access: read_only
우선 Opt-In 방식으로 기본으로는 모든 설정을 막아두되, 내가 허용하려는 actuator 만 readonly를 허용하도록 설정하였다.
(Opt-In = 모두 비허용하고 내가 허용하려는 옵션만 포함 = 화이트리스트)
(Opt-Out = 모두 허용하고 내가 비허용하려는 옵션만 제외 = 블랙리스트)
또한 actuator API 에는 프로메테우스 서버만 접근할 수 있도록 외부에 공개된 8080이 아닌 8081 포트로 접근하도록 포트 설정을 바꿔주었다.
다음으로 actuator API 에 접근할 때 인증된 사용자만 접근할 수 있도록 시큐리티 설정을 추가하였다.
actuator:
prometheus:
username: "${ACTUATOR_PROMETHEUS_USERNAME}"
password: "${ACTUATOR_PROMETHEUS_PASSWORD}"
인증 방식은 간단하게 기본 로그인 방식을 사용할 예정이므로, 위와 같이 username, password 를 환경변수로 받아준다.
@Bean
@Order(1)
public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint())
.csrf(AbstractHttpConfigurer::disable)
.httpBasic(Customizer.withDefaults())
.authorizeHttpRequests(auth -> auth.requestMatchers(EndpointRequest.to("health"))
.permitAll()
.requestMatchers(EndpointRequest.to("prometheus"))
.hasRole("PROMETHEUS")
.anyRequest()
.denyAll());
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
그리고 위와 같이 시큐리티 설정을 분리하여 적용해주었다.
일반 API 는 JWT 인증을 타야하고, actuator 는 서버 내부적으로만 돌아가므로 매번 토큰을 발급받는 것은 비효율적이라고 판단하여 시큐리티가 기본 제공하는 http basic 방식의 로그인으로 인증하도록 구현하였다.
이 과정에서 http.securityMatcher() 메서드의 역할을 학습할 수 있었다.
이 옵션으로 API 요청이 들어왔을 때 어떤 filter chain 을 탈지 시큐리티가 결정한다.
3. Prometheus 서버 설정
프로메테우스는 스프링과 별개 어플리케이션으로 모니터링 지표를 직접 수집하는 서버이다.
엄밀하게 운영하려면 스프링 어플리케이션과 분리하여 띄우는 것이 맞으나 (스프링 어플리케이션이 띄워져있는 인스턴스가 죽었다고 모니터링까지 같이 죽으면 안되므로..), 현재는 비용 문제로 인해 같은 인스턴스 안에 도커 컨테이너를 분리하여 띄웠다.
https://prometheus.io/docs/prometheus/latest/installation/
Installation | Prometheus
Prometheus project documentation for Installation
prometheus.io
도커를 사용하면 간단하게 프로메테우스 서버를 띄울 수 있다.
공식 문서에서는 docker run 명령어를 알려주고 있는데, 매번 이렇게 실행시키기는 불편하므로 docker compose 파일에 프로메테우스를 추가로 정의하였다.
prometheus:
container_name: prometheus
image: "prom/prometheus"
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
이때 프로메테우스 설정을 외부에서 지정할 수 있도록 위와 같이 설정 파일을 볼륨으로 연결하였다.
이제 docker compose 파일이 있는 곳에 prometheus.yml 파일을 만들고 다음과 같이 내용을 작성하였다.
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["prometheus:9090"]
- job_name: "spring"
metrics_path: "/actuator/prometheus"
basic_auth:
username: <USER NAME>
password: <PASSWORD>
static_configs:
- targets: ["server:8081"]
targets 의 경우, 프로메테우스 컨테이너와 스프링 컨테이너가 같은 도커로 띄워져 있기 때문에 스프링 컨테이너 이름인 server 를 통해 네트워크 연결하도록 설정하였다.
(실제 제대로 운영하는 환경이라면 프로메테우스와 스프링은 인스턴스를 분리하는 것이 좋겠지만, 현재 이 세팅은 개발 서버에서 하고 있어서 같은 인스턴스에서 컨테이너만 분리하여 실행하도록 하였다)
4. Grafana 설정
프로메테우스가 스프링 actuator 엔드포인트를 호출하여 메트릭을 수집하는 역할을 수행한다면, grafana 는 프로메테우스가 수집한 메트릭을 보기 좋게 시각화하는 툴이다.
그라파나 역시 도커로 간단하게 띄울 수 있다.
grafana:
container_name: grafana
image: grafana/grafana
ports:
- "3000:3000"
environment:
GF_SERVER_ROOT_URL: https://dev-api.carebridges.kr/monitoring/
GF_SERVER_SERVE_FROM_SUB_PATH: "true"
나의 경우, 별도 인스턴스로 띄운 것이 아니였기 때문에
기존 api 서버에 모니터링용 path 를 붙여서, /monitoring 경로로 들어오는 요청을 그라파나로 보내도록 웹서버를 설정하였다.
그리고 그라파나에서는 이 경로로 온 요청을 root 로 보도록 위와 같이 설정하였다.
이렇게 설정하고 GF_SERVER_ROOT_URL 로 접속하면 그라파나 로그인 창이 뜬다.
초기 아이디와 비밀번호는 admin 이다.
로그인에 성공하면 비밀번호를 설정하도록 되어있으므로 비밀번호를 변경해준다.

그라파나와 프로메테우스를 연동하기 위해 Connection - Add new connection 탭으로 이동한다.

prometheus 를 검색한다.
나의 경우 이미 설치가 되어있었다.

prometheus 를 클릭하면 플러그인 상세화면으로 들어갈 수 있다.
Add new data source 를 클릭한다.

Connection 항목의 url 을 위와 같이 작성해주었다.
(그라파나와 프로메테우스가 같은 도커 컨테이너에서 돌고 있었기 때문에 컨테이너 이름으로 호스트를 적었다)

이제 이 데이터소스를 기반으로 대시보드를 생성한다.
Dashboards 탭으로 이동 후, New 버튼을 클릭하고, Import 를 클릭한다.
새로 만들기를 하면 대시보드에서 조회할 항목 패널을 일일히 설정해야 해서 매우 귀찮다.

4701 을 입력하고 Load 하자.

대시보드 이름을 자유롭게 짓고, 맨 하단 DS_PROMETHEUS 항목에서 아까 생성한 데이터소스를 지정한 뒤에 Import 버튼을 클릭한다.

나의 경우, 이렇게 빨간 느낌표 화면들이 주르륵 나왔다.
마우스를 갖다대면 DS_PROMETHEUS 값을 찾을 수 없다고 나온다...

우측 상단 Edit 버튼을 클릭

Settings 클릭

Variables 탭으로 이동한다.
기본적으로 지정된 변수들이 존재한다.
참고로 application 변수의 경우, 위와 같은 흐름대로 따라왔다면 지정되어있지 않을 것이다.
application.yml 에서 application 태그를 추가하거나 (정석)
프로메테우스 설정 파일에서
relabel_configs:
- target_label: application
replacement: spring
이렇게 applictation 태그를 임의로 달아주면 된다.
이렇게 안하면 패널 설정값 들어가서 일일히 application 필터를 지워줘야 한다..
다시 본론으로 돌아와서 지금 문제는 DS_PROMETHEUS 변수가 없는 것이 문제이다.
위 이미지 하단의 Renamed or missing variables 를 펼쳐보면 이 변수가 들어있는 것이 보인다.
(분명 설정했는데 없다고 뜬다. 킹받는다..)
어쩔 수 없이 직접 변수를 만들어주자.
New Variable 버튼을 클릭한다.

Variable type 은 Data source
Name 은 DS_PROMETHEUS
Data source options 의 Type 은 Prometheus 로 지정하고 저장한다.

application 변수까지 잘 설정했다면 위와 같이 모든 메트릭이 잘 보인다.
'WEB(BE) > Spring & Spring Boot' 카테고리의 다른 글
| @SQLDelete와 TransientObjectException 예외 (0) | 2026.03.08 |
|---|---|
| [Redis] READONLY You can't write against a read only replica. 에러 해결기 (feat. 중국) (0) | 2025.08.06 |
| JAVA 값 객체의 동등 비교 ('==' 과 equals() 의 차이) (0) | 2025.03.08 |
| [Swagger] Failed to load API definition (403, 500, NoSuchMethodError) (3) | 2025.01.22 |
| [Spring Boot] application.yml 데이터베이스 연결 정보 입력 (0) | 2025.01.06 |