prometheus, opentelemetry, Loki 를 활용한 모니터링과 grafana 시각화
Spring 대시보드 예제 바로보기
https://grafana.com/grafana/dashboards/17175-spring-boot-observability/
FastAPI 대시보드 예제 바로보기
https://grafana.com/grafana/dashboards/16110-fastapi-observability/
이번 포스팅에선 prometheus, opentelemetry, Loki, grafana를 활용한 모니터링 및 시각화를 다룰 예정이다.
java-spring, python-fastapi 에 붙인 예시이다. 안타깝게도 내가 2주전에 임시저장해놓은 글이 감쪽같이 사라졌기때문에, 간략하게 제시할 것이다.
주요 키워드는 위 세가지지만, 전반적인 툴은 다음과 같다.
- Trace: Tempo, Opentelemetry instrument, Opentelemetry collector
- Metrics: Prometheus, (Spring인경우
- Logs: Loki, Promtail
- Monitoring & Visual Tool: Grafana
난이도는 Loki, Promtail, Prometheus, Grafana는 어플리케이션(프레임워크) 매우 쉽다.
다만 Trace는 프레임워크 별로 라이브러리를 별도로 하는 것 + 설정법이 까다롭기 때문에 실제로 적용이 되었는지 아닌지 판단하기 조금 어렵다.
Prometheus는 수집기 UI에서 Target Health를 확인할 수 있지만, Otel-Collector는 그렇지 않기 때문이다.
몇 가지 인사이트를 정리하고자 한다.
1. Tempo 는 Opentelemetry의 Trace를 수집한다.
Framework (opentelemetry) -> Opentelemetry Collector (otel collector) -> Tempo
2. Framework 마다 Opentelemetry 를 적용하는 방법이 다르다
- Spring https://opentelemetry.io/docs/zero-code/java/spring-boot-starter/getting-started/
- FastAPI https://github.com/blueswen/fastapi-observability/blob/main/fastapi_app/utils.py
나는 Spring이 조금 더 까다로웠다. 실행시 종속성 jar를 붙여야하는데, 제약사항이 꽤 있었기에 까다로웠다.
3. Spring의 경우 Prometheus 적용과 actuator라는 개념의 종속성이 붙는데, FastAPI는 그런게 없다. 난 (이전 포스트) FastAPI로 Prometheus를 구현해봤기에 좀 낯설었지만 크게 다를바가없었다. 그냥 metrics를 노출하는 정도에서 + 알파.
4. Trace 수집도구인 Opentelemetry 는 Spring의 경우 PinPoint와 런타임시 충돌이 난다. 따라서 딱 하나를 정해서 사용해야한다. 나는 Opentelemetry를 권장한다.
5. 나는 서비스에서 FastAPI, Spring 둘다 쓰기에 두 군 데에 모두 다 Observability Dashboard를 적용했다. 매우 만족한다.
https://grafana.com/grafana/dashboards/17175-spring-boot-observability/
https://grafana.com/grafana/dashboards/16110-fastapi-observability/
6. 개요에 대해 개략적으로 설명하자면, Loki는 Promtail에서 전송하는걸 처리하는 곳이다. Tempo는 Otel Collector가 전송하는 것을 처리하는 곳이다. Otel Collector는 각 Framework 에서 전송하는 데이터를 처리하는 곳이다. Prometheus는 각 Application Endpoint를 주기적으로 스크래핑한다.
7. Prometheus는 스크래핑할 endpoint를 정의하는 yaml을 작성해야한다. Otel Collector 또한 yaml을 작성해야하는데, 조금 더 복잡하다. Otel Collector는 작업 명세서를 작성하는 것이다. 여러분이 작성한다면 아래와 비슷할 것이다.
receivers:
otlp:
protocols:
grpc:
endpoint: otel-collector:4317
http:
endpoint: otel-collector:4318
exporters:
otlp/tempo:
endpoint: "tempo:14317" # Tempo로 트레이스 전송
tls:
insecure: true
prometheus:
endpoint: otel-collector:55681
loki:
endpoint: http://loki:3100/loki/api/v1/push
processors:
batch:
timeout: 5s # 데이터를 일정 시간 동안 배치 처리
filter/drop:
traces:
span:
- attributes["http.route"] == "/actuator/prometheus"
- attributes["http.route"] == "/healthz"
connectors:
servicegraph:
extensions:
pprof:
endpoint: otel-collector:1777
service:
pipelines:
traces:
receivers: [otlp] # OpenTelemetry 프로토콜로 트레이스 수신
processors: [filter/drop, batch]
exporters: [otlp/tempo,servicegraph] # Tempo로 트레이스 데이터 내보내기
logs:
receivers: [otlp] # OpenTelemetry 프로토콜로 트레이스 수신
processors: [batch]
exporters: [loki] # Tempo로 데이터 내보내기
metrics:
receivers: [otlp,servicegraph] # OpenTelemetry 프로토콜로 트레이스 수신
processors: [batch]
exporters: [prometheus] # prometheus
좀더 자세한 플러그인들은 https://github.com/open-telemetry/opentelemetry-collector/tree/main 여기서 봐야한다. 여기 github폴더가 정답지이다. ChatGPT도 꽤 옛날 방법을 제시하거나 엉터리를 제시할 것이다.
여기까지 내가 전달할 수 있는 것이다.
아마 K8S-helm 이던, naive하게 docker-compose로 구성하는 가에 따라 작업방법은 다를것인데 구체적인 구현법은 여러분에게 맡긴다. 내 생각엔 기존 서비스에 붙여야한다면 docker compose로 붙이는게 더 쉬울 거 같다. observability set를 구성하는데 암초들이 많을 거라 생각한다. 원치 않는 기능에서의 불필요한 trace 수집(반복적이고 의미없는 웹소켓에 span 수집 등), 기존 종속성과 충돌로 인한 멈춤 등을 고려해보면 일단 쉽게 붙이는게 가장 낫지 않을까 쉽다.
마무리하자면, 강추 강추이고,
더 부연설명을 하는것보다 여러분이 구현하면서 찾아가는게 더 재밌으리라 생각이된다. ^^!
즐 프로그래밍 하시고 원하는 것을 얻으시길.