spring:
application:
name: practice
server:
port: 8080
#모든 엔드포인트 노출 설정
management:
endpoints:
web:
exposure:
include: *
endpoint:
#헬스 체크 엔드포인트 상세 정보 표시 설정
health:
show-details: always # 기본값은 never
show-details 설정을 when_authorized 옵션을 통해서 인증된 사용자에게만 제공하는 옵션을 사용하는 것이 좋다.# 애플리케이션의 기본 포트를 8080으로 설정
server.port=8080
# Actuator 엔드포인트를 19090 포트에서 서비스하도록 설정
management.server.port=19090
management:
endpoints:
web:
exposure:
include: *
endpoint:
#헬스 체크 엔드포인트 상세 정보 표시 설정
health:
show-details: always
# 이 설정은 /actuator/health 엔드포인트에서 헬스 체크 정보를 항상 상세히 보여주도록 설정합니다. 기본적으로, 헬스 체크 엔드포인트는 요약된 상태 정보만 제공하며, 상세 정보는 노출되지 않습니다.
prometheus:
enabled: true

해당 엔드포인트로 접근하면 매트릭스를 확인할 수 있다.
global:
scrape_interval: 15s # 메트릭 수집 간격
scrape_configs:
- job_name: 'spring-boot'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
15초 간격으로 /actuator/premetheus 엔트포인트에서 메트릭을 수집하는 옵션입니다.
targets 에서 host.docker.internal 는 Docker 에서 제공하는 특수한 DNS 이름으로, Docker 컨테이너가 호스트 머신(즉, Docker 를 실행하는 컴퓨터)의 네트워크 서비스에 접근할 수 있게 한다.
이를 통해 컨테이너 내부에서 호스트 머신의 네트워크 주소를 참조할 수 있다.
version: '3.8'
services:
prometheus:
image: prom/prometheus
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
추후 다른 설정도 추가하기 위해 docker-compose 파일로 작성했다.

다음처럼 localhost:9090 으로 접속하면 프로메테우스 서버에 접속할 수 있다.
Status -> Target 로 접속하면 스프링 애플리케이션 매트릭스를 수집하고 있는 것을 확인할 수 있다.
version: '3.8'
services:
prometheus:
image: prom/prometheus
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
container_name: grafana
ports:
- "3000:3000"
depends_on:
- prometheus

localhost:3000 으로 접속하면 기본 계정 admin/admin 으로 접속할 수 있다.

datasource 에서 prometheus 를 등록할 수 있고,

추후 운영상황에서 적용할 보안설정이나, 여러 추가 설정또한 존재한다. 현재는 연습용이기에 연결만 적용.

다음으론 그라파나의 대시보드 생성을 확인해보면, grafana.com 으로 접속해서 제공하고있는 여러 템플릿을 확인해볼 수 있다.

접속해서 확인해보면 이런식으로 이미 잘 구성해놓은 대시보드들이 존재한다.
JVM, spring, jdbc, kafka, rabbitMQ, mysql, ... 등등 여러 잘만들어진 대시보드들을 제공하고 있기에 잘 가져다 쓰기만 하면 된다!

카피해서 붙여넣기하고, prometheus로 설정하면 대시보드가 잘 생성된다.

uptime, cpu 사용률, 메모리, GC, db connection, http, logback 등 엄청나게 다양한 메트릭을 대시보드로 제공해준다. 해당 값들을 확인해서 조정하는 부분은 아직 공부가 필요한 것 같다..
이번엔 그라파나를 슬랙과 알림을 연동해보자.

기본 Alerting -> Contact points 로 접속해면 기본 email로 알림이 설정되어있다.

여기서 생성을 통해 slack을 설정하고, webhook을 등록해주면 된다.
(slack api webhook 생성은 생략)

다음으로 Alerting > Notification policies 에서 Default policy의 edit 을 통해 기본 설정을 내가 만든 slack 알림으로 설정해준다.

그다음 Alerting > Alert rules > New alert rule 에 들어가서 Metric은 up Label filters 는 job에 spring-boot 로 설정해준다. 그리고 Threshold Input 타입을 A로, IS BELOW 는 1로 설정해준다면, 스프링부트 어플리케이션이 정지되는 순간 알림을 보낼 수 있다.

또한 다음 설정을 통해 1m 으로 설정해주면 springboot의 상태를 1분마다 확인하는 옵션을 설정한다.

