통합 모니터링의 필요성
Issuefy 프로젝트를 진행하면서 중점을 둔 부분은 바로 모니터링 시스템의 구축이었습니다. 이전 프로젝트들에서 경험했던 문제점들을 토대로, 이번 프로젝트에서는 보다 효과적이고 안정적인 모니터링 체계를 갖추고자 했습니다.
지속적인 모니터링의 부재
과거 프로젝트에서는 주로 인프라 구성과 CI/CD 파이프라인 구축에 초점을 맞추다 보니, 서비스 운영 과정에서의 지속적인 모니터링이 소홀해지는 경향이 있었습니다. 배포 자동화에만 집중한 나머지 배포 이후의 서비스 상태 모니터링은 상대적으로 간과되었고, 이로 인해 인프라나 애플리케이션에 문제가 발생해도 개발팀이 신속하게 인지하지 못하는 상황이 종종 발생했습니다.
통합된 로깅 전략 및 로그 분석 도구의 필요성
서비스 운영 중 이슈가 발생하여 로그를 확인해야 할 때, 팀 내에 일관된 로깅 전략이 부재하여 어려움을 겪었습니다. 개발자마다 각자의 스타일로 로그를 작성하다 보니 로그 포맷이 통일되지 않았고, 문제 상황과 관련된 로그를 찾아내는 것 자체가 쉽지 않았습니다. 게다가 로그 분석을 위한 적절한 도구가 없어 단순히 "docker logs" 명령어로 컨테이너의 로그를 확인하는 수준에 그쳤기 때문에, 로그 파일의 가독성도 매우 떨어지는 문제가 있었습니다.
애플리케이션 내부 메트릭 모니터링의 필요성
단순히 로그 모니터링뿐만 아니라, JVM과 같은 애플리케이션 런타임 환경의 내부 메트릭도 모니터링할 필요성을 느꼈습니다. 힙 메모리 사용량, 가비지 컬렉션 동작 여부 등을 실시간으로 모니터링함으로써 메모리 누수나 성능 이슈를 사전에 탐지하고 대응할 수 있기 때문입니다.
확장 가능한 인프라에 적합한 모니터링 및 알림 체계
이번 프로젝트에서는 오토 스케일링과 컨테이너 오케스트레이션을 활용하여 트래픽 변화에 유연하게 대응할 수 있는 확장성 있는 인프라를 구성하고자 했습니다. 비록 프로젝트 규모가 크지 않아 실제로 대량의 트래픽이 발생할 가능성은 적었지만, 이러한 아키텍처 상에서의 모니터링 경험을 쌓는 것 자체가 의미 있다고 판단했습니다. 오토 스케일링되는 인스턴스의 리소스 사용량을 모니터링하고, 문제 상황 발생 시 적절한 알림을 받을 수 있는 체계를 갖추는 것이 목표였습니다.
이에 Issuefy 프로젝트의 인프라를 설계할 때, 단순히 개발과 배포에 그치지 않고 운영 과정에서의 통합 모니터링 체계를 갖추는 것에 초점을 두었습니다. 요구사항 분석 단계에서부터 모니터링 시스템의 필요성을 명확히 하고, 이를 아키텍처 설계에 반영하여 구현함으로써 서비스 운영 과정에서의 가시성과 안정성을 확보하고자 했습니다.
요구사항 수집 및 분석 → 설계 → 개발(문서화) → 배포 → 모니터링
기술스택 및 구성
AWS CloudWatch는 사용하기에 가장 간편하고 효율적인 모니터링 도구이지만 비용 부담이 크다는 단점이 있습니다. 반면 오픈소스 모니터링 도구는 비용 부담을 최소화하면서도 필요한 기능을 제공할 수 있습니다. 비용 비교를 위해 한 달 동안 2만 개의 사용자 정의 메트릭을 수집하는 시나리오를 가정했습니다.
한 달 동안 20,000개의 메트릭을 수집하는 경우를 가정해 보았을 때 서울 리전에서 CloudWatch를 사용할 경우 약 6달러의 비용이 발생할 것으로 예상되었습니다. 향후 메트릭 수가 증가한다면 비용은 7~8달러까지 상승할 수 있습니다.
반면 오픈소스 모니터링 도구를 사용하는 경우, 20,000개의 메트릭 데이터 크기는 1GB 이하일 것으로 판단했습니다. AWS에서는 인바운드 데이터 전송은 무료이고, 아웃바운드 데이터 전송은 매월 모든 리전의 서비스를 합산하여 100GB까지 무료로 제공됩니다. 따라서 오픈소스 도구를 사용할 경우 비용이 발생할 가능성이 낮았습니다. 추가 비용이 발생하더라도 GB당 0.126달러로, CloudWatch에 비해 훨씬 저렴한 편입니다.
이러한 비용 분석 결과를 바탕으로 오픈소스 기반의 모니터링 기술 스택을 선택하게 되었습니다.
통합 모니터링을 위해 선정한 기술 스택은 Prometheus, Node Exporter, Logback, Promtail, Loki, Grafana 였습니다.
- Prometheus는 풍부한 자료와 수평적 확장성, 강력한 시계열 데이터 수집 기능을 갖추고 있어 선택하게 되었습니다.
- Node Exporter는 Prometheus와 함께 사용하기에 적합하며, 인스턴스의 상태를 모니터링하는 데 유용합니다.
- Logback은 스프링 부트에 기본적으로 내장되어 있어 기본적인 로그 출력에 적절하다고 판단했습니다.
- Promtail은 실시간 로그 수집에 강점이 있고, Loki 및 Grafana와의 연동이 쉽습니다.
- Loki는 Grafana와 연동하기 좋고 Prometheus의 PromQL과 유사한 LogQL을 지원해서 학습하기에 적합했습니다.
- Grafana는 Prometheus, Node Exporter, Loki 모두를 지원하여 통합 모니터링 대시보드를 구축하는 데 적합했습니다.
서비스 인스턴스에는 Spring 컨테이너와 함께 Node Exporter, Promtail 등의 에이전트 컨테이너를 함께 실행하여 메트릭과 로그를 수집합니다. 수집된 메트릭은 스케일 아웃 시에도 지속적으로 수집되어야 했기 때문에, 메트릭을 모니터링 인스턴스의 Prometheus와 Loki로 전송하도록 구성했습니다.
오토 스케일링으로 인해 서비스 인스턴스의 수가 가변적이므로, Prometheus가 동적으로 메트릭 수집 대상을 인지할 수 있도록 Prometheus 서비스 디스커버리를 활용했습니다. 이를 통해 인스턴스가 추가되거나 제거될 때마다 Prometheus가 자동으로 모니터링 대상을 업데이트할 수 있도록 하였습니다.
서비스 인스턴스 내부에는 ECS로 관리되는 5개의 컨테이너가 실행되게 되었고, 모니터링 인스턴스에는 Node Exporter 컨테이너, ASG 메트릭을 수집하는 Prometheus 컨테이너, 그리고 Grafana 컨테이너가 실행되도록 구성했습니다.
도입 결과
통합 모니터링 시스템 구축을 완료한 결과, Grafana 대시보드를 통해 서비스 전반의 상태를 한눈에 파악할 수 있게 되었습니다. JVM Micrometer, Node Exporter, Application log 등의 대시보드를 통하여 다양한 메트릭과 로그 데이터를 수집하고 시각화함으로써, 현재 배포되어 있는 서비스들의 동작 상태를 보다 상세하게 모니터링할 수 있게 되었습니다.
Grafana 대시보드에는 개발팀이 주시해야 할 주요 지표들을 한 곳에 모아 실시간으로 확인할 수 있도록 구성하였습니다. CPU 사용량, 메모리 사용량, 디스크 I/O, 네트워크 트래픽 등 인프라 리소스 관련 메트릭등 다양한 데이터를 한 자리에서 모니터링할 수 있습니다.
뿐만 아니라 Grafana의 알림 기능을 활용하여 문제 상황 발생 시 신속하게 대응할 수 있는 체계를 마련하였습니다. Grafana의 Alert rules을 설정하여 특정 메트릭이 임계값을 벗어나거나 이상 패턴이 감지되면 즉시 알림을 받을 수 있도록 하였습니다. 알림은 Slack 봇을 통해 개발팀 채널로 전달되도록 설정하여, 담당자가 빠르게 인지하고 대응 조치를 취할 수 있게 하였습니다.
트러블 슈팅
Promtail과 Loki를 연동하는 과정에서 문제 상황에 직면했습니다.
구성
먼저 배포 인스턴스의 Spring 컨테이너는 Logback을 사용하여 3개의 로그 파일을 롤링하면서 호스트 인스턴스의 EBS에 로그를 기록하고 있었습니다. 그리고 같은 인스턴스에 Promtail 컨테이너는 호스트 인스턴스의 로그 디렉터리를 마운트 하여로그를 수집하도록 구성하여 마운트 된 로그 디렉터리를 스크레이핑 하도록 설정했습니다.
Promtail의 설정 파일에서는 수집한 로그를 모니터링 인스턴스에서 실행 중인 Loki 컨테이너로 전송하도록 Private ip를 사용하여 설정했습니다. Promtail의 로그를 확인해 보니 로그 파일에 대한 테일링이 정상적으로 시작되었다는 메시지가 출력되었고, Loki의 로그에서도 Promtail로부터 수신한 로그 데이터가 정상적으로 처리되었다는 내용을 확인할 수 있었습니다.
문제 상황
하지만 Grafana에서 로그를 조회해 보면 약 1시간가량 새로운 로그가 없을 경우 No data 메시지가 표시되고, 로그 익스플로러에서도 레이블이나 소스가 나타나지 않는 문제가 발생했습니다. 그러다 새로운 로그가 생성되면 다시 Grafana에 로그가 정상적으로 표시되는 현상을 관찰할 수 있었습니다.
시도 방법
이에 문제 해결을 위해 다음과 같은 시도를 해보았습니다.
- Promtail 컨테이너의 로그를 확인했으나 테일링 시작 메시지 외에는 특별한 이상 로그가 발견되지 않았습니다.
- Loki 컨테이너의 로그에서는 가끔 쿼리 결과가 0개라는 메시지가 출력되긴 했으나 명확한 에러 로그는 찾을 수 없었습니다.
- 네트워크 연결 문제일 수도 있다고 생각하여 Promtail 컨테이너 내부로 접속하여 모니터링 인스턴스를 대상으로 curl 명령어를 사용하였지만 정상적으로 응답이 왔습니다.
- 마찬가지로 네트워크 문제를 의심하여 Grafana datasource 설정에서 클라이언트 URL을 외부 IP에서 내부 IP로 변경해 보았으나 실패했습니다.
- Loki 설정파일의 Stroage의 저장 경로를 /tmp이기 때문에 파일이 자동으로 삭제되는 것이 아닐까 하여 저장 경로를 /opt로 변경하는 것도 시도해 보았지만 역시 실패했습니다.
- Promtail 컨테이너에 마운트 된 로그 파일과 디렉터리의 읽기 전용 속성을 해제해 보았으나 문제 해결에는 도움이 되지 않았습니다.
- Promtail 컨테이너의 메모리가 부족하여 작업을 중지시키는 것이 아닐까 하여 컨테이너 메모리 제한을 128MB에서 256MB로 증가시켜 보았지만 효과는 없었습니다.
- 1시간가량 로그가 잘 나타나는 것으로 보았을 때 Loki와 Grafana 간의 커넥션 타임아웃 문제일 수 있을 것이라 예상했으나 관련 정보를 찾을 수 없었습니다.
그러던 중 Loki의 로그를 좀 더 자세히 살펴보니 no data 현상이 나타났다 새로운 로그가 생성되었을 때 "empty ring" 에러 로그가 발생하는 것을 확인할 수 있었습니다. 그리고 로그가 다시 나타날 때 WAL에 의해 복구되었다는 로그가 있었습니다. 이에 따라 Loki의 Ring Store를 Inmemory에서 etcd로 변경하는 방안을 시도해 보았지만 마찬가지로 실패했습니다.
해결
이렇게 Promtail, Loki, Grafana의 설정을 꼼꼼히 확인했음에도 불구하고 문제의 원인을 찾을 수 없었습니다. 그래서 Loki의 공식 문서를 다시 한 번 자세히 읽어보게 되었습니다. 그러던 중 한 가지 중요한 사실을 깨달을 수 있었는데, 바로 Loki가 LogQL이라는 쿼리 언어를 기반으로 동작한다는 점이었습니다.
이때 저는 문득 이런 생각이 들었습니다. "Loki가 쿼리를 날렸을 때 정말로 로그 데이터가 없어서 'No data'를 반환하고 있는 것은 아닐까?" 이러한 생각에 Grafana 대시보드의 시간 범위를 조정하고 페이지를 새로고침해보기로 했습니다.
시간 범위를 변경하고 새로고침을 하자 로그 데이터가 정상적으로 나타나기 시작했습니다. 로그 수집 파이프라인 자체는 정상적으로 동작하고 있었지만, 대시보드의 쿼리 설정으로 인해 로그가 없어 보이는 현상이 발생한 것이었습니다. 대시보드에 접속했을 때 기본적으로 1시간의 범위를 가진 LogQL 쿼리가 발생하고 이에 대한 결과가 대시보드에 표현되는 것이었습니다.
이를 통해 단순히 시스템을 구성하고 동작시키는 것에 그치지 않고, 내부 동작 원리를 깊이 있게 이해하고 학습해야 한다는 깨달음을 얻을 수 있었습니다.
마치며
통합 모니터링 시스템을 구축하는 과정은 결코 쉽지만은 않았습니다. 단순히 모니터링 도구를 설치하고 데이터를 수집하는 것 이상의 복잡한 작업이 필요했기 때문입니다.
우선 모니터링 시스템이 서비스의 인프라와 아키텍처에 맞게 설계되어야 했습니다. 특히 오토 스케일링 그룹을 사용하여 동적으로 인스턴스 수를 조정하는 환경에서는, 모니터링 시스템도 이에 맞춰 유연하게 대응할 수 있어야 했습니다. 새로운 인스턴스가 추가되면 자동으로 모니터링 대상으로 포함되고, 인스턴스가 제거되면 모니터링 대상에서도 제외되어야 합니다. 이를 위해 ASG와 연동되는 서비스 디스커버리 메커니즘을 활용해야 했고, 이는 모니터링 시스템 설계에 복잡성을 더했습니다.
또한 ECS를 사용하여 서비스를 컨테이너로 배포하는 환경에서는, 컨테이너 단위로 메트릭과 로그를 수집해야 했습니다. 이를 위해 각 서비스 컨테이너와 함께 메트릭과 로그 수집을 위한 에이전트 컨테이너를 사이드카 패턴으로 배포해야 했습니다. 에이전트 컨테이너는 서비스 컨테이너의 상태를 모니터링하고, 필요한 데이터를 수집하여 중앙 모니터링 시스템으로 전송하는 역할을 합니다.
이 중 가장 어려웠던 점은 바로 이런 동적인 환경에서 안정적이고 일관된 모니터링을 제공하는 것이었습니다. 오토 스케일링으로 인해 인스턴스가 동적으로 추가되고 제거되는 상황에서도, 모든 인스턴스의 메트릭과 로그가 빠짐없이 수집되어야 합니다. 이를 위해서는 에이전트 컨테이너의 설정과 버전 관리가 일관되게 이루어져야 하고, 모니터링 시스템과의 연결도 안정적으로 유지되어야 합니다.
뿐만 아니라 컨테이너 간 통신과 데이터 공유를 위한 설정도 필요했습니다. 에이전트 컨테이너가 서비스 컨테이너의 로그 파일에 접근하기 위해서는 호스트 인스턴스의 EBS 볼륨을 마운트하고, 이에 대한 접근 권한을 적절히 설정해야 했습니다. 이런 작업은 컨테이너 오케스트레이션과 밀접한 관련이 있으므로, ECS의 작동 방식에 대한 추가적인 학습이 필요했습니다.
이렇게 다양한 요소들을 고려하고 통합하는 과정에서 수많은 시행착오를 겪었습니다. 설정 파일의 오류, 네트워크 문제, 권한 설정의 실수 등으로 인해 모니터링 시스템이 제대로 동작하지 않는 경우가 많았고, 하나하나 문제를 해결해 나가는 과정이 도전의 연속이었습니다.
하지만 이런 어려움을 극복하고 안정적인 모니터링 시스템을 구축할 수 있었던 원동력은 다름 아닌 개발 과정 자체에서 얻는 즐거움과 성취감이었습니다. 확장 가능한 인프라를 설계하고 이를 개발 과정에 실제로 적용하는 과정이 참 즐거웠습니다.
이번 통합 모니터링 시스템을 구축하며 얻은 것들이 많다고 생각합니다. 서비스에 대한 가시성과 안정성을 확보하고, 문제 상황에 유연하게 대처할 수 있는 기반을 만드는 소중한 경험이 되었습니다. 물론 현재 구축한 모니터링 시스템은 기초 수준이며, 앞으로도 지속적으로 발전시켜 나가고자 합니다. 특히 PromQL과 LogQL을 통해 대량의 메트릭과 로그 데이터 속에서 원하는 정보를 정확하게 추출하여 활용할 수 있도록 학습할 계획입니다.
'Issuefy' 카테고리의 다른 글
[Issuefy] Jmeter를 사용한 성능 테스트 및 스케일링 분석 (0) | 2024.09.23 |
---|---|
[Issuefy] Server-Sent Events를 이용한 실시간 알림 기능 도입기 (4) | 2024.09.13 |
[Issuefy]Loki와 LogQL을 활용한 실시간 사용자 활동 대시보드 구현 (2) | 2024.09.05 |
[Issuefy] 의심스러운 로그 탐지 및 대응기 (3) | 2024.06.06 |