블로그에 새로운 스킨을 적용해봤습니다.
적응 안되긴하는데 조금씩 커스텀해가면서 사용해보려고합니다.
1. 배경 및 목표
여러가지 문제가 있었습니다.
기존에는 docker logs와 grep을 활용하여 컨테이너 로그를 확인하곤 하였습니다.
CLI 환경에서 로그를 확인하는것이 불편하고 원하는 내용만 필터링하기 어려웠습니다.
로그백을 활용하여 error 로그만을 저장하고 확인하였지만 의미있는 내용을 탐색하기 쉽지 않았습니다.
또한 Blue, Green 방식의 무중단 배포를 적용하였고 번갈아 올라오는 두 컨테이너의 로그를 한번에 확인하고 저장하여야 하였습니다.
이러한 애로사항을 해결하기 위해 설정한 목표는 다음과 같습니다.
- Docker 컨테이너의 로그를 사용
- 로그를 저장하여 관리
- Blue, Green 두 컨테이너의 로그를 하나로 확인하기
- 하나의 인스턴스에서 모든것을 구축하기
여러 방식들이 있었습니다.
저는 비용적인 제약 때문에 모니터링용 AWS 인스턴스, 로그를 S3에 저장하는 등에 제약이 있어서 목표를 위와 같이 설정하였습니다.
이에 제 포스팅을 그대로 따라하시기 보다는 충분히 고려하신 후 상황에 맞게 사용하시면 좋겠습니다.
2. 개념
사용할 기술들을 간단하게 짚고 넘어가겠습니다.
저는 Docker compose를 통해 Loki, Grafana, Promtail을 사용하였습니다.
1) Loki
- 로깅 및 이벤트 데이터를 수집, 저장, 검색하기 위한 오픈소스 플랫폼
- 로그에 대한 메타데이터만 인덱싱, 레이블을 기반으로 구축
- 청크 단위로 저장이 되고 압축률에 따라 데이터가 감소
- 많이 사용되는 ELK 시스템에 비해 비용 절감
2) Grafana
- 오픈소스 분석 및 시각화도구
- 다양한 모니터링 시스템을 데이터 소스로 연결 가능
- Loki의 데이터를 시각화하고 분석하는 대시보드 역할
3) Promtail
- 로그를 Loki에 전달하는 에이전트 역할(ELK stack의 Filebeat)
- log stream에 label을 붙이고 loki로 전달
간단하게 생각하면 Promtail이 Loki에게 로그 데이터를 보내고 그 데이터를 Grafana를 통해 시각화 하여 보여주는것 입니다.
제가 생각한 구성을 시각화 하면 다음과 같습니다.

