모니터링 시스템 구축기

‍서지오·2023년 10월 25일
0

클라우드

목록 보기
1/2

Prometheus & Grafana 설정

1. spring boot actuator 외부 접근 제한(for 보안)

spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://mariadb:3306/boeing
    username: ${DB_USER}
    password: ${DB_PASSWORD}
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
    open-in-view: false
  redis:
    host: redis
    port: ${REDIS_PORT}
    password: ${REDIS_PASSWORD}

# spring actuator 설정
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics, prometheus
  server:
    port: ${PROMETHEUS_PORT}
    base-path: ${PROMETHEUS_PATH}

server:
  servlet:
    context-path: /api/v1
  • include : 사용할 엔드포인트(url) 설정
    • ex) health, info, prometheus
  • port : 프로메테우스 접속 시 사용할 포트(PROMETHEUS_PORT)
  • base-path : 프로메테우스 접속 시 사용할 경로(PROMETHEUS_PATH)
  • .env 파일과 docker-compose의 environment 영역에 application.yml에서 사용할 변수 추가 필요

2. docker-compose-monitoring.yml

version: '3'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    networks:
      - deploy
    ports:
      - "9091:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    networks:
      - deploy
    ports:
      - "3001:3000"
    volumes:
      - ./grafana-data:/var/lib/grafana
    depends_on:
      - prometheus

networks:
  deploy:
    external: true
  • volumes를 설정하여 컨테이너가 내려가도 기존 Grafana에서 설정한 대시보드나 데이터 소스가 유지 되도록 함
  • 프로메테우스는 9090, 그라파나는 3000번 포트를 default로 사용하므로 외부포트만 수정해야 한다!!

3. prometheus.yml

scrape_configs:
  - job_name: 'bizscanner'
    metrics_path: '/{PROMETHEUS_PATH}/actuator/prometheus'
    scrape_interval: 5s
    static_configs:
      - targets: ['spring:{PROMETHEUS_PORT}']
  • PROMETHEUS_PORT : monitoring
  • PROMETHEUS_PATH : 8081

Promtail & Loki 설정

1. Logback 설정(logback-spring.xml)

