서비스 운영 중 "로그 좀 확인해주세요"라는 요청은 일상입니다.
하지만 서버가 10대만 넘어가도 각 서버에 접속해서 grep 명령어로 로그를 뒤지는 것은 매우 비효율적입니다.
게다가 로그 파일이 로테이션되어 사라지거나, 너무 커서 열리지 않는 경우도 다반사였습니다.
이러한 문제를 해결하기 위해 로그를 중앙에서 수집, 저장, 분석할 수 있는 ELK Stack (Elasticsearch, Logstash, Kibana)을 도입했습니다.
전체적인 데이터 흐름은 다음과 같습니다.
빠른 구축과 테스트를 위해 Docker Compose를 활용했습니다.
version: '3.7'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200
logstash:
image: docker.elastic.co/logstash/logstash:7.17.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- 5044:5044
kibana:
image: docker.elastic.co/kibana/kibana:7.17.0
ports:
- 5601:5601
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200
Spring Boot 애플리케이션 로그를 파싱하기 위한 설정 예시입니다. Grok 패턴을 사용하여 로그 레벨, 클래스명, 메시지 등을 분리합니다.
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{DATA:pid} --- [%{DATA:thread}] %{DATA:class} : %{GREEDYDATA:log_message}" }
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}
로그가 발생하는 서버에 Filebeat를 설치하고 설정을 수정합니다.
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/myapp/*.log
output.logstash:
hosts: ["elk-server-ip:5044"]
Kibana에 접속하여 Index Pattern(app-logs-*)을 생성하면 수집된 로그를 실시간으로 확인할 수 있습니다.
이제 level: ERROR 검색어 하나만으로 전체 서버의 에러 로그를 한 번에 모아볼 수 있습니다.
"시간대별 에러 발생 추이", "가장 많이 호출된 API Top 10", "응답 시간이 느린 트랜잭션" 등을 시각화하여 대시보드로 만들었습니다. 이를 통해 배포 직후 에러율 급증을 1분 안에 감지하고 즉시 롤백하는 등 운영 안정성이 대폭 향상되었습니다.