본문 바로가기
Database & Storage

Loki + Promtail + Grafana로 로그 수집·검색·알림: 가벼운 ELK 대안 구축(단일 서버 → 다중 서버 확장)

by yamoojin83 2025. 10. 28.

Loki + Promtail + Grafana로 로그 수집·검색·알림: 가벼운 ELK 대안 구축(단일 서버 → 다중 서버 확장)

운영 환경의 장애 원인 파악은 결국 로그에서 시작합니다. 하지만 전통 ELK(Elasticsearch+Logstash+Kibana)는 리소스 요구량과 관리 복잡도가 높습니다. Loki + Promtail + Grafana 조합은 인덱스 없는 설계로 저비용·간편 운영·빠른 도입이 장점입니다. 이 글은 Ubuntu 24.04 기준으로 단일 서버에 구축한 뒤, 다중 서버로 확장하는 방법까지 설정 스니펫운영 체크리스트로 정리합니다.


1) 아키텍처 한 장 요약

  • Promtail: 로컬 파일(예: /var/log/*.log) Tail → 라벨링 → Loki로 전송
  • Loki: 로그 저장/쿼리. 인덱스 대신 라벨 메타데이터로 가볍게 관리
  • Grafana: 시각화·검색(LogQL)·알림 룰
[App/OS Logs] --tail--> [Promtail] --push--> [Loki] <--query--> [Grafana]

핵심: “무분별한 라벨 남용 금지”. 필요한 라벨(호스트, 서비스명, 환경 등)만 최소화해 저장 효율을 유지합니다.


2) 설치(단일 서버 시작)

2-1) 패키지/사용자

sudo useradd --system --no-create-home --shell /usr/sbin/nologin loki
sudo useradd --system --no-create-home --shell /usr/sbin/nologin promtail

2-2) 바이너리 배치

공식 릴리스를 받아 /usr/local/bin에 배치(버전은 환경에 맞게 교체).

sudo mv loki promtail /usr/local/bin/
sudo chmod +x /usr/local/bin/loki /usr/local/bin/promtail

3) Loki 설정(로컬 볼륨 저장, 단일 인스턴스)

# /etc/loki/config.yml (최소 예시)
auth_enabled: false

server:
  http_listen_port: 3100

common:
  instance_addr: 127.0.0.1
  path_prefix: /var/lib/loki
  storage:
    filesystem:
      chunks_directory: /var/lib/loki/chunks
      rules_directory: /var/lib/loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

schema_config:
  configs:
    - from: 2025-01-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  ingestion_rate_mb: 8
  ingestion_burst_size_mb: 16
  max_streams_per_user: 10000

chunk_store_config:
  max_look_back_period: 720h

table_manager:
  retention_deletes_enabled: true
  retention_period: 720h   # 30일 보관 예시

3-1) 디렉터리/권한

sudo mkdir -p /var/lib/loki/{chunks,rules}
sudo chown -R loki:loki /var/lib/loki /etc/loki

3-2) systemd 서비스

# /etc/systemd/system/loki.service
[Unit]
Description=Loki Log Aggregation
After=network-online.target
Wants=network-online.target

[Service]
User=loki
ExecStart=/usr/local/bin/loki --config.file=/etc/loki/config.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now loki
systemctl status loki --no-pager

4) Promtail 설정(파일 경로 지정, 라벨 최소화)

# /etc/promtail/config.yml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

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

scrape_configs:
  - job_name: syslog
    static_configs:
      - targets: [localhost]
        labels:
          job: syslog
          host: ${HOSTNAME}
          __path__: /var/log/syslog

  - job_name: nginx
    static_configs:
      - targets: [localhost]
        labels:
          job: nginx
          host: ${HOSTNAME}
          __path__: /var/log/nginx/*.log

  - job_name: app
    static_configs:
      - targets: [localhost]
        labels:
          job: myapp
          env: prod
          host: ${HOSTNAME}
          __path__: /var/log/myapp/*.log

4-1) 디렉터리/서비스

sudo mkdir -p /var/lib/promtail
sudo chown -R promtail:promtail /var/lib/promtail /etc/promtail
# /etc/systemd/system/promtail.service
[Unit]
Description=Promtail Log Collector
After=network-online.target
Wants=network-online.target

[Service]
User=promtail
ExecStart=/usr/local/bin/promtail --config.file=/etc/promtail/config.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now promtail
systemctl status promtail --no-pager

5) Grafana 연결(탐색·대시보드·알림)

  1. Grafana 설치 후 로그인 → Connections → Data sources → Add data source
  2. Loki 선택, URL에 http://127.0.0.1:3100 입력 → Save & Test
  3. Explore에서 LogQL로 즉시 검색

5-1) LogQL 기초

{job="nginx"} |= "GET" |~ "\\.css" 
{job="myapp", env="prod"} | logfmt | level="ERROR"
{host="web-01"} | json | line_status >= 500

: 애플리케이션 로그를 JSON/Logfmt로 찍으면 파싱 후 필터링이 쉬워집니다.


6) 알림(로그 패턴 기반 경보)

Grafana 10+의 Alerting을 사용해 특정 LogQL 카운트를 지표로 전환 후 임계치 알림을 보낼 수 있습니다.

  1. Dashboards → Alerting → Alert rules → New
  2. 쿼리 예시(5분간 에러 20회 이상):
# Loki → Metrics 탭에서 count_over_time 사용
sum by (job) (count_over_time({job="myapp"} |= "ERROR" [5m])) >= 20

Slack/Webhook/Email 연락처를 연결하면 실시간 통지가 가능합니다.


7) 다중 서버 확장(Agent만 추가)

  • 각 서버에 Promtail만 설치하고, clients.url을 중앙 Loki로 지정
  • 라벨에 host, env, job 정도만 유지(카디널리티 폭증 방지)
# 각 애플리케이션 서버의 /etc/promtail/config.yml (발췌)
clients:
  - url: http://loki.example.internal:3100/loki/api/v1/push

스토리지: 단일 서버는 filesystem으로 시작하고, 규모가 커지면 S3 호환 오브젝트 스토리지(미니오 등)로 이전을 검토합니다.


8) 운영 체크리스트

  • 라벨 가이드: host, job, env, (선택)app. 동적 값(사용자ID 등)은 절대 라벨로 넣지 않기.
  • 보관정책: 7~30일 사이로 시작 → 비용/검색 패턴에 따라 조정.
  • 보안: Loki HTTP 엔드포인트는 내부망 제한(방화벽/UFW). Reverse proxy로 인증 헤더 부여 가능.
  • 성능: Promtail의 positions.yaml이 손상되면 재수집 가능성. 백업 또는 변동 최소화.
  • 백업: 운영 정책에 따라 /var/lib/loki 스냅샷(또는 오브젝트 스토리지 자체 내구성 의존).

9) 문제 해결 빠른 분기

  • 로그가 안 들어옴: Promtail 로그에서 client 에러 확인 → Loki URL/포트/방화벽 재확인.
  • 검색이 느림: 기간/라벨 범위를 좁히고, 과도한 라벨 제거. 보관기간/청크 파라미터 점검.
  • 용량 급증: 라벨 폭발(카디널리티) 여부 점검, env·job 외 가변 라벨 삭제.
  • 중복 수집: positions 파일 경로 고정, 동일 로그 파일의 로테이션 정책 확인(logrotate 설정).

10) 마무리

Loki 스택은 “적당히 가볍고 충분히 강력한” 로그 플랫폼입니다. 단일 서버에서 빠르게 시작해, Promtail만 늘려 다중 서버로 매끄럽게 확장할 수 있습니다. 지금 운영 중인 서비스의 에러 키워드 2~3개부터 알림을 걸고, 팀 합의된 라벨 가이드만 지켜도 장애 대응 속도는 눈에 띄게 개선됩니다.