안녕하세요. J4J입니다.
이번 포스팅은 kubernetes에서 spring 애플리케이션 metric 수집하여 prometheus와 grafana를 이용한 모니터링 방법에 대해 적어보는 시간을 가져보려고 합니다.
관련 글
Kubernetes 모니터링을 위한 Prometheus, Grafana 개념 정리
Kubernetes 모니터링을 위한 Prometheus, Grafana 개념 정리
안녕하세요. J4J입니다. 이번 포스팅은 kubernetes 모니터링을 위한 prometheus, grafana 개념에 대해 적어보는 시간을 가져보려고 합니다. Kubernetes 모니터링이 필요한 이유 kubernetes 환경에서 여러 개의 po
jforj.tistory.com
Kubernetes 모니터링 구축: Helm으로 kube-prometheus-stack 설치하기 (Docker Desktop)
Kubernetes 모니터링 구축: Helm으로 kube-prometheus-stack 설치하기 (Docker Desktop)
안녕하세요. J4J입니다. 이번 포스팅은 kubernetes 모니터링을 위한 helm으로 kube-prometheus-stack을 설치하는 방법에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 Helm 이란? Helm 입문을 위한 기본
jforj.tistory.com
애플리케이션 모니터링을 위한 Spring Boot Actuator: 개념 정리와 구성 가이드
애플리케이션 모니터링을 위한 Spring Boot Actuator: 개념 정리와 구성 가이드
안녕하세요. J4J입니다. 이번 포스팅은 애플리케이션 모니터링을 위한 spring boot actuator 개념 정리 및 구성 가이드에 대해 적어보는 시간을 가져보려고 합니다. Spring Boot Actuator 개념 spring boot actuato
jforj.tistory.com
애플리케이션 Metric 수집 Flow
kubernetes에 배포되는 애플리케이션 내부에서 metric을 수집하기 위해서 필요한 것은 다음과 같습니다.
[ Spring Boot ]
- Spring Actuator
- Prometheus Micrometer
[ Kubernetes 내부 서비스 ]
- Prometheus
- Grafana
- ServiceMonitor
그리고 metric 수집을 위한 flow는 다음과 같이 이루어집니다.

