📌 들어가며

로그를 한곳에 모아 조회·알람하려면 로그 집계 시스템이 필요합니다. Loki는 Grafana에서 제공하는 오픈소스 로그 집계 시스템으로, Prometheus·Grafana 스택과 잘 맞고 메타정보만 인덱싱해 Elasticsearch보다 가볍게 쓸 수 있습니다. 이 글은 Docker 기반으로 Loki를 설치하고 설정하는 방법을 안내합니다.

💡 이런 분들께 추천합니다

  • Grafana/Prometheus 스택에 로그 수집(Loki)을 붙이려는 분
  • Docker 환경에서 Loki를 빠르게 띄워 보고 싶은 분
  • 로그 집계·모니터링 구성을 처음 해 보는 분

🧩 개념 설명 / 배경 지식

이미 Loki와 Grafana 스택을 알고 있다면 다음 섹션으로 넘어가도 됩니다.

Grafana Promtail Loki Architecture
아래 그림에서 Loki에 해당하는 부분입니다. Prometheus Loki는 Grafana에서 제공하는 오픈소스 기반의 로그 집계 시스템이며, 수평 확장·고가용성·Multi-tenancy를 지원합니다.

Loki 인덱스 구성
메타정보만 인덱스하도록 강제되어 있어, 전체를 인덱싱하는 Elasticsearch에 비해 빠르고 간결하며 저장소를 적게 씁니다.

🔍 본론: Docker 기반 Loki 설치 및 설정

테스트 환경: 인터넷 가능 환경, Rocky Linux 8.6, Docker 구성 완료 상태

1. Loki docker-compose 구동을 위한 스크립트 준비

전체파일 구성

tree

├── create.sh
├── delete.sh
├── docker-compose.yml
├── log.sh
├── start.sh
└── stop.sh

1) Loki의 docker-compose.yml 샘플

주요설정 설명
- -config.file: loki에서 사용하는 config파일 위치 정의. 아래와 같이 설정시 loki 컨테이너 이미지에서 제공하는 기본설정값 그대로 사용

vi  docker-compose.yml

version: '3.7'

# monitor-net이름으로 이미 구성한 경우에는 networks부분은 주석처리
networks:
  monitor-net:
    driver: bridge

services:

  loki:
#    image: grafana/loki:2.7.4
    image: grafana/loki:latest
    container_name: loki
    ports:
      - 3100:3100
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - monitor-net
    labels:
      logging: "promtail"
      logging_jobname: "containerlogs"

참고: /etc/loki/local-config.yaml 설정 내용 조회방법

docker exec -it loki cat /etc/loki/local-config.yaml

auth_enabled: false

server:
  http_listen_port: 3100

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

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

ruler:
  alertmanager_url: http://localhost:9093

# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
#
# Statistics help us better understand how Loki is used, and they show us performance
# levels for most users. This helps us prioritize features and documentation.
# For more information on what's sent, look at
# https://github.com/grafana/loki/blob/main/pkg/usagestats/stats.go
# Refer to the buildReport method to see what goes into a report.
#
# If you would like to disable reporting, uncomment the following lines:
#analytics:
#  reporting_enabled: false


2) docker 컨테이너 생성,삭제,구동,중지,로그조회 등 스크립트 작성

cat > create.sh <<EOF
#!/usr/bin/bash
docker-compose -f docker-compose.yml up -d
docker-compose -f docker-compose.yml logs -f
EOF

cat > delete.sh <<EOF
#!/usr/bin/bash
docker-compose -f docker-compose.yml down -v
EOF

cat > start.sh <<EOF
#!/usr/bin/bash
docker-compose -f docker-compose.yml start
EOF

cat > stop.sh <<EOF
#!/usr/bin/bash
docker-compose -f docker-compose.yml stop
EOF

cat > log.sh <<EOF
#!/usr/bin/bash
docker-compose -f docker-compose.yml logs -f
EOF

chmod +x *.sh

2. Loki 정상구동여부 확인

### 구동하기
./create.sh 

### 도커컨테이너 정상구동여부 확인
docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                    NAMES
c16cdc7ba488   grafana/loki:latest         "/usr/bin/loki -conf…"   6 days ago   Up 35 minutes   0.0.0.0:3100->3100/tcp, :::3100->3100/tcp   loki