최종 알림을 내가 만든 slack-alert로 설정해주면 스프링부트 애플리케이션이 중지되고, 실행될 때 마다 알림을 발송하게 된다.

이처럼 알림을 확인해 볼 수 있다.
지금은 서버가 다운되었을 때를 확인해보았는데, 만약 운영 상태라면 서버가 죽었다면 이미 너무 늦은 알림이 아닐까 싶다.. 서버가 죽기전에 여러 메트릭에 대해 한계점을 설정해 해당 값이 넘게되면 경고 알림을 계속 보내도록 하는게 더 효율적일 것 같다.
여튼 별도의 agent 설정 필요없이 쉽게 로그를 Loki로 전송할 수 있게하는 라이브러리이다.
implementation 'com.github.loki4j:loki-logback-appender:1.5.1'
@GetMapping("/")
public String hello(HttpServletResponse response) throws IOException {
logger.info("Attempted access to / endpoint resulted in 403 Forbidden");
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
return null;
}
<configuration>
<appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
<http>
<url>http://localhost:3100/loki/api/v1/push</url>
</http>
<format>
<label>
<pattern>app=my-app,host=${HOSTNAME}</pattern>
</label>
<message class="com.github.loki4j.logback.JsonLayout" />
</format>
</appender>
<root level="DEBUG">
<appender-ref ref="LOKI" />
</root>
</configuration>
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2020-10-24
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
#
# Statistics help us better understand how Loki is used, and they show us performance
# levels for most users. This helps us prioritize features and documentation.
# For more information on what's sent, look at
# https://github.com/grafana/loki/blob/main/pkg/analytics/stats.go
# Refer to the buildReport method to see what goes into a report.
#
# If you would like to disable reporting, uncomment the following lines:
#analytics:
# reporting_enabled: false
위 설정은 Loki 공식 페이지에서 제공하는 방법이다.
다음 링크로 접속하면 바로 복/붙 가능하다.
https://raw.githubusercontent.com/grafana/loki/v3.0.0/cmd/loki/loki-local-config.yaml
docker run --name loki -d -v ${loki-config.yml 이 저장된 폴더}:/mnt/config -p 3100:3100 grafana/loki:3.0.0 -config.file=/mnt/config/loki-config.yml
loki-config.yml 파일이 프로메테우스 설정 파일과 다른 폴더에 존재해서 그냥 docker run 명령어로 실행시켰다.


다음 엔트포인트로 접속하면 상태를 확인할 수 있다.

이번엔 그라파나에서 loki 를 연결시켜 보자.

Explore 페이지에서 Loki 선택해서 app -> my-app Line filters에 Line Contains 를 통해서 로그의 필터를 적용할 수 있다.
위 그림에서처럼 controller 에서 발생한 로그를 필터링을 통해 확인할 수 있다.
Prometheus, Grafana 는 굉장히 많이 들어본 모니터링 툴이였는데, 이번에 써보니까 확실히 사람들이 많이 사용함에 있어서 자료도 많고, 대시보드 템플릿도 다양하게 제공하고 있었다.
오픈소스라 그런지 확실히 참고할 자료도 많고, 사용하기도 쉬웠다.
Loki는 이번에 처음 듣고, 사용해보았다.
일반적으로 로그를 수집하고 활용하는 시스템은 Elasticsearch를 중심으로 ELK(Elasticsearch, Logstash, Kibana) 가 일반적으로 사용된다.
하지만, Elasticsearch 를 사용하면 그만큼 시스템 요구사항과 관리가 필요하고, 클러스터의 크기가 증가할수록 관리 비용도 증가하게 된다.
그에비해 Grafana Labs에서 정의한 Loki의 특징은
이러한 장점으로 k8s 상에 설치해서 사용하기에도 용이하다.
또한 메타정보만 인덱스하도록 강제되어 있기에, 전체 설정을 통해 구성하는 elasticsearch에 비해 빠르고 간결해 적은 저장소를 필요로 하는 장점이 있다.
(하지만, 전체 탐색에 있어서는 elasticsearch 보다 느리다.)

또한 이번에 사용한 것 처럼 Spring Boot에 좋은 라이브러리가 존재하기에 연동하기도 쉽다.
2023 년 글에 의하면 배민에서도 ELK Stack에서 Loki로 전환했다고 한다!!
확실히 요즘엔 k8s 가 유행하면서 해당 환경에서 적합한 기술들이 각광받고 있는 것 같다.