하나의 인스턴스에서 사용하지만, 나눠서 관리하기 위해 두개의 Docker compose를 사용하였습니다.
docker log를 promtail을 통해 가져오면서 loki, promtail, grafana의 로그는 제외하도록 하였습니다.
저는 하나의 인스턴스에서 사용하기에 다 몰아넣었지만,
모니터링을 사용되는 서버와 다른 서버에서 사용하려면 Promtail은 데이터를 가져오려고 하는곳에 설치해야 합니다.
Promtail은 실제 로그가 생성되는 곳에서 로그를 감지하고 Loki로 전달해주는 역할을 합니다.
해당 부분을 인지하시고 상황에 맞게 사용하셨으면 좋겠습니다.
3. 구현
1) loki-config.yaml
공식문서에서 맛보기 용으로 제공되는 loki-config.yaml을 토대로 원하는 설정들을 추가하였습니다.
저는 Loki를 3100번 포트에서 사용하였습니다.
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
공식문서에서는 /tmp/loki에 데이터를 보관하지만, 저는 데이터를 저장할 목적으로 /loki 경로를 지정하였습니다.
해당 경로는 호스트와 볼륨 마운트 하였습니다.
limits_config:
retention_period: 2160h
reject_old_samples: true
reject_old_samples_max_age: 2160h
max_cache_freshness_per_query: 10m
보관기간을 설정하려고 하였습니다.
90일 동안 보관하려고 하였고 오래된 로그는 거부, 삭제하도록 구성되어 있습니다.
max_cache_freshness_per_query는 캐시설정입니다. default가 10m인데 추후 변경할 수도 있을것같아 명시해두었습니다.
전체 코드
# loki-config.yaml
# 인증기능 비활성화
auth_enabled: false
server:
http_listen_port: 3100
common:
instance_addr: 127.0.0.1
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: tsdb
# 파일 시스템을 오브젝트 스토어로 사용
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
# 보관기간 90일 설정
limits_config:
retention_period: 2160h
reject_old_samples: true
reject_old_samples_max_age: 2160h
# 쿼리 시 캐시 데이터의 최대 유효기간
max_cache_freshness_per_query: 10m
ruler:
alertmanager_url: http://localhost:9093
2) promtail-config.yaml
promtail은 9080포트를 사용하였습니다.
마찬가지로 추가 설정을 위해 promtail-config.yaml을 작성하였습니다.
positions:
filename: /var/log/promtail-positions.yaml
promtail은 수집중인 로그 파일의 마지막 읽은 위치(offset)을 저장해야, 재시작 시 같은 부분을 다시 읽지 않고 이어갈 수 있습니다.
해당 경로도 볼륨마운트로 관리합니다.
scrape_configs:
- job_name: "docker"
docker_sd_configs:
- host: unix:///var/run/docker.sock
relabel_configs:
# loki, promtail, grafana 로그 제외
- source_labels: [__meta_docker_container_name]
regex: "/(loki|promtail|grafana)"
action: drop
# 모든 컨테이너 로그
- source_labels: [__meta_docker_container_name]
regex: "/(.*)"
target_label: container
# app만 그룹핑
- source_labels: [__meta_docker_container_name]
regex: "/(app-blue|app-green)"
target_label: app
replacement: "application"
# Docker 컨테이너의 로그 파일 경로를 __path__ 라벨에 할당하여 실제 로그 파일 위치 지정
- source_labels: [__meta_docker_container_log_path]
target_label: __path__
docker_sd_configs를 통해 실행중인 모든 Docker 컨테이너의 로그를 수집합니다.
docker.sock과 볼륨마운트가 필요합니다.
relabel_configs는 라벨링 규칙입니다.
첫번째 라벨은 모니터링 관련 컨테이너의 로그를 무시하는 규칙입니다.
두번째 라벨은 모든 컨테이너에 이름 라벨을 부여합니다.
세번쩨 라벨은 app-blue, app-green이라고 명명된 컨테이너를 application이라는 이름으로 그룹화 합니다.
전체코드
# promtail-config.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/log/promtail-positions.yaml
clients:
# 수집 로그를 전달할 로키 엔드포인트
# 현재는 같은 인스턴스의 docker network 상에 있으므로 loki:3100 추후 인스턴스 분리 시 변경
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: "docker"
docker_sd_configs:
- host: unix:///var/run/docker.sock
relabel_configs:
# loki, promtail, grafana 로그 제외
- source_labels: [__meta_docker_container_name]
regex: "/(loki|promtail|grafana)"
action: drop
# 모든 컨테이너 로그
- source_labels: [__meta_docker_container_name]
regex: "/(.*)"
target_label: container
# app만 그룹핑
- source_labels: [__meta_docker_container_name]
regex: "/(app-blue|app-green)"
target_label: app
replacement: "application"
# Docker 컨테이너의 로그 파일 경로를 __path__ 라벨에 할당하여 실제 로그 파일 위치 지정
- source_labels: [__meta_docker_container_log_path]
target_label: __path__
3) docker-compose.yml
grafana, promtail, grafana를 관리하는 docker compose 입니다.
grafana는 3000번 포트에 띄웠습니다.
networks:
my_app_net:
external: true
name: {기존에 있는 Docker network}
저는 Docker compose를 나눴지만 Nginx 설정 등의 문제로 기존 Docker network에 연결하고자 설정하였습니다.
loki:
image: grafana/loki:latest
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/loki-config.yaml
volumes:
- ./loki-config.yaml:/etc/loki/loki-config.yaml
# 로그 데이터와 인덱스를 저장할 영속 볼륨 마운트
- loki-data:/loki
아까 설정한 loki-config를 사용하기 위해 볼륨 설정을 해주었습니다.
사용하기 위해서 docker-compose.yml이 있는 경로에 loki-config.yaml을 넣어줘야 합니다.
또한 데이터를 저장하기 위한 볼륨마운트 또한 해주었습니다.
promtail:
image: grafana/promtail:latest
container_name: promtail
# 포트 설정
ports:
- "9080:9080"
volumes:
# docker 데몬 소켓을 마운트하여 컨테이너 로그 및 메타 데이터 수집
- /var/run/docker.sock:/var/run/docker.sock
# promtail 설정
- ./promtail-config.yml:/etc/promtail/promtail-config.yml
# positions파일이 유지되도록 호스트와 볼륨 마운트
# 로그 읽기 위치 정보를 저장
- promtail-positions:/var/log
마찬가지로 promtail-config.yaml도 경로에 넣어줍니다.
데이터를 저장하기 위한 볼륨마운트 또한 해주었습니다.
grafana:
environment:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
# 익명 접근 비활성화
- GF_AUTH_ANONYMOUS_ENABLED=false
# ID
- GF_SECURITY_ADMIN_USER={아이디}
# 비번
- GF_SECURITY_ADMIN_PASSWORD={비밀번호}
- GF_FEATURE_TOGGLES_ENABLE=alertingSimplifiedRouting,alertingQueryAndExpressionsStepMode
그라파나 접속시에 사용할 아이디와 비밀번호 설정해줍니다.
전체코드
# docker-compose.yml
version: "3.3"
networks:
my_app_net:
external: true
name: {기존에 있는 Docker network}
services:
loki:
image: grafana/loki:latest
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/loki-config.yaml
volumes:
- ./loki-config.yaml:/etc/loki/loki-config.yaml
# 로그 데이터와 인덱스를 저장할 영속 볼륨 마운트
- loki-data:/loki
networks:
- my_app_net
promtail:
image: grafana/promtail:latest
container_name: promtail
# 포트 설정
ports:
- "9080:9080"
volumes:
# docker 데몬 소켓을 마운트하여 컨테이너 로그 및 메타 데이터 수집
- /var/run/docker.sock:/var/run/docker.sock
# promtail 설정
- ./promtail-config.yml:/etc/promtail/promtail-config.yml
# positions파일이 유지되도록 호스트와 볼륨 마운트
# 로그 읽기 위치 정보를 저장
- promtail-positions:/var/log
# 새로운 promtail설정에 맞춰 config.yml -> promtail-config.yml
command: -config.file=/etc/promtail/promtail-config.yml
networks:
- my_app_net
grafana:
environment:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
# 익명 접근 비활성화
- GF_AUTH_ANONYMOUS_ENABLED=false
# ID
- GF_SECURITY_ADMIN_USER={아이디}
# 비번
- GF_SECURITY_ADMIN_PASSWORD={비밀번호}
- GF_FEATURE_TOGGLES_ENABLE=alertingSimplifiedRouting,alertingQueryAndExpressionsStepMode
entrypoint:
- sh
- -euc
- |
mkdir -p /etc/grafana/provisioning/datasources
cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
orgId: 1
url: http://loki:3100
basicAuth: false
isDefault: true
version: 1
editable: false
EOF
/run.sh
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
networks:
- my_app_net
volumes:
# 로키 로그 데이터와 인덱스 정보를 저장할 볼륨
loki-data:
# Promtail이 마지막으로 읽은 로그 위치 정보를 저장
promtail-positions:
4. 테스트
컨테이너를 실행하고 브라우저를 통해 그라파나에 접속합니다.
docker compose up --build
아이디와 비밀번호를 치고 들어가면 다음과 같은 화면이 뜰 것 입니다. Explore에 들어가줍니다.

