모니터링과 로깅 시스템 구축
지난 절에서는 NestJS 애플리케이션을 다양한 클라우드 플랫폼에 배포하는 전략에 대해 알아보았습니다. 이제 11장의 마지막 절로, 배포된 애플리케이션의 건강 상태를 지속적으로 확인하고, 문제 발생 시 신속하게 감지 및 진단할 수 있도록 모니터링(Monitoring)과 로깅(Logging) 시스템을 구축하는 방법에 대해 살펴보겠습니다.
애플리케이션을 성공적으로 배포하는 것만큼 중요한 것이 바로 안정적인 운영입니다. 문제가 발생하기 전에 잠재적인 위협을 감지하고, 문제가 발생했을 때 빠르게 원인을 파악하여 해결하기 위해서는 체계적인 모니터링과 로그 관리가 필수적입니다. "측정할 수 없으면 관리할 수 없다"는 말처럼, 시스템의 상태를 가시화하는 것이 운영의 시작입니다.
모니터링 시스템 구축
모니터링은 시스템의 주요 지표(메트릭)를 지속적으로 수집하고 시각화하여, 애플리케이션과 인프라의 성능, 가용성, 오류 등을 실시간으로 파악하는 활동입니다.
모니터링의 핵심 요소
- 메트릭(Metrics) 수집: CPU 사용률, 메모리 사용량, 네트워크 I/O, 디스크 I/O 등 인프라 메트릭과 함께, 애플리케이션 응답 시간, 처리량(QPS/RPS), 에러율, 데이터베이스 쿼리 시간 등 애플리케이션 메트릭을 수집합니다.
- 대시보드(Dashboards): 수집된 메트릭을 그래프, 차트 등으로 시각화하여 시스템의 현재 상태를 한눈에 파악할 수 있도록 합니다.
- 알림(Alerts): 특정 메트릭이 임계값을 초과하거나 비정상적인 패턴을 보일 때, 개발자나 운영자에게 이메일, SMS, Slack 등으로 알림을 보냅니다.
- 분산 트레이싱(Distributed Tracing): 마이크로서비스 아키텍처와 같이 여러 서비스가 복잡하게 얽혀 있는 환경에서, 단일 요청이 여러 서비스를 거쳐가는 과정을 추적하여 병목 지점을 파악합니다.
NestJS 모니터링 스택
9장 4절 "성능 모니터링과 프로파일링"에서 Prometheus와 Grafana를 이용한 NestJS 애플리케이션 모니터링의 기본 개념을 다뤘습니다. 여기서는 클라우드 배포 환경에 맞게 좀 더 구체화합니다.
구성 요소
- NestJS 애플리케이션:
prom-client
라이브러리를 사용하여 애플리케이션 메트릭을 Prometheus 형식으로 노출합니다. (/metrics
엔드포인트) - Prometheus: NestJS
/metrics
엔드포인트를 주기적으로 "스크랩(scrape)"하여 메트릭을 수집하고 저장합니다. - Grafana: Prometheus에서 수집된 메트릭 데이터를 가져와 시각적인 대시보드를 구축합니다.
- Alertmanager (선택 사항): Prometheus와 연동하여 정의된 알림 규칙에 따라 알림을 발생시킵니다.
클라우드 환경에서의 배포 예시 (AWS ECS/EKS 환경)
NestJS 앱 컨테이너: Docker 이미지에 prom-client
를 포함하고 /metrics
엔드포인트를 노출합니다.
Prometheus 서버 배포
- EC2 인스턴스에 직접 배포: 작은 규모에서 시작할 때 사용합니다. EC2에 Prometheus를 설치하고, NestJS 컨테이너의 IP 주소 또는 서비스 디스커버리(예: DNS)를 통해
targets
를 설정합니다. - Kubernetes (EKS)에 배포: Prometheus Operator를 사용하여 Kubernetes 클러스터에 Prometheus를 배포하는 것이 일반적입니다. 이는 서비스 디스커버리, 자동 설정 등을 강력하게 지원합니다.
- 관리형 Prometheus 서비스: AWS Managed Service for Prometheus (AMP), Google Cloud Managed Service for Prometheus (GMP) 등을 사용하여 Prometheus 서버 자체의 관리 부담을 줄일 수 있습니다.
Grafana 서버 배포
- EC2 인스턴스에 직접 배포: 웹 서버처럼 Grafana를 설치하고 실행합니다.
- Kubernetes (EKS)에 배포: Grafana를 Pod으로 배포하고 Ingress를 통해 외부에 노출합니다.
- 관리형 Grafana 서비스: Amazon Managed Grafana (AMG) 등을 사용하여 Grafana 서버 관리 없이 바로 대시보드를 구축할 수 있습니다.
클라우드 모니터링 서비스 활용
- AWS CloudWatch: EC2 인스턴스, ECS/EKS 컨테이너, RDS 데이터베이스 등 AWS 서비스의 기본 메트릭을 자동으로 수집하고, 대시보드 및 알림 기능을 제공합니다. NestJS 앱 내에서 CloudWatch Logs로 로그를 보내고, CloudWatch Metrics로 커스텀 메트릭을 푸시할 수도 있습니다.
- GCP Cloud Monitoring, Azure Monitor: 각 클라우드 플랫폼의 유사한 관리형 모니터링 서비스입니다.
Health Check 엔드포인트
모니터링 시스템에서 애플리케이션의 생존 여부를 확인하기 위한 Health Check 엔드포인트를 제공하는 것이 중요합니다. NestJS에서 간단하게 구현할 수 있습니다.
import { Controller, Get } from '@nestjs/common';
@Controller('health')
export class HealthController {
@Get()
check() {
// 실제 서비스에서는 데이터베이스 연결, 외부 API 연결 등 핵심 의존성 상태도 함께 체크
return { status: 'ok', timestamp: new Date().toISOString() };
}
}
import { Module } from '@nestjs/common';
import { HealthController } from './health.controller';
@Module({
controllers: [HealthController],
})
export class HealthModule {}
// ...
@Module({
imports: [HealthModule],
// ...
})
export class AppModule {}
이제 /health
엔드포인트로 요청을 보내 애플리케이션의 상태를 확인할 수 있습니다. 로드 밸런서, 컨테이너 오케스트레이터(Kubernetes) 등은 이 헬스 체크 엔드포인트를 사용하여 애플리케이션 인스턴스의 정상 작동 여부를 판단하고, 비정상 인스턴스를 트래픽에서 제외하거나 재시작합니다.
로깅 시스템 구축
로깅은 애플리케이션이 실행되는 동안 발생하는 모든 이벤트(정보, 경고, 오류 등)를 기록하는 과정입니다. 체계적인 로깅은 문제 진단, 보안 감사, 시스템 분석에 필수적입니다.
로깅의 핵심 요소
- 로그 수집: NestJS 애플리케이션에서 발생하는 모든 로그를 수집합니다.
- 로그 통합/집중화: 여러 인스턴스나 서비스에서 발생하는 로그를 중앙의 한 곳으로 모아 관리합니다.
- 로그 저장: 수집된 로그를 효율적으로 저장하고 검색할 수 있도록 합니다. (예: Elasticsearch, S3)
- 로그 분석 및 시각화: 저장된 로그를 분석하고 시각화하여 패턴을 파악하거나 특정 이벤트를 검색합니다. (예: Kibana)
- 알림: 특정 로그 패턴(예: 대량의 에러 로그)이 감지될 때 알림을 보냅니다.
NestJS 로깅 스택
10장 3절 "로깅과 감사 추적"에서 NestJS와 Winston을 이용한 로깅의 기본 개념을 다뤘습니다. 여기서는 실제 클라우드 환경에서의 로그 수집 및 집중화 전략에 집중합니다.
로그 수집 및 전송 전략
컨테이너 표준 출력 (stdout/stderr)
- 가장 권장되는 방식입니다. NestJS 애플리케이션 내에서
console.log
나 Winston과 같은 로거를 사용하여 로그를 표준 출력(stdout) 또는 표준 에러(stderr) 로 보냅니다. - Docker 컨테이너는 기본적으로
stdout/stderr
를 캡처하고 Docker Daemon의 로깅 드라이버를 통해 외부로 전송할 수 있습니다. - 장점: 애플리케이션 코드를 수정할 필요가 거의 없으며, 컨테이너 환경에서 로그 관리가 간편합니다.
- 단점: 로그가 컨테이너 내부에 직접 저장되지 않으므로, 컨테이너가 삭제되면 로그도 사라집니다. (그래서 중앙 집중화가 필요합니다.)
로그 수집 에이전트(Log Collector Agents)
- 각 서버(EC2 인스턴스) 또는 컨테이너(Kubernetes Pod)에 로그 수집 에이전트를 설치하여, 애플리케이션의 로그 파일이나
stdout/stderr
스트림을 읽어 중앙 집중식 로그 관리 시스템으로 전송합니다. - 인프라 레벨 에이전트
- AWS CloudWatch Agent: EC2 인스턴스에서 로그 파일을 CloudWatch Logs로 전송.
- Fluentd / Fluent Bit: 오픈 소스 로그 수집기로, 다양한 소스에서 로그를 수집하여 다양한 목적지로 전송 가능 (Elasticsearch, S3, CloudWatch Logs 등). Kubernetes 환경에서 데몬셋(DaemonSet)으로 배포되어 각 노드의 로그를 수집하는 데 널리 사용됩니다.
- Filebeat: Elastic Stack의 일부로, 로그 파일을 수집하여 Elasticsearch로 전송.
- NestJS 애플리케이션에서 직접 전송: 일부 로깅 라이브러리(예: Winston의 특정 트랜스포트)는 로그를 직접 외부 서비스(예: S3, Elasticsearch)로 전송하는 기능을 제공하기도 합니다. 하지만 이는 애플리케이션에 추가적인 책임을 부여하므로, 별도의 에이전트 사용이 더 일반적입니다.
중앙 집중식 로그 관리 시스템
- ELK Stack (Elasticsearch, Logstash, Kibana)
- Elasticsearch: 분산형 검색 및 분석 엔진으로, 대량의 로그 데이터를 저장하고 빠르게 검색할 수 있습니다.
- Logstash: 다양한 소스에서 로그를 수집하고, 처리(필터링, 파싱)하여 Elasticsearch로 전송합니다.
- Kibana: Elasticsearch에 저장된 데이터를 시각화하고 대시보드를 생성하는 도구입니다.
- 배포: EC2에 직접 설치하거나, Elasticsearch Service (AWS OpenSearch Service)와 같은 관리형 서비스 이용, EKS에 배포하는 방식 등 다양합니다.
- 클라우드 네이티브 로깅 서비스
- AWS CloudWatch Logs: 로그를 중앙 집중식으로 수집, 저장, 모니터링하고 분석합니다. CloudWatch Logs Insights를 통해 SQL과 유사한 쿼리로 로그를 분석할 수 있습니다.
- GCP Cloud Logging: 구글 클라우드 환경의 통합 로깅 서비스.
- Azure Monitor Logs: 애저 환경의 로깅 서비스.
- 상업용 APM/로깅 솔루션
- Datadog, Splunk, New Relic: 통합된 모니터링, 로깅, 트레이싱 기능을 제공하는 강력한 상업용 솔루션입니다. 에이전트를 설치하여 데이터를 수집하고, 웹 기반 대시보드에서 모든 것을 관리할 수 있습니다.
로그 포맷팅
- 로그를 JSON 형식으로 출력하는 것이 좋습니다. JSON 로그는 기계가 파싱하고 분석하기 용이하여 중앙 집중식 로그 시스템에서 검색 및 필터링 성능을 향상시킵니다.
- Winston에서 JSON 포맷을 사용하는 예시
src/config/winston.logger.ts (수정) import { LoggerService } from '@nestjs/common'; import { createLogger, format, transports, Logger as WinstonLoggerType } from 'winston'; import * as DailyRotateFile from 'winston-daily-rotate-file'; export class WinstonLogger implements LoggerService { private readonly logger: WinstonLoggerType; constructor() { // ... (이전 consoleFormat은 그대로 유지) // 파일/콘솔에 JSON 형식으로 저장하는 포맷 (필요에 따라 콘솔에도 적용 가능) const jsonFormat = format.combine( format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), format.json(), // JSON 형식으로 출력 ); this.logger = createLogger({ level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', format: jsonFormat, // 기본 포맷을 JSON으로 설정 transports: [ new transports.Console({ format: process.env.NODE_ENV === 'production' ? jsonFormat : consoleFormat, // 운영 환경 콘솔도 JSON으로 }), new DailyRotateFile({ filename: 'logs/application-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true, maxSize: '20m', maxFiles: '14d', level: 'info', }), // ... 에러, 예외, Promise 예외 파일 트랜스포트 ], // ... exceptionHandlers, rejectionHandlers }); } // ... log, error, warn, debug, verbose 메서드는 동일 }
모니터링과 로깅 시스템 구축은 안정적인 서비스 운영을 위한 양대 축입니다. 메트릭을 통해 시스템의 현재 상태와 추세를 파적하고, 알림을 통해 문제 발생을 즉시 감지하며, 로그를 통해 문제의 원인을 심층적으로 진단할 수 있습니다. NestJS는 이러한 시스템들과 쉽게 통합될 수 있는 유연성을 제공합니다. 클라우드 환경의 다양한 관리형 서비스와 오픈 소스 도구를 조합하여, 여러분의 NestJS 애플리케이션을 위한 강력한 관측성(Observability)을 확보하시길 바랍니다.