[Observability] Loki와 Promtail을 이용한 로그 모니터링 아키텍쳐
서버를 운영하게 되면 로그는 자연스럽게 발생한다. 이러한 로그들은 양도 많을 뿐더러 관리하는 서버의 수가 많아지면 그 내용들을 일일히 직접 확인하기란 어려울 따름이다. 그래서 로그 수집과 가시화 시스템을 구축하여 로그들을 모니터링하게 된다.
이번에는 Loki와 Promtail, Grafana를 이용해 로그를 모니터링하는 아키텍쳐를 구축해보도록 한다.
Loki & Promtail
Like Prometheus, but for logs
Loki는 오픈소스 타입의 로그 모니터링 도구로, 로그를 Label을 통해 그룹화해 처리한다. Prometheus가 Metric을 수집하는데에 목적을 두었다면, Loki는 로그를 수집하는데에 목적을 둔 도구로 볼 수 있다.
로그 라인의 메타데이터(Label)를 인덱싱해, 그 Label 단위로 로그 메시지를 압축시킨 뒤 chunk단위로 저장해 스토리지 사용량을 더 줄일 수 있게 된다.
Loki는 LogQL이라는 query language를 이용한다. 이는 Prometheus의 PromQL과 유사한 구조로, 이를 사용할 줄 알면 큰 어려움없이 LogQL도 사용할 수 있다.
Promtail은 로그를 수집하는 에이전트로, 로그를 수집해 Loki로 로그를 전송하는 역할을 맡는다. Loki는 Promtail 외에도 Fluentd, logstash와도 같이 사용할 수 있도록 지원한다.
Promtail은 수집한 로그 데이터를 Push해주는 방식으로 Loki에 전달한다.
Loki-Promtail-Grafana 아키텍쳐는 ELK stack과 비교될 수 있다.
ELK stack과 비교하면 Loki 아키텍쳐는 다음과 같은 장점이 존재한다.
- 사용과 구축이 비교적 간단하다
- 저장공간과 CPU, 메모리 리소스를 적게 먹는다
- 쿠버네티스 환경에 친화적이다
다만, 다음과 같은 점은 ELK stack에 비해 단점으로 작용한다.
- 로그 검색 기능
- 앞서 이야기 했듯이 메타데이터를 바탕으로 색인화를 하고 로그 본문을 색인화하지 않기 때문에 ElasticSearch같이 복잡한 쿼리와 빠른 검색속도에 밀리게 된다.
Loki 아키텍쳐 구축
k8s 클러스터에 배포된 파드에서 발생하는 로그들을 수집해 가시화해주는 Grafana-Loki-Promtail 아키텍쳐를 구축해보도록 한다.
간단하게 클러스터를 하나 구축한 뒤 Nginx 서비스를 배포 후, 이 파드들에서 발생하는 로그들을 Grafana-Loki-Promtail 아키텍쳐로 수집 후 가시화 해보기로 한다.
먼저 grafana helm 저장소를 추가해준다.
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
다음으로 먼저 Nginx 서비스를 배포하도록 한다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test-nginx
name: test-nginx
spec:
replicas: 3
selector:
matchLabels:
app: test-nginx
template:
metadata:
labels:
app: test-nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc
name: nginx-svc
spec:
ports:
- name: 8080-80
nodePort: 31080
protocol: TCP
targetPort: 80
port: 80
selector:
app: test-nginx
type: NodePort
이어서 앞서 추가한 grafana 저장소의 loki-stack을 설치해준다. 해당 value 파일에는 Loki와 promtail 외에도 다른 요소들도 구성은 되어있는 상태이다. 기본적으로 Loki, Promtail 이외 것들은 disable되어있다.
helm install loki-stack grafana/loki-stack -n monitoring
그리고 grafana를 설치한다. value 파일을 받아 admin과 port부분을 약간 수정해준다. (grafana를 nodeport로 지정해 간단하게 내용을 확인하기 위함)
helm show values grafana/grafana > grafana.yml
helm install grafana grafana/grafana -f grafana.yml -n monitoring
이어서 Grafana에 접속 후, 좌측 패널에 Connections > Data Sources에서 앞서 생성한 Loki를 연결해준다.
Loki의 접속 URL을 작성 후 Save하면 Test connection이 진행되고 저장된다.
+) grafana/loki-stack의 내용 중 loki의 버전에 이슈가 있는 것을 발견했다. loki-stack value 파일을 사용하는 경우, helm install 이후 loki의 버전을 수정해주어야한다.
이 글에서는 간단하게 Loki 아키텍쳐를 구성하기 위해 loki-stack을 사용했으나, loki와 promtail을 각각 별도로 install하도록하자
kubectl edit statefulset loki-stack -n monitoring
image: grafana/loki:2.6.1 => grafana/loki:2.9.7
그리고 대시보드에서 이 Data Source를 가져와 쿼리를 작성한다. 쿼리를 작성 후 Run Query로 결과를 패널에서 확인할 수 있다.
아래는 Label Filter로 다른 namespace에 존재하는 nginx 파드의 로그를 가져온 것이다.
이렇게 Grafana에 Loki를 연결해 클러스터 내의 파드 로그를 가져와 보았다. 검색능력은 ElasticSearch보다 떨어지는 경향을 보이나 로그의 메타데이터를 Label로 저장해 쿼리에서 호출하는 것으로 간단하게 로그를 검색할 수 있는 것을 볼 수 있다.
또한 ElasticSearch보다 훨씬 간단하게 구축할 수 있고, 많은 엔지니어들에게 친숙한 Grafana 대시보드와도 잘 연계가 되어있기에 꽤나 매력있는 모니터링 도구로 생각된다.
다음에는 이 Loki의 구조를 딥하게 알아보고 오브젝트 스토리지와의 연계도 진행해보도록 한다.
우아한형제들에서 Loki 아키텍쳐에 대한 설명과 도입과정을 잘 설명한 글이 있으니 읽어보도록 한다.