Profile picture

[Docker] 도커로 운영 중인 Django 블로그에 모니터링 도입하기

JaehyoJJAng2023년 05월 22일

◾️ 구성도

image


◾️ 구성 진행

이번 포스팅에서는 모니터링에 필요한 docker-compose.yaml 파일이나
기타 config(loki-config.yaml,promtail-config.yaml) 파일 작성은 하지 않을 것이다.

관련 내용의 경우 [Monitoring] Docker-Compose로 Grafana/Loki 구축 및 rsyslog, journal 로그 연동하기를 참고하여 구축해보도록 하자.

이번 실습에서는 미리 배포된 Grafana, Loki, Promtail에서 설정만 조금 바꿔서 NPM의 Proxy Hosts들 로그도 함께 모니터링 할 수 있도록 구성해볼 것이다.


◾️ 사전 준비

  • Docker / Docker Compose
  • NPM(Nginx Proxy Manager)
  • Grafana, Loki, Promtail

작업 진행 전에 서브 도메인 생성과
Nginx Proxy Manager(NPM)에서 새로 등록한 서브 도메인을 프록시 호스트(Proxy Host)로 등록해주어야 한다.


▪️ 서브 도메인 생성

서브 도메인 생성 방법은 아래 게시글에서 자세하게 확인 가능하다. [Domain] 가비아 서브 도메인 설정하기


이번 실습에서 사용될 서브 도메인은 아래와 같다.
image


▪️ Proxy Hosts 등록

현재 배포된 NPM 어드민 페이지로 이동한 후, 위에서 생성한 서브 도메인을 내부 grafana 앱으로 연결시켜주자.
image


SSL 인증서도 발급하도록 하자.
image


grafana.waytothem.store로 브라우저에 접근해보자. 접근이 정상적으로 되고 SSL 인증서 또한 발급됐는지 확인하자.
image


▪️ YAML 파일 다운로드

cd /loki
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/cmd/loki/loki-local-config.yaml -O config/loki-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/cmd/promtail/promtail-docker-config.yaml -O config/promtail-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/v2.2.1/production/docker-compose.yaml -O docker-compose.yaml

▪️ rsyslog.conf 수정

로그 서버 구축 전 모니터링 서버에서 rsyslog.conf 파일을 수정해주어야 한다.

$ cat /etc/rsyslog.conf

...
$template RemoteLogs, "/var/log/remote/%$YEAR%-%$MONTH%-%$DAY%.log"
*.* ?RemoteLogs

#### GLOBAL DIRECTIVES ####

관련 포맷은 rsyslog 서버 구축하기 - WTT 게시글을 참고하도록 하자.

