9 min read

[Homelab] Grafana Loki 로그 모니터링 구축해보기 - (1)

[Homelab] Grafana Loki 로그 모니터링 구축해보기 - (1)

시스템을 운영하는 일을 하다보면 로그는 뗄 수 없는 존재인 것 같다

정기 작업을 위해 어플리케이션을 재기동하거나 가끔 서비스가 불안정하면
습관적으로 tail 로 로그를 띄워두고 상태를 확인해본다

그런데 로그라는게 태생이 어플리케이션이 하는일을 글로 남기는 일이다 보니
당연히도 그 양이 참 많다

실제로 알고 싶은 내용은 보통 특정 시점에 한 두줄 내외로 끝인데 그걸 위해 주르륵 올라오는 로그를 보고 있자니 여간 귀찮은 일이 아닐 수 없다

그러다보니 이런 생각이 들때도 있다

내가 필요한 건 문제가 생기는 특정 로그인데, 굳이 다 봐야할까?
메트릭에 문제가 생기면 그 시점에 발생한 로그만 보여주는 방법은 없을까?

Grafana Labs 의 Loki 를 이용해 질문의 해답을 찾아보자


로그를 모아보자

로그 모니터링이나 집계가 나만 고민한 내용도 아니고
당연히 수 많은 Paid/OSS 솔루션들이 있다

그 중 이쪽 방면에서 가장 인지도가 높은 툴을 꼽자면 당연히 ElasticSearch 가 되겠다

흔히 사용하는 ELK(ElasticSearch + Logstash + Kibana) 스택을 구성하면
로그 수집(Logstash) → 파싱 & 분석 & 저장(ElasticSearch) → 시각화(Kibana) 까지
단번에 구성할 수 있다

심지어 오픈소스로 제공도 해주고 사용할 수 있는 기능의 범위도 넓다

회사에서도 이렇게 ELK 스택을 구성해 로그들을 수집해 관리하고 있기도 하다

ELK 가 로그를 데이터처럼 다루면서 집계/모니터링이 가능하다보니
De-Facto 표준처럼 사용되기는 하지만 사용하다보면 명확하게 단점이 드러난다

  1. 로그 파싱 rule 생성/관리에 많은 시간이 소비됨
  2. 상대적으로 많은 양의 컴퓨팅 용량이 필요함
  3. 유지보수 난이도가 높음

단순 로그를 위해서 은근히 들어가는 공수가 높은데 내가 필요한 로그 몇 줄 보기위해서는 너무나 과하다
그리고 어렵기도 하고 말이지..

Loki 등장!

히히히

요즘 Grafana Labs 에서 이런저런 좋은 툴들을 많이 릴리즈 해주고 있어서 웹사이트를 둘러보던 중 발견한 Loki.

참고로 2018년도 KubeCon 에서 최초 릴리즈하면서 밝혔지만
실제로 북유럽 신화의 그 Loki 에서 모티브를 얻은게 맞다!!

사람들이 X(구 트위터) 에서도 헷갈리니 제발 저 이름으로 짓지 말라고 했지만 그냥 저 이름으로 밀어부친 듯하다 ㅋㅋ

덕분에 Grafana Loki 하면 자꾸 마블의 로키가 생각이 난다

다시 본론으로 돌아와서 아래 공식 소개링크를 살펴보자

Grafana Loki OSS | Log aggregation system
Loki is a horizontally scalable, highly available, multi-tenant log aggregation system inspired by Prometheus.
Loki takes a unique approach by only indexing the metadata rather than the full text of the log lines

위 문구처럼 Loki 가 제안하는 방법을 보면 ElasticSearch 가 가진 방식을 보완한다기 보다는 오히려 로그 관리를 바라보는 관점이 다르다는게 더 정확하겠다

Loki 에서 보는 로그 관리 기법은 이렇다

ElasticSearch 처럼 로그를 한줄 한줄 파싱해서 "데이터 자체를 보관한다" 라기보다는
데이터는 손대지 말고 필요한 "메타데이터만 레이블로 보관하자" 라는 방식으로 접근하고 있다

필요하다면 레이블로 필터만 걸어서 관련 로그를 다 뽑아내자! 라는 방식인 셈.

당연히 이런 방식은 일장일단이 있는데

ElasticSearch 대비해서 데이터 처리에 대한 비용도 낮고 복잡하게 로그를 파싱해야 할 필요도 없어지는 반면
로그가 가진 데이터 자체를 집계하거나 가공하는건 어렵다는 단점이 생긴다