docker logs loki
[root@rocky8 promtail]# docker logs loki
level=warn ts=2023-04-12T00:20:46.856282084Z caller=loki.go:286 msg="per-tenant timeout not configured, using default engine timeout (\"5m0s\"). This behavior will change in the next major to always use the default per-tenant timeout (\"5m\")."
level=info ts=2023-04-12T00:20:46.870600208Z caller=main.go:108 msg="Starting Loki" version="(version=2.8.0, branch=HEAD, revision=90888a0cc)"
level=info ts=2023-04-12T00:20:46.871668305Z caller=server.go:323 http=[::]:3100 grpc=[::]:9095 msg="server listening on addresses"
level=warn ts=2023-04-12T00:20:46.895185176Z caller=cache.go:114 msg="fifocache config is deprecated. use embedded-cache instead"
level=warn ts=2023-04-12T00:20:46.895219711Z caller=experimental.go:20 msg="experimental feature in use" feature="In-memory (FIFO) cache - chunksembedded-cache"
level=info ts=2023-04-12T00:20:46.895570888Z caller=table_manager.go:262 msg="query readiness setup completed" duration=1.322µs distinct_users_len=0
level=info ts=2023-04-12T00:20:46.895605572Z caller=shipper.go:131 msg="starting index shipper in RW mode"
level=info ts=2023-04-12T00:20:46.895770641Z caller=shipper_index_client.go:78 msg="starting boltdb shipper in RW mode"
level=info ts=2023-04-12T00:20:46.89613884Z caller=worker.go:112 msg="Starting querier worker using query-scheduler and scheduler ring for addresses"
level=info ts=2023-04-12T00:20:46.8972083Z caller=mapper.go:47 msg="cleaning up mapped rules directory" path=/loki/rules-temp
이후 로그 생략..

3. Loki 메트릭 데이터 조회

curl http://아이피:3100/metrics

# HELP cortex_consul_request_duration_seconds Time spent on consul requests.
# TYPE cortex_consul_request_duration_seconds histogram
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.005"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.01"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.025"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.05"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.1"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.25"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="0.5"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="1"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="2.5"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="5"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="10"} 725
cortex_consul_request_duration_seconds_bucket{kv_name="ingester-ring",operation="CAS loop",status_code="200",le="+Inf"} 725
cortex_consul_request_duration_seconds_sum{kv_name="ingester-ring",operation="CAS loop",status_code="200"} 0.052866492999999945
cortex_consul_request_duration_seconds_count{kv_name="ingester-ring",operation="CAS loop",status_code="200"} 725
# HELP cortex_distributor_ingester_clients The current number of ingester clients.
# TYPE cortex_distributor_ingester_clients gauge
cortex_distributor_ingester_clients 2
# HELP cortex_dns_failures_total The number of DNS lookup failures
# TYPE cortex_dns_failures_total counter
cortex_dns_failures_total{name="memberlist"} 0
# HELP cortex_dns_lookups_total The number of DNS lookups resolutions attempts
# TYPE cortex_dns_lookups_total counter
cortex_dns_lookups_total{name="memberlist"} 0
# HELP cortex_frontend_query_range_duration_seconds Total time spent in seconds doing query range requests.
# TYPE cortex_frontend_query_range_duration_seconds histogram

4. 구동화면 예시

container 로그 파일을 Promtail로 수집한 뒤 Grafana 대시보드에 추가해 조회하는 방법은 별도 글로 설명 예정입니다.

⚠️ 주의사항

  • monitor-net 등 기존 Docker 네트워크가 있으면 docker-compose.ymlnetworks 부분을 주석 처리하세요. Loki 기본 설정은 단일 인스턴스용이므로, 프로덕션 고가용성은 공식 문서의 분산 설정을 참고하세요.

✅ 실습 / 적용 예시

Step 1. docker-compose.ymlcreate.sh·delete.sh·start.sh·stop.sh·log.sh 스크립트를 준비합니다. Step 2. ./create.sh로 Loki 컨테이너를 띄운 뒤 docker ps, docker logs loki로 구동을 확인합니다. Step 3. curl http://아이피:3100/metrics로 메트릭을 조회하고, Promtail·Grafana와 연동해 로그를 수집·조회합니다.

🚧 트러블슈팅 / 자주 묻는 질문

Q. Loki 컨테이너는 떠 있는데 Grafana에서 로그가 안 보여요.
A. Promtail이 Loki로 로그를 전송하도록 설정했는지, Grafana 데이터 소스에 Loki URL(예: http://loki:3100)이 올바르게 등록됐는지 확인하세요. Q. 기본 설정 파일 내용을 바꾸고 싶어요.
A. local-config.yaml을 바꾸려면 볼륨 마운트로 설정 파일을 넘기고 command에서 해당 경로를 지정하세요.

📝 마무리

  • Loki는 Grafana 계열의 로그 집계 시스템으로, Docker 한 컨테이너로 빠르게 구동할 수 있습니다.
  • docker-compose와 스크립트로 생성·시작·중지·로그 조회를 정리해 두면 운영이 편합니다.
  • 다음 단계로 Promtail 로그 수집 설정과 Grafana 대시보드 구성을 이어가면 됩니다.

댓글남기기