대충 설명하자면 rsyslog 로그들을 /var/log/remote 경로 하위에 2023-01-01.log 형식으로 로그 파일을 생성하겠다는 의미이다.
(localhost 로그 및 클라이언트 서버들의 로그가 2023-01-01.log 파일에 기록된다. // 물론 클라이언트 서버의 rsyslog.conf 파일에 마스터 서버 IP가 기록되어 있어야 한다. 해당 내용은 위 링크 내용을 참고하도록 하자.)


위처럼 /etc/rsyslog.conf 파일을 수정하였으면 rsyslog 서비스를 재시작하자.

sudo systemctl restart rsyslog

◾️ 설정 파일 수정하기

현재 NPM에 등록된 Proxy host들의 로그들은 npm 프로젝트 경로의 data/logs 디렉토리에 실시간으로 기록된다.

$ pwd
/home/ubuntu/Python_Web_Development_2022/data/logs

$ ls -lh /home/ubuntu/Python_Web_Development_2022/data/logs | tail -n 2
-rw-r--r-- 1 root root 333K Dec 11 06:12 proxy-host-6_access.log
-rw-r--r-- 1 root root  37K Dec 11 06:12 proxy-host-6_error.log

나는 해당 경로 또한 모니터링 타겟으로 지정하기 위해서 promtail-config.yaml 파일과 docker-compose.yaml 파일을 조금 수정해줄 것이다.

수정 내용은 매우 간단하다.
docker-compose.yaml의 loki-promtail 컨테이너 설정 부분에 Proxy host들의 로그가 기록되어 있는 /home/ubuntu/Python_Web_Development_2022/data/logs 경로를 바인드 마운트로 추가해주면 되고, promtail-config.yaml 파일에는 컨테이너에서 바인딩된 경로(/data/logs)를 타겟으로 잡아주기만 하면 끝이다.


▪️ docker-compose

# /loki/docker-compose.yaml

version: "3.8"
services:
  loki:
    image: grafana/loki
    restart: always
    volumes:
      - type: bind
        source: '/home/${USER}/loki/config'
        target: '/mnt/config'
      - type: bind
        source: '/home/${USER}/loki'
        target: '/loki'
    ports:
      - "3100:3100"
    command: -config.file=/mnt/config/loki-config.yaml
    container_name: gafana-loki
    networks:
      - 'loki-net'

  promtail:
    image: grafana/promtail
    restart: always
    ports:
      - "1514:1514"
    volumes:
      # 추가된 마운트 경로
      - '/home/ubuntu/Python_Web_Development_2022/data/logs:/data/logs' # Proxy hosts 로그 경로 지정
      
      - type: bind
        source: '/var/log'
        target: '/var/log'
      - type: bind
        source: '/home/${USER}/loki/config'
        target: '/mnt/config'
      - type: bind
        source: '/var/log/journal/'
        target: '/var/log/journal/'
      - type: bind
        source: '/run/log/journal/'
        target: '/run/log/journal/'
      - type: bind
        source: '/etc/machine-id'
        target: '/etc/machine-id'
    command: -config.file=/mnt/config/promtail-config.yaml
    container_name: loki-promtail
    networks:
      - 'loki-net'

  grafana:
    container_name: grafana
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - type: volume
        source: "grafana-db"
        target: "/var/lib/grafana"
    networks:
      - 'loki-net'

volumes:
  grafana-db: {}

networks:
  loki-net:
    driver: bridge
    external: false

기존 docker-compose.yaml 설정에서 아래 내용만 추가해줬다.

      - type: bind # 추가된 마운트 경로
        source: '/home/ubuntu/Python_Web_Development_2022/data/logs'
        target: '/data/logs'

Proxy Host들의 로그가 기록되는 디렉토리를 절대 경로로 지정해 주었다. 그렇게 함으로써 loki-promtail 컨테이너의 /data/logs 디렉토리에는 proxy hosts들의 로그가 실시간으로 업데이트될 수 있을 거다.


▪️ promtail-config

# /loki/config/promtail-config.yaml

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: jhlogs
  static_configs:
  - targets:
      - localhost
    labels:
      job: remote_logs
      __path__: /var/log/remote/*log
  
  # Proxy host들의 로그 수집하기 위해 target 추가 생성.
  - targets:
      - localhost
    labels:
      job: proxy_host_logs
      __path__: /data/logs/*log

- job_name: syslog
  syslog:
    listen_address: 0.0.0.0:1514
    labels:
      job: "syslog"
  relabel_configs:
    - source_labels: ["__syslog_connection_ip_address"]
      target_label: "ip_address"
    - source_labels: ["__syslog_message_severity"]
      target_label: "severity"
    - source_labels: ["__syslog_message_facility"]
      target_label: "facility"
    - source_labels: ["__syslog_message_app_name"]
      target_label: "app_name"
    - source_labels: ["__syslog_message_hostname"]
      target_label: "host"

- job_name: journal
  journal:
    max_age: 12h
    labels:
      job: systemd-journal
  relabel_configs:
    - source_labels: ["__journal__systemd_unit"]
      target_label: "systemd_unit"
    - source_labels: ["__journal__hostname"]
      target_label: "nodename"
    - source_labels: ["__journal_syslog_identifier"]
      target_label: "syslog_identifier"

기존 promtail-config.yaml 설정에서 아래 타겟을 추가해줬다.

  # Proxy host들의 로그 수집하기 위해 target 추가 생성.
  - targets:
      - localhost
    labels:
      job: proxy_host_logs
      __path__: /data/logs/*log

Proxy host들의 로그 기록들이 loki-promtail 컨테이너의 /data/logs 디렉토리로 'proxy-host-1_access.log' 이라는 파일명 형식으로 넘어왔을 것이다.
로그 파일들이 있는 target path를 지정해주면 된다.


▪️ loki-config

task_manager를 설정하여 2주 정도의 log만 보관되도록 설정

# /loki/config/loki-config.yaml 

auth_enabled: false
server:
  http_listen_port: 3100
  grpc_listen_port: 9096

ingester:
  wal:
    enabled: true
    dir: /tmp/wal
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 1h       # Any chunk not receiving new logs in this time will be flushed
  max_chunk_age: 1h           # All chunks will be flushed when they hit this age, default is 1h
  chunk_target_size: 1048576  # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
  chunk_retain_period: 30s    # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
  max_transfer_retries: 0     # Chunk transfers disabled

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

storage_config:
  boltdb_shipper:
    active_index_directory: /tmp/loki/boltdb-shipper-active
    cache_location: /tmp/loki/boltdb-shipper-cache
    cache_ttl: 24h         # Can be increased for faster performance over longer query periods, uses more disk space
    shared_store: filesystem
  filesystem:
    directory: /tmp/loki/chunks

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

limits_config:
  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

ruler:
  storage:
    type: local
    local:
      directory: /tmp/loki/rules
  rule_path: /tmp/loki/rules-temp
  alertmanager_url: http://localhost:9093
  ring:
    kvstore:
      store: inmemory
  enable_api: true

◾️ Grafana 테스트

그라파나(grafana.waytothem.store)로 접근한 후, Explore로 페이지로 이동하여 아래처럼 Label filters를 job = 'job name' 형식으로 필터를 걸어서 로그를 조회해보자.
image
정상적으로 Proxy hosts들의 로그들이 조회되고 있는 것을 확인할 수 있다.


Loading script...