deploy 환경 로그 수집
웹 애플리케이션을 배포하고 문제가 발생하면 에러 로그를 봐야 하는 경우도 있다. 예를 들어서 도커 컨테이너로 배포했다면 jar를 실행하는 컨테이너의 로그를 직접 확인하는 방법이 있다.
순식간에 로그들이 쌓이고 직접 찾기에는 효율적이진 않다. (제가 이 방법을 계속하고 있었죠..)
위에처럼 불편하게 로그를 일일이 확인하지 않고 ERROR 로그들만 수집해서 모아놓고 보고 싶었다. 다른 로그 레벨들도 존재하겠지만 지금 당장은 ERROR 로그들만 수집하려고 한다.
에러 로그를 수집해서 확인하는 방법은 여러 가지 존재하지만 이번에는 ELK 스택을 사용해 보려고한다.
ELK 스택
ELK 스택은 Elasticsearch, Logstash, 그리고 Kibana의 약자로, 로그 및 이벤트 데이터를 수집, 저장, 분석, 시각화하는 데 사용되는 오픈 소스 도구들의 모음이다. 이 도구들은 웹 서버의 로그를 수집하는데 서로 다른 역할을 담당한다.
Elasticsearch
분산 검색 및 분석 엔진으로 데이터를 저장하고 검색하는 역할을 한다. 많은 데이터를 안정적으로 저장하고 검색 및 집계가 가능하며 로그, 지표, 트랜잭션 등의 다양한 유형의 데이터를 색인화하고 검색하는 데 사용한다.
Logstash
로그 데이터를 수집하고 처리, 변환하여 Elasticsearch 또는 다른 저장소로 전송하는 역할을 한다. 즉, 수집한 데이터를 Elasticsearch 또는 다른 저장소로 전송하는 과정에서 데이터를 수집하고, 필터링, 변환, 가공까지 담당한다.
Kibana
Elasticsearch에 저장된 데이터를 분석하거나 시각화하여 대시보드를 생성할 수 있는 웹 인터페이스이다.
Elasticsearch에서 검색된 데이터를 탐색하거나 그래프, 차트 등 시각화 가능하다.
로그는 이러한 흐름으로 수집하고 시각화한다.

웹 애플리케이션 서버에서 Logstash로 에러 로그를 전송한다.
Logstash는 필터링, 변환을 통해 가공한 데이터를 엘라스틱 서치로 전송한다.
Kibana에서는 엘라스틱 서치에 저장되어 있는 데이터를 index를 기반으로 시각화한다.
docker compose로 ELK 스택 이미지 구성하기
기본 이미지를 사용해도 컨테이너가 실행되는데 문제는 없지만 yml을 정의해서 넘겨준다.
ELK yml 설정
보안 설정은 xpack.security 옵션을 변경하면 된다.
elastic 8버전 이상부터는 ssl을 필수로 사용하는 것 같다.
xpack.security는 보안 관련이다. 접속 시 로그인이 필요하다면 설정하면 된다.
host를 0.0.0.0으로 설정해서 모든 네트워크 인터페이스에서 들어오는 요청을 수럭하도록 구성한다.
[logstash.conf]
input 섹션
로그 데이터를 수신하는 입력 플러그인 설정이다.
TCP 프로토콜을 통해 데이터를 수신하는데 5000 port에서 로그 데이터를 수신한다.
수신된 데이터는 json 형식의 라인으로 인코딩된다.
웹 서버에서 로그 파일을 생성해서 기록하고 파일을 읽어올 수 있겠지만, ec2 프리티어 인스턴스를 사용하기 때문에 자원을 최대한 적게 사용하려고 로그 파일을 생성하지 않고 로그가 발생하면 전송하도록 했다.
filter 섹션
입력된 로그를 처리하는 필터 플러그인 설정이다. 에러 로그만 수집하기 위해서 로그 항목의 level이 "ERROR"가 아닌것은 버린다.
output 섹션
Elasticsearch 인스턴스 호스트 주소와 포트를 설정하고, Elasticsearch에 접근하기 위해서 user와 password를 설정한다. index는 로그가 저장될 인덱스 이름이다. "logstash-%{+YYYY.MM.dd}" 형식의 인덱스에 로그가 저장된다.
Kibana index 패턴과 Elasticsearch Index Lifecycle Policy 자동 설정
ec2 프리 티어를 사용하기 때문에 한정된 자원을 효율적으로 사용할 필요가 있다고 느꼈다.
따라서 웹 서버가 배포될 때마다 ELK 컨테이너도 다시 빌드 하면서 이전 로그들을 지우고, 너무 오랫동안 로그가 남으면 그만큼 메모리를 차지하기 때문에 로그를 보관하는 기간도 설정해야 했다.
하지만 서버가 자주 재배포 된다면 인덱스 패턴을 생성하고 Lifecycle Policy를 매번 재설정하는데 번거로움이 있겠다고 생각해서 쉘 스크립트를 작성해서 자동화를 하도록 해봤다.
[script.sh]
엘라스틱 서치 컨테이너의 실행을 health check로 확인하고 ILM 정책을 설정한다. 저장하는 기간은 7일로 설정했다.
Kibana도 똑같이 컨테이너의 실행을 확인하고 인덱스 패턴을 생성하게 하는 스크립트이다.
Springboot Logback 설정
스프링부트에서 발생한 로그를 logstash가 읽을 수 있는 json으로 변환해야 한다. 이를 도와주는 encoder 라이브러리를 추가한다.
[logback-spring.xml]
logstash encoder 를 적용한 appender를 작성한다. 에러를 필터링 하는것을 logstash filter에 위임했지만 여기서 필터를 설정해서 ERROR 로그만 logstash에 전송하는 방법도 존재한다.
Summary
결론적으로 서버의 로그를 logstash로 보내는 방법은 두 가지가 있다.
서버의 log를 file로 저장하고 logstash에서 파일을 읽는 방법.
서버의 log를 logstash에 tcp로 전송하는 방법
에러 로그를 수집하는 방법은 많이 존재할 것이다. 이전에 Sentry라는 에러 로그를 수집, 트래킹 하는 도구를 사용했었다. 무료 라이센스가 한 달이었고 이를 구성하는 것도 ELK를 사용하는 것보다 복잡하다고 생각한다.
그럼 ELK를 사용해서 로그를 수집하는 게 더 좋은가??
이것도 잘 모르겠다. 환경을 구성하는 것에 큰 어려움은 없었다. (너무 단순하게 구성해서 그럴 수 있다.) ELK를 ec2 프리 티어로 사용하는데 너무 무겁다. 로그를 확인하러 들어가는 데 가끔은 많은 시간이 걸리기도 했다. 로그만 수집하는 것이 아니라 APM과 같은 다른 부가적인 기능들을 더 사용한다면 적합할 수 있겠지만 로그 수집으로만 사용한다면 그건 또 아닌 거 같다.
만약 자원이 많고 에러를 위한 인프라가 필요했다면 Sentry를 사용할 것 같다.
Last updated