여기서 한 가지 알고 가야 될 점은 spring 내부에 metric 정보를 수집하기 위해 사용되는 actuator와 micrometer의 경우 일반적인 상황에서 모두 동일한 방식으로 활용될 수 있습니다.
하지만 kubernetes 내부 service monitor를 이용한 metric scrape 하는 과정은 구축하는 환경마다 다를 수 있습니다.
이번 글에서는 Kubernetes 모니터링 구축: Helm으로 kube-prometheus-stack 설치하기 (Docker Desktop)에서 설정했던 kube-promethues-stack을 기반으로 환경 구성을 진행합니다.
Kubernetes 모니터링 구축: Helm으로 kube-prometheus-stack 설치하기 (Docker Desktop)
안녕하세요. J4J입니다. 이번 포스팅은 kubernetes 모니터링을 위한 helm으로 kube-prometheus-stack을 설치하는 방법에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 Helm 이란? Helm 입문을 위한 기본
jforj.tistory.com
kube-prometheus-stack 기반으로 구성을 하게 되면 service monitor CRD 구성을 위한 별도 과정 필요 없이 리소스 정보만을 구성하여 즉시 사용할 수 있습니다.
하지만 prometheus와 grafana 등을 모두 개별적으로 구성하고 있었다면 service monitor 사용 환경을 위한 구성 방식에 대해서 추가적으로 확인이 필요하실 겁니다.
Metric 수집 애플리케이션 구축
이번에는 metric을 수집하는 애플리케이션을 구축하여 kubernetes에 배포해 보도록 하겠습니다.
간단한 케이스로 사용자 로그인이 이루어진 것에 대한 metric 수집을 해보겠습니다.
[ 1. dependency 설정 ]
// build.gradle
dependencies {
// spring actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// micrometer prometheus
implementation 'io.micrometer:micrometer-registry-prometheus'
}
[ 2. application resource 설정 ]
// application.yml
management:
endpoints:
web:
exposure:
include: prometheus, metrics # actuator web endpoint 노출 설정
endpoint:
prometheus:
access: unrestricted # prometheusa endpoint 접근 제한 설정
[ 3. metric 수집 class 작성 ]
// dto
package com.jforj.kubernetsmetric.dto;
public record LoginRequest(
String userId
) {
}
// controller
package com.jforj.kubernetsmetric.controller;
import com.jforj.kubernetsmetric.dto.LoginRequest;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class LoginController {
private final MeterRegistry meterRegistry;
@PostMapping("/login")
public ResponseEntity<Object> login(@RequestBody LoginRequest loginRequest) {
List<String> loginUserIds = List.of("1234", "5678");
if (!loginUserIds.contains(loginRequest.userId())) {
collectLoginCounterMetric(loginRequest.userId(), false, "로그인 할 수 있는 사용자 아이디가 존재하지 않습니다.");
return ResponseEntity.ok("Login Failed.");
}
collectLoginCounterMetric(loginRequest.userId(), true, null);
return ResponseEntity.ok("Login Success.");
}
/**
* login counter metric 수집
*
* @param userId 사용자 아이디
* @param loginSuccess 로그인 성공 여부
* @param errorMessage 에러 메세지
*/
private void collectLoginCounterMetric(String userId, boolean loginSuccess, String errorMessage) {
Counter.builder("login_request") // metric 명
.description("login request success/error counter metric information.") // metric description
.tag("class", this.getClass().getName()) // metric label
.tag("userId", userId) // metric label
.tag("loginSuccess", String.valueOf(loginSuccess)) // metric label
.tag("errorMessage", StringUtils.hasText(errorMessage) ? errorMessage : "N/A") // metric label
.register(meterRegistry) // counter 집계에 사용되는 registry 등록
.increment(); // 1만큼 데이터 증가
}
}
[ 4. metric 수집 확인 ]
metric 수집을 확인하기 전 metric 정보가 수집될 수 있도록 다음과 같은 api 요청을 전달해 보겠습니다.



metric이 수집된 것인지를 확인하기 위해서는 로컬 환경 기준 http://localhost:8080/actuator/prometheus으로 접근하여 확인할 수 있습니다.
올바르게 데이터가 수집된 경우에는 다음과 같이 로그인 요청한 횟수에 맞게 상황 별 데이터가 적재되어 있는 것이 확인됩니다.

Kubernetes 배포
애플리케이션 설정이 완료되었다면 kube-prometheus-stack 이 설치되어 있는 kubernetes에 함께 배포가 이루어져야 합니다.
다만 이곳에서 인지할 점 중 하나는 service monitor라는 것을 이용하여 metric scrape 과정이 이루어집니다.
그래서 최소 svc, deployment에 대한 리소스 설정이 이루어진 뒤 애플리케이션 배포가 이루어지면 됩니다.
배포 방식은 어떤 것을 선택하더라도 상관없습니다.
저는 간단하게 다음과 같이 kube-prometheus-stack이 설치되어 있는 docker desktop에 배포해 보겠습니다.
[ 1. jar 파일 생성 ]
gradle의 bootJar 명령어를 이용하여 jar 파일을 생성합니다.
올바르게 동작할 경우 프로젝트의 /build/libs 경로에 jar 파일 하나가 생성되어 있습니다.