라벨 필터를 설정하고 Run query를 누르면 로그를 확인할 수 있습니다

로그가 잘 나오는것을 확인할 수 있습니다.


특정 로그를 검색할 수도 있습니다.

더욱 다양한 설정과 기능이 있을것으로 생각됩니다.
제 포스팅은 맛보기로 보시고 원하시는 로그 관리 시스템 구축하시길 바라겠습니다.
참고
https://grafana.com/docs/loki/latest/setup/install/docker
Install Loki with Docker or Docker Compose | Grafana Loki documentation
Install Loki with Docker or Docker Compose You can install Loki and Promtail with Docker or Docker Compose if you are evaluating, testing, or developing Loki. For production, Grafana recommends installing with Helm or Tanka. The configuration files associa
grafana.com
https://techblog.woowahan.com/14505/
따끈따끈한 전사 로그 시스템 전환기: ELK Stack에서 Loki로 전환한 이유 | 우아한형제들 기술블로그
안녕하세요. 클라우드모니터링플랫폼팀의 이연수입니다. 우아한형제들의 모니터링시스템 구축 및 관리, 운영을 하고 있습니다. 작년부터 올해 초까지 팀에서 전사 로그 시스템을 전환을 진행
techblog.woowahan.com
https://leonkong.cc/docker-compose-grafana-loki#b39649559e184a5792c4633fa6aedbe7
docker-compose로 Grafana, Loki 요리해보기
공채원의 기술 블로그입니다. 주로 개발과 관련해 공부한 내용들을 정리합니다. 현재 Go로 백엔드 개발을 하고 있습니다.
leonkong.cc
초보 개발자의 글이라 부족한점이 많습니다. 잘못된점 등을 지적해주시면 감사하게 받겠습니다.