내가 필요로 하는 목적은 특정 시점에 발생하는 로그를 보여주는게 전부이니
오히려 Loki 가 더 적합하다고 볼 수 있지만
항상 그렇듯 상황에 맞게 적절한 방식을 채택하는게 중요하겠다


음 잘 모르겠으니 일단 한번 올려보자

어떤 장단점이 있는지 잘 모르겠다면 한번 써보는게 답이다

Loki 는 여러가지 구축 방법을 제공하는데
이 글에서는 Docker 를 기반으로 구성을 해보려고 한다

당연히 Helm 차트 등을 이용해 Kubernetes 에 구성도 할 수 있다

계획하고 있는 간략한 구성도를 보면 이렇다

로그가 발생하는 장비나 서비스에서 fluent-bit 을 통해 Loki 에 저장하고
최종적으로 Grafana 를 이용해 시각화 하는 방법이다

로그를 장기보관하려면 디스크 용량도 상당히 많이 필요할테니
S3 인터페이스를 제공해주는 MinIO 를 올려서 Loki 의 백엔드 스토리지로 사용해보려고 한다

우선 MinIO 는 나중에 연동하고 기본 설정으로 구성해보자

아래 공식 링크에서 docker-compose 를 사용한 구성방법을 제공해주니 확인해보자

Install Loki with Docker or Docker Compose | Grafana Loki documentation
Describes how to install Loki using Docker or Docker Compose

docker-compose.yml

Grafana 도 같이 올라가게 구성하였으니
이미 Grafana 가 있다면 제외하고 올리도록 하자

networks:
  monitoring: {}

services:
  grafana:
    image: grafana/grafana:latest
    user: "1000"
    container_name: grafana
    restart: always
    ports:
      - '3000:3000'
    volumes:
      - /data/metrics-data/grafana:/var/lib/grafana
    networks:
      - monitoring

  loki:
    image: grafana/loki:latest
    user: "1000"
    ports:
      - "3100:3100"
    restart: always
    command: -config.file=/etc/loki/local-config.yaml -config.expand-env=true
    volumes:
      - /data/loki/local-config.yaml:/etc/loki/local-config.yaml
      - /data/logs-data/loki:/loki
    networks:
      - monitoring

local-config.yaml

# 테스트 목적이니 인증은 일단 비활성화 해두자
auth_enabled: false

# 로그데이터를 받을 포트 지정
server:
  http_listen_port: 3100
  grpc_listen_port: 9096

# 로그를 백엔드 스토리지로 넘기는 역할을 하는 컴포넌트이다
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: 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)

# 데이터 스키마에 대한 설정을 해주자
schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

# boltdb_shipper 의 스토리지를 설정한다
# boltdb 는 데모용으로만 사용할 목적이고 2.X 버전 이후로는 레거시 처리되었으니 
# 실제 운영에서는 쓰지 말도록 하자
# 향후 MinIO 기반의 S3 스토리지로 넘어갈 예정
storage_config:
  boltdb_shipper:
    active_index_directory: /loki/boltdb-shipper-active
    cache_location: /loki/boltdb-shipper-cache
    cache_ttl: 24h         # Can be increased for faster performance over longer query periods, uses more disk space
  filesystem:
    directory: /loki/chunks

# 데이터 양이 많을 수 있으니 주기적으로 압축
compactor:
  working_directory: /loki/boltdb-shipper-compactor

table_manager:
  retention_deletes_enabled: true
  retention_period: 336h # how long data remaind

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

# 각종 fine tuning
limits_config:
  allow_structured_metadata: false
  volume_enabled: true
  max_streams_per_user: 100000

이제 올려보자

docker compose up -d

다 올라갔다면 Grafana 에 접속해 데이터소스 추가를 해주자

Grafana 가 별도 구축되어 있는게 아니라면 monitoring 네트워크를 사용하니 loki 호스트명으로 접근이 가능하다

docker-compose.yaml 에서 열어준 3100 포트로 설정하고 접속을 확인해주자


이렇게 Grafana Loki 를 구축했다

소개가 길고 구축은 별게 없어서 좀 허무할 수도 있지만
MinIO 도 아직 없는 상태이고 실제 로그가 인입되기 시작하면 몇가지 수정이 필요한 부분도 있다

다음 글에서는 fluent-bit 을 통해 nginx 웹서버의 로그를 수집하고 어떻게 로그가 저장되고 쿼리할 수 있는지 살펴보자.