EKS에 LGTM 스택 구축하기 - Loki, Grafana, Tempo, Mimir 실전 셋업 가이드
EKS 클러스터에 Grafana LGTM 스택을 Helm으로 배포하고, OTel Collector 사이드카로 Spring Boot 앱의 로그·트레이스·메트릭을 수집하는 전체 과정을 다룹니다.
배경
EKS 클러스터에서 서비스를 운영하다 보면 로그, 트레이스, 메트릭을 한 곳에서 볼 수 있는 모니터링 환경이 필요해진다. Datadog이나 New Relic 같은 SaaS를 쓰면 편하지만, 호스트와 로그량 기반 과금이 서비스가 커질수록 부담이 된다.
LGTM 스택(Loki, Grafana, Tempo, Mimir)은 Grafana Labs의 오픈소스 조합으로, EKS에 Helm으로 배포하면 인프라 비용만으로 운영할 수 있다. OTel(OpenTelemetry) 표준 기반이라 벤더 종속 없이 수집 파이프라인을 구성할 수 있고, 나중에 백엔드를 바꿔도 애플리케이션 코드를 수정할 필요가 없다.
이 글에서는 LGTM 스택을 EKS에 배포하고, Spring Boot 앱에 OTel Collector 사이드카를 붙여 로그·트레이스·메트릭을 수집하는 전체 과정을 단계별로 다룬다.
최종 구성:
사전 준비 EKS 클러스터 (1.28+) kubectl, Helm 3 설치 S3 버킷 (Loki/Tempo/Mimir 저장소용) IRSA 설정 가능한 IAM 권한
이 글에서는 observability라는 namespace에 LGTM 스택을 배포한다. 실제 환경에서는 전용 노드풀로 격리하는 것을 추천한다.
1단계: IRSA - S3 접근 권한 설정
Loki, Tempo, Mimir 모두 S3에 데이터를 저장한다. IRSA(IAM Roles for Service Accounts)로 Pod에 S3 접근 권한을 부여하면 Access Key를 하드코딩할 필요가 없다.
IAM Policy 생성
ServiceAccount 생성
모든 LGTM 컴포넌트가 이 ServiceAccount를 공유한다. Helm values에서 serviceAccount.create: false, serviceAccount.name: lgtm으로 설정하면 된다.
2단계: Loki 배포 - 로그 저장소
Helm repo 추가:
Loki values 작성
배포
핵심 설정 설명
| 설정 | 값 | 이유 | |||| | deploymentMode | SimpleScalable | backend/read/write 분리로 역할별 스케일링 가능 | | auth_enabled | false | 멀티테넌시 불필요 시 Grafana 연결이 간소화됨 | | store | tsdb | Loki 3.x 권장 인덱스 형식 | | schema | v13 | 최신 스키마, structured metadata 지원 | | replication_factor | 1 | 단일 레플리카 환경. HA 필요 시 3으로 변경 | 주의: auth_enabled: true로 두면 Grafana 데이터소스 설정에서 X-Scope-OrgID 헤더를 직접 넣어야 한다. 단일 테넌트에서는 false가 편하다.
3단계: Tempo 배포 - 분산 트레이싱
Tempo values 작성
배포
핵심 설정 설명
| 설정 | 값 | 이유 | |||| | traces.otlp.grpc/http | true | OTel Collector에서 OTLP로 트레이스 수신 | | distributor.replicas | 2 | 트레이스 수신 가용성 확보 | | ingester.persistence | 20Gi | WAL(Write Ahead Log) 저장. 데이터 유실 방지 | | metricsGenerator | enabled | 트레이스에서 서비스 그래프/span 메트릭 자동 생성 |
metricsGenerator를 켜면 Grafana에서 서비스 간 호출 관계를 시각적으로 볼 수 있다. 트레이스를 수동 분석하지 않아도 서비스 토폴로지가 자동으로 그려진다.
4단계: Mimir 배포 - 메트릭 장기 저장
Mimir values 작성
배포
핵심 설정 설명
| 설정 | 값 | 이유 | |||| | ingest_storage.enabled | false | Kafka 없는 classic 아키텍처 | | wal_compression_enabled | true | ingester 디스크 사용량 절약 | | ship_interval | 2m | 2분마다 S3로 블록 업로드. 데이터 유실 최소화 | | retention_period | 2160h | 90일 보관. 필요에 따라 조정 | | zoneAwareReplication | false | 단일 레플리카에서는 비활성 필수 | 주의: Mimir 6.x (3.0)부터 기본이 Kafka 기반 ingest로 바뀌었다. classic 모드로 쓰려면 ingest_storage.enabled: false를 명시해야 한다.
5단계: Grafana 배포 - 대시보드