본문 바로가기

Spring/Ticketing 프로젝트

Spring + Grafana, Loki, Prometheus로 모니터링 시스템 구축하기

반응형

개요

  • Spring + ELK Stack으로 로그 모니터링 시스템을 구축하려 했지만, ElasticSearch가 서버에 너무 무거워서 정상적으로 동작하지 않았습니다. 이에 대한 대안으로 ELK 대신 Loki와 Grafana로 로그 시각화 툴을 구축하고, 추가적으로 Prometheus를 도입해 메트릭또한 수집해 보고자 합니다.
  • 먼저 Grafana, Loki, Promtail을 필요로 하는데, 각 서비스의 역할은 다음과 같습니다.
    1. Grafana: 로그 시각화
    2. Loki: 로그 데이터 저장 및 인덱싱
    3. Prometheus : Spring, MySQL, Nginx등의 매트릭 수집
  • Grafana와 Loki는 별도의 모니터링 서버에 구축하고, Promtail은 Application 서버에 구축하려 합니다.

Grafana + Loki 구축하기

먼저 Grafana와 Loki 서버를 모니터링 서버에 구축해봅니다.

  • docker-compose.yml
version: '3'

services:
  loki:
    image: grafana/loki:2.8.0
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - ./loki-config.yaml:/etc/loki/local-config.yaml
      - ./loki-storage:/loki
  grafana:
    image: grafana/grafana:9.5.1
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=???
    volumes:
      - ./grafana-storage:/var/lib/grafana

 

  • loki-config.yaml
auth_enabled: true

server:
  http_listen_port: 3100
  http_server_read_timeout: 30s
  http_server_write_timeout: 30s
  grpc_server_max_recv_msg_size: 10485760
  grpc_server_max_send_msg_size: 10485760

auth:
  type: basic
  basic:
    username: ??
    password: ??
ingester:
  wal:
    enabled: true
    dir: /loki/wal
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s

schema_config:
  configs:
    - from: 2020-05-15
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /loki/boltdb-shipper-active
    cache_location: /loki/boltdb-shipper-cache
    cache_ttl: 24h
    shared_store: filesystem
  filesystem:
    directory: /loki/chunks

compactor:
  working_directory: /loki/boltdb-shipper-compactor
  shared_store: filesystem

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: false
  retention_period: 0s
  • 설정 파일 파라미터는 아래에서 확인할 수 있습니다. 필요한 부분만 수정하였습니다.
  • 각 설정에 대한 설명은 다음과 같습니다.
    • server: 서버 포트, 패킷 크기, 타임아웃 정의
    • auth: Loki에 업로드하기 위한 인증 정보
    • Ingester: 로그 데이터 수신 및 저장 역할
      • wal: Ingester가 수신한 로그를 로그 형태로 기록 후 전송
      • lifecycler: Ingester의 생명 주기 관리
    • schema_config: BoltDB-Shipper 저장소와 파일 시스템 객체 저장소에 로그 저장
    • Compactor: 저장된 로그 데이터를 최적화 및 압축

Promtail 구축하기

다음으로 application server에 Promtail 컨테이너를 등록하여 Spring에서 설정한 로그 파일을 가져갈 수 있도록 합니다.

  • docker-compose.yml(Spring 서버)
version: '3'
services:
  min-ticketing:
    # ...
    volumes:
      - ./logs:/app/logs
  # ...
  promtail:
    image: grafana/promtail:2.8.0
    container_name: promtail
    volumes:
      - ./logs:/logs
      - ./promtail-conf.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.yml
    depends_on:
      - min-ticketing

어플리케이션 로그가 저장되는 logs 폴더와 promtail이 감시할 logs 폴더에 볼륨을 설정하여 promtail이 로그 파일을 가져가서 Loki로 전송할 수 있도록 하였습니다.

  • promtail-conf.yml
server:
  http_listen_port: 9080
  grpc_listen_port: 0
positions:
  filename: /tmp/positions.yaml

clients:
  - url: ??
    basic_auth:
      username: "??"
      password: "???"
scrape_configs:
  - job_name: spring_application
    static_configs:
      - targets:
          - min_ticketing
        labels:
          job: ticketing_logs
          __path__: /logs/ticketing_*.log
    pipeline_stages:
      - json:
          expressions:
            timestamp: '"@timestamp"'
            level: level
            logger: logger_name
            thread: thread_name
            message: message
      - timestamp:
          source: timestamp
          format: RFC3339Nano
      - labels:
          level:
          logger:
          thread:
  • Promtail 설정으로, LogstashEncoder 기반으로 저장된 어플리케이션 로그를 Promtail에서 파싱하여 전송하도록 설정하였습니다.

Prometheus 설정하기

  • 그 다음으로 Prometheus를 추가해 줄 것인데, 먼저 이전에 Grafana, Loki 컨테이너를 실행하는 docker-compose 파일에 Prometheus를 추가해 줍시다.
version: '3'

services:
	# .....
  prometheus:
    container_name: prometheus
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus-config.yml:/etc/prometheus/prometheus.yml
  • prometheus-config.yml은 다음과 같습니다.
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['spring actuator ip:9090']
  - job_name: 'mysql'
    scrape_interval: 5s
    static_configs:
      - targets: ["mysql exporter ip:9104"]
        labels:
          group: 'mysql'
          service: 'mysql'
  - job_name: 'mysql-node'
    scrape_interval: 5s
    static_configs:
      - targets: ["mysql node exporter ip:9100"]  # Node Exporter의 IP와 포트
        labels:
          group: 'mysql'
          service: 'node'
  - job_name: 'nginx'
    static_configs:
      - targets: ['nginx exporter ip:9113']
  • 저는 Spring 외에도 MySQL Exporter, Node Exporter, Nginx Exporter를 추가로 사용하였는데요, 이 글에서는 모두 다루기엔 분량상 너무 길어질 거 같으니 도움을 얻을 수 있는 링크만 남기도록 하겠습니다.
  • 그 후 Spring Actuator + Prometheus Registry 라이브러리를 추가하여 메트릭을 제공하도록 해야합니다.
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
  • 그 후 Spring application.yml 파일에 아래와 같이 설정해줍니다.
management:
  endpoints:
    web:
      exposure:
        include: health, prometheus
  metrics:
    tags:
      application: ${spring.application.name}
  server:
    port: 9090

 

  • 저는 웹 Port와 Actuator Port를 구분하여 외부 사용자가 Actuator에 접근할 수 없도록 제한하였습니다.

Grafana 등록

이제 Grafana에 DataSource를 등록해 주면 됩니다.
그 후 대시보드를 등록하면 되는데, 제가 사용한 대시보드 들은 아래와 같습니다.

 

 

 

 

 

 

 

 

 

반응형