<configuration>
    <!-- 로그 패턴 및 색상 지정 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <property name="consoleLogPattern"
              value="[%d{yyyy-MM-dd' T 'HH:mm:ss.SSS}]  %clr(%-5level) %clr(${PID:-}){magenta} %clr(---){faint} %clr([%15.15thread]){faint} %clr(%-40.40logger{36}){cyan} %clr(:){faint} %msg%n"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${consoleLogPattern}</pattern>
        </encoder>
    </appender>

    <!-- root level 설정 -->
    <root level="info">
        <appender-ref ref="console"/>
    </root>

    <!-- 로그 파일이 생성될 경로 지정 -->
    <property name="infoLogPath" value="logs/backend/info"/>
    <property name="warnLogPath" value="logs/backend/warn"/>
    <property name="errorLogPath" value="logs/backend/error"/>

    <!-- 로그 파일 이름 형식 지정 -->
    <property name="fileNamePattern" value="%d{yyyy-MM-dd}_%i.log"/>

    <!-- 로그 패턴 지정 -->
    <property name="logPattern" value="%d{HH:mm:ss.SSS} [%20thread] %-5level %-53logger{36} - %msg%n"/>

    <!-- INFO LOG -->
    <!-- 롤링 패턴 적용(시간 또는 일 단위로 파일을 구분) -->
    <appender name="info-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 로그 파일 보관 주기 설정, 보관 주기를 넘어가면 자동으로 삭제-->
            <maxHistory>7</maxHistory>

            <!-- 로그 파일당 최대 용량 설정 -->
            <maxFileSize>1GB</maxFileSize>

            <!-- 전체 파일 크기 설정, 전체 크기 제한을 조과하면 가장 오래된 파일을 삭제 -->
            <totalSizeCap>1GB</totalSizeCap>
            <fileNamePattern>${infoLogPath}/${fileNamePattern}</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${logPattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>NEUTRAL</onMismatch>
        </filter>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- WARN LOG -->
    <appender name="warn-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <maxHistory>7</maxHistory>
            <maxFileSize>1GB</maxFileSize>
            <totalSizeCap>1GB</totalSizeCap>
            <fileNamePattern>${warnLogPath}/${fileNamePattern}</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${logPattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- ERROR LOG -->
    <appender name="error-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <maxHistory>7</maxHistory>
            <maxFileSize>1GB</maxFileSize>
            <totalSizeCap>1GB</totalSizeCap>
            <fileNamePattern>${errorLogPath}/${fileNamePattern}</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>${logPattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <root level="info">
        <appender-ref ref="info-file"/>
        <appender-ref ref="warn-file"/>
        <appender-ref ref="error-file"/>
    </root>
</configuration>
  • logback-spring.xml : log를 level별로 구분하여 파일로 관리하기 위한 logback 설정 파일
  • 코드 분석
    1. conversionRuleproperty: 이 부분에서는 로그 패턴과 색상을 정의합니다. %clr 토큰을 사용하여 로그 레벨과 기타 텍스트에 색상을 지정합니다. consoleLogPattern은 콘솔 출력에 사용할 패턴을 정의하고, %d, %clr, %-5level, %clr(${PID:-}), %clr(---), %clr([%15.15thread]), %clr(%-40.40logger{36}), %clr(:), %msg%n 등이 포함되어 있습니다.
    2. appender 요소: 로그를 출력하는 대상을 설정합니다. 여기에서는 console 앱렌더를 정의하여 콘솔에 로그를 출력합니다. 또한 info-file, warn-file, error-file 앱렌더를 정의하여 로그 파일에 저장합니다.
    3. rollingPolicy: 로그 파일 롤링 정책을 설정합니다. 로그 파일은 최대 7일 동안 보관되며, 파일 크기는 최대 1GB로 제한됩니다. totalSizeCap은 모든 로그 파일의 총 크기 제한을 나타냅니다.
    4. encoder: 로그 메시지의 출력 형식을 정의합니다. 여기에서는 logPattern에 정의된 패턴을 사용하여 로그 메시지를 출력합니다.
    5. filter: 각 앱렌더에는 로그 레벨에 따라 필터가 설정되어 있습니다. 이 필터는 각 앱렌더에 대한 로그 레벨을 제한합니다. 예를 들어, info-file 앱렌더는 INFO 레벨의 로그만 허용하고, warn-file 앱렌더는 WARN 레벨의 로그만 허용하도록 설정되어 있습니다.
    6. root 로거: 루트 로거의 레벨을 info로 설정하고, appender-ref를 사용하여 각 앱렌더를 루트 로거에 연결합니다. 이로 인해 INFO, WARN, ERROR 레벨의 로그가 각각 다른 파일에 저장됩니다.

2. spring을 실행하는 docker-compose.yml 수정

volumes:
      - /home/ubuntu/monitoring/logs:/app/logs
  • 컨테이너 내부의 logs 폴더를 외부와 마운팅 하기 위해 volumes 구문 추가

3. docker-compose-monitoring.yml에 loki, promtail 설정 추가

  loki:
    image: grafana/loki:latest
    networks:
      - deploy
		ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    networks:
      - deploy
    volumes:
      - ./logs:/logs
      - ./promtail-config.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.y

4. promtail-config.yml

positions:
  filename: /tmp/positions.yaml # 동기화 작업을 이루기 위해 promtail이 읽은 마지막 로그 정보를 저장하는 곳

clients:
  - url: http://loki:3000/loki/api/v1/push # push할 Loki의 주소

scrape_configs:
  - job_name: info
    static_configs:
      - targets:
          - localhost
        labels:
          job: info_logs
          __path__: ./logs/info/*.log # info 폴더 내에 log 파일들 모두 수집
        
  - job_name: warn
    static_configs:
      - targets:
          - localhost
        labels:
          job: warn_logs
          __path__: ./logs/warn/*.log # warn 폴더 내에 log 파일들 모두 수집
          
  - job_name: error
    static_configs:
      - targets:
          - localhost
        labels:
          job: error_logs
          __path__: ./logs/error/*.log # error 폴더 내에 log 파일들 모두 수집

마주친 에러들….

1. docker-compose로 grafana 컨테이너 실행 시 ‘Grafana '/var/lib/grafana/plugins': Permission denied’ 에러 발생

  • user: "$UID:$GID" : grafana image 내에 /var/lib/grafana의 쓰기 작업을 허용해줘도 계속해서 에러가 났다.
  • docker-compose down 후 재실행하니까 해결됨…

2. docker-ufw 설정 관련 에러

  • 프로메테우스는 -p 9091:9090, 그라파나는 -p 3001:3000으로 포트 포워딩 한 상태
  • 도커 컨테이너를 띄울 때 포트포워딩을 했으므로 이더넷에는 외부포트(9091, 3001)이 열리게 된다.(도커는 ufw 규칙 위에 존재하기 때문에) ⇒ 따라서 굳이 docker-ufw allow로 외부 포트를 열어줄 필요가 없다.
  • docker-ufw를 사용한 순간 네트워크들의 포트를 모두 막기 때문에 이더넷에서 deploy 네트워크의 내부 포트로(9090, 3000) 포워딩이 막힘 ⇒ 이를 해결하기 위해 docker-ufw allow 명령어로 내부 포트를 열어준다.

참고자료

profile
백엔드 개발자를 꿈꾸는 학생입니다!

0개의 댓글