[ 2. Dockerfile 정의 ]
jar 파일은 복사하여 별도 폴더에 보관합니다.
그리고 jar 파일이 있는 동일한 경로에 다음과 같이 Dockerfile을 정의합니다.
Dockerfile은 프로젝트 상황에 맞는 설정을 해주시면 됩니다.
// Dockerfile
FROM openjdk:24-jdk
COPY ./*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
[ 3. docker image 생성 ]
mac에서는 command, window에서는 cmd를 오픈한 뒤 Dockerfile이 있는 경로로 이동해 줍니다.
그리고 다음 명령어를 통해 docker image를 생성합니다.
$ docker build -t kubernetes-metric-app .
[ 4. kubernetes resource 파일 설정 ]
// kubernetes-metric-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubernetes-metric-app
labels:
app: kubernetes-metric-app
namespace: monitoring # namespace를 사용하는 경우 설정
spec:
replicas: 1
selector:
matchLabels:
app: kubernetes-metric-app
template:
metadata:
labels:
app: kubernetes-metric-app
spec:
containers:
- name: kubernetes-metric-app
image: kubernetes-metric-app:latest # Dockerfile로 build한 image 설정
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: kubernetes-metric-app
labels:
app: kubernetes-metric-app
namespace: monitoring # namespace를 사용하는 경우 설정
spec:
selector:
app: kubernetes-metric-app
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
[ 5. kubernetes 애플리케이션 배포 ]
docker image와 동일하게 mac에서는 command, window에서는 cmd를 오픈한 뒤 deployment yaml 파일이 있는 경로로 이동해 줍니다.
그리고 kubectl을 이용하여 resource 파일 기반 애플리케이션 배포를 수행합니다.
$ kubectl apply -f kubernetes-metric-app-deployment.yaml
[ 6. metric 수집 처리 ]
kubernetes에 애플리케이션 배포가 완료되었다면 로컬에서 했던 방식과 동일하게 metric 수집이 이루어질 수 있도록 요청을 전달합니다.
배포되어 있는 곳 또한 "[애플리케이션 도메인]/actuator/prometheus"에 접근하면 수집된 metric 정보를 확인할 수 있습니다.
ServiceMonitor 구축
이번에는 service monitor를 kubernetes에 구축해 보겠습니다.
service monitor는 위에서 flow로 가볍게 표현된 것처럼 특정 svc에 존재하는 metric 정보를 scrape 하여 prometheus에 저장될 수 있도록 도와주는 역할을 수행합니다.
그래서 service monitor에 애플리케이션의 metric endpoint 경로를 알려주고, 원하는 prometheus에 수집될 수 있도록 설정해 보겠습니다.
[ 1. kubernetes resource 파일 설정 ]
// kubernetes-metric-app-service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kubernetes-metric-app-service-monitor
namespace: monitoring # namespace를 사용하는 경우 설정
labels:
release: kube-prometheus-stack # kube-prometheus-stack helm 설치할 때 사용한 helm name 작성
spec:
selector:
matchLabels:
app: kubernetes-metric-app # application svc name 작성
namespaceSelector:
matchNames:
- monitoring # namespace를 사용하는 경우 설정
endpoints:
- port: http
path: /actuator/prometheus
interval: 15s # metric scrape 주기 설정
[ 2. kubernetes에 배포 ]
mac에서는 command, window에서는 cmd를 오픈한 뒤 service monitor yaml 파일이 있는 경로로 이동해 줍니다.
그리고 kubectl을 이용하여 service monitor를 kubernetes에 생성해 줍니다.
$ kubectl apply -f kubernetes-metric-app-service-monitor.yaml
[ 3. service monitor 설정 확인 ]
service monitor가 올바르게 구성되어 있는지는 prometheus에 접근하여 확인할 수 있습니다.
"[prometheus 도메인]/targets"에 접근하면 다음과 같이 위에서 추가한 service monitor가 올바르게 동작하고 있다는 것을 확인할 수 있습니다.

Grafana 대시보드 구성
prometheus의 target에 올바르게 확인이 된다면 grafana 대시보드를 구성해볼 수 있습니다.
kubernetes 내부에 사용되고 있는 grafana에 접근한 뒤 Dashboards 메뉴에 접속하여 New 버튼을 통해 새로운 대시보드를 생성합니다.

New dashboard를 클릭하면 다음과 같이 화면이 나오고, Add visualization을 클릭해 줍니다.

data source는 당연히 함께 사용되고 있는 prometheus를 선택합니다.

올바르게 metric 정보가 수집되고 있다면 metric을 선택하는 칸에서 login_request_total이라는 정보를 확인할 수 있습니다.
그리고 Run queries를 누르면 시계열 데이터를 기반으로 한 수집된 metric 정보를 아래와 같이 패널에서 확인이 가능합니다.

애플리케이션 Metric 수집 방식
지금까지 애플리케이션 내부에서 metric 수집을 위해 counter meter를 활용했었습니다.
사실 prometheus micrometer에서는 counter 외에도 다른 방식들을 제공해주고 있습니다.
Prometheus Micrometer Graphing을 확인해 보면 다음 종류들을 확인할 수 있습니다.
- Counter
- Timer
- Long task timers
Micrometer Prometheus :: Micrometer
Prometheus is a dimensional time series database with a built-in UI, a custom query language, and math operations. Prometheus is designed to operate on a pull model, periodically scraping metrics from application instances, based on service discovery. Micr
docs.micrometer.io
이 외에도 라이브러리 내부를 확인해보면 Gauge, DistributionSummary 등 제공해 주는 인터페이스가 더 다양하게 존재합니다.
어떤 목적의 metric을 수집하고 싶은 것인지에 따라 사용되는 meter 정보가 달라지게 됩니다.
한 가지 더 소개하려고 하는 것 중 하나는 어노테이션 기반으로 metric 수집하는 방식입니다.
위에서는 라이브러리에서 제공해주는 인터페이스로 builder 패턴을 활용하여 원하는 형태의 metric을 수집하는 방식이었습니다.
하지만 이 방법 외에도 어노테이션을 이용하여 더 편리하게 metric을 수집할 수 있는 방법이 존재합니다.
다만, 어노테이션을 사용한다고 모든 경우에 대해 사용되는 것이 아니기에 상황에 따라 적절하게 사용해 보시면 좋을 것 같습니다.
사용 방식에 대해서 간단히만 소개하려고 합니다.
사용되는 어노테이션은 observation을 이용한 방식으로 대표적으로 @Observed, @Timed 등이 존재합니다.
@Observed를 예시로 다음과 같이 추가적인 설정을 순차적으로 적용하여 사용해볼 수 있습니다.
[ 1. dependency 설정 ]
// build.gradle
dependencies {
// observation 사용을 위해 aop 설정
implementation 'org.springframework.boot:spring-boot-starter-aop'
}
[ 2. application resource 설정 ]
// application.yml
management:
observations:
annotations:
enabled: true # observation annotation 사용 설정
[ 3. @Observed 설정 ]
필요한 method의 상위에 다음과 같이 어노테이션을 추가해볼 수 있습니다.
public class LoginController {
@Observed(
name = "api_flow", // metric 명
contextualName = "loginController.login", // trace/span 표기 명
lowCardinalityKeyValues = {"step", "presentation"} // metric label
)
@PostMapping("/login")
public ResponseEntity<Object> login(@RequestBody LoginRequest loginRequest) {
...
}
}
[ 4. 수집되는 metric 확인 ]
어노테이션이 추가된 상태에서 /actuator/prometheus에 접속하여 수집된 metric을 확인해 보겠습니다.
그러면 다음과 같이 active 형태의 observation이 관찰 진행 중인 정보에 대해서 표현되는 것도 확인할 수 있고, 호출이 완료된 것에 대해서도 확인할 수 있습니다.

참고 사항으로 만약 @Timed를 사용한다고 하더라도 유사한 구조로 metric 정보가 확인됩니다.
다만 @Observed는 @Timed와 다르게 metric 정보에다가 tracing, logging 정보가 함께 사용될 수 있는 어노테이션이라는 차이점이 존재합니다.
이상으로 kubernetes에서 spring 애플리케이션 metric 수집하여 prometheus와 grafana를 이용한 모니터링 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Spring > SpringBoot' 카테고리의 다른 글
| RestTemplate 말고 이거 사용하세요: RestClient 입문 가이드 (0) | 2025.12.12 |
|---|---|
| Micrometer Tracing으로 Spring 애플리케이션 분산 트레이싱하기 (3) | 2025.09.29 |
| 애플리케이션 모니터링을 위한 Spring Boot Actuator: 개념 정리와 구성 가이드 (1) | 2025.09.10 |
| [SpringBoot] Kafka로 분산형 데이터 처리하기 (5) - SpringBoot에 Kafka Consumer 사용 환경 설정 (2) | 2025.06.29 |
| [SpringBoot] Kafka로 분산형 데이터 처리하기 (4) - SpringBoot에 Kafka Producer 사용 환경 설정 (0) | 2024.09.17 |
댓글