Search

[Monitoring]1.3 도커를 활용하여 Node Exporter 모니터링 환경 구축

Publish Date
2024/12/12
Tags
Status
Done
1 more property
Node Exporter 모니터링 환경 구축
서버의 시스템 자원을 실시간으로 모니터링하고, 문제를 사전에 감지하며, 애플리케이션과 서버 수준에서 종합적인 상태 분석을 제공하기 위해 Node Exporter 기반 모니터링 환경을 구축한다.

배경 및 목표

앞서 애플리케이션 레벨 모니터링을 JVM Actuator를 통해 구현했지만 서버의 하드웨어 및 OS 자원을 모니터링하기 위해서는 Node Exporter가 필요하다. 이를 통해 애플리케이션의 CPU, 메모리, 디스크 사용량 등 OS 수준의 메트릭을 수집하여 서버 상태를 실시간으로 분석하고, 리소스 과부하를 방지하고자 한다.
구분
JVM Actuator
Node Exporter
목적
JVM 내부 상태 (Heap 메모리, GC 활동, 스레드 상태 등)
OS 수준의 메트릭 (CPU, 메모리, 디스크 사용량 등)을 수집
주요 기능
- GC 빈도 분석 - 힙 메모리 사용량 추적 - 스레드 상태 확인
- 서버의 하드웨어 및 운영 체제 자원 상태 실시간 확인 - CPU 사용량, 메모리 누수, 디스크 사용량 모니터링
사용 사례
- JVM 성능 문제 디버깅 - 애플리케이션 레벨 성능 최적화
- 서버 자원 과부하 문제 해결 - OS 자원 사용량 분석
대상 범위
JVM 내부 상태 및 애플리케이션 모니터링
서버 하드웨어 및 운영 체제 레벨의 자원 상태 확인
주요 차이점
애플리케이션(JVM) 레벨 모니터링에 특화
시스템(OS) 레벨 모니터링에 특화

Node Exporter 환경 구축

개발환경

항목
설정
Java
17 (image: eclipse-temurin:17-jre)
Spring Boot
3.1.5
Gradle Kotlin
1.9.20
Monitoring
- Prometheus (image: prom/prometheus) - Grafana (image: grafana/grafana)
Prometheus Exporter
- Nginx Exporter (image: nginx/nginx-prometheus-exporter
Dash Board

구조

coupon-project/ ├── docker-compose.yml # Docker 서비스 구성 파일 │ ├── _monitoring/ │ └── prometheus/config/ │ └── prometheus.yml # Prometheus 설정 파일 │ ├── coupon-BE/ │ ├── setup_node_exporter.sh # Node Exporter 설치 및 실행 공통 셸 스크립트 │ ├── Dockerfile-couponAPI # coupon-api Dockerfile │ └── Dockerfile-couponConsumer # coupon-consumer Dockerfile │ └── kakaoshop-BE/ ├── setup_node_exporter.sh # Node Exporter 설치 및 실행 공통 셸 스크립트 └── Dockerfile # kakao-be Dockerfile
Java
복사
파일명
설명
setup_node_exporter.sh
Node Exporter 설치, 실행, 및 환경 설정을 위한 공통 셸 스크립트
docker-compose.yml
전체 Docker 컨테이너를 관리하고 실행하기 위한 구성 파일
prometheus.yml
Prometheus가 모니터링할 대상(Exporter)을 정의한 설정 파일
Dockerfile-couponAPI
coupon-api Spring Boot 애플리케이션 및 Node Exporter 병렬 실행을 위한 Dockerfile
Dockerfile-couponConsumer
coupon-consumer Spring Boot 애플리케이션 및 Node Exporter 병렬 실행을 위한 Dockerfile
Dockerfile (kakaoshop-BE)
kakao-be Spring Boot 애플리케이션 및 Node Exporter 병렬 실행을 위한 Dockerfile

구현

Node Exporter는 다양한 방식으로 설치 및 구성할 수 있다.
방법1. 서버에서 직접 설치
바이너리 파일을 다운로드하거나 OS 패키지 매니저를 사용하여 설치
시스템 자원 모니터링을 위한 간단하고 빠른 설정 가능
방법2. Docker 컨테이너 실행
Node Exporter 별도의 도커 컨테이너로 실행
설치 및 업데이트가 간단하며 컨테이너화 된 환경에서 사용하기 적합
방법3. Dockerfile에 Node Exporter 설정
Node Exporter를 Spring Boot 애플리케이션의 Dockerfile에 포함
하나의 컨테이너에서 애플리케이션과 Node Exporter 동시에 실행
컨테이너 수를 줄이고 관리 복잡성을 낮출수 있음
이번 내용에서는 서버에 직접 Exporter를 설치 방법을 확인 한 후에, 이를 기반으로 Dockerfile에 Node Exporter 설정하는 방법으로 진행한다. 더불어 coupon-api, coupon-consumer, kakao-be 여러 서비스에 동일한 설정이 필요하므로 Shell Script를 작성하여 공통 작업을 자동화할 것이다.

0. 환경 사전 준비

Spring 애플리케이션 서버와 Prometheus 및 Grafana 설치 되어 있어야 한다.

1.(방법1)서버에 직접 Node Exporter 설치하기

Node Exporter의 최신 릴리스 페이지에서 바이너리를 다운로드하고 압축을 해제한다.
curl -L https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz | tar xz
Bash
복사
압축 해제 후, Node Exporter 디렉토리로 이동하여 실행한다.
cd node_exporter-1.6.0.linux-amd64 ./node_exporter
Bash
복사
에러 처리: NFSd 수집기 비활성화
Node Exporter 실행 중 다음과 같은 에러가 발생할 수 있다. 이는 nfsd 수집기가 커널의 NFS 메트릭 포맷을 처리하지 못할 때 발생한다.
ts=2024-12-20T09:32:43.988Z caller=tls_config.go:277 level=info msg="TLS is disabled." http2=false address=[::]:9100 ts=2024-12-20T09:32:47.530Z caller=collector.go:169 level=error msg="collector failed" name=nfsd duration_seconds=0.001696917 err="failed to retrieve nfsd stats: unknown NFSd metric line \"wdeleg_getattr\"" ts=2024-12-20T09:32:52.484Z caller=collector.go:169 level=error msg="collector failed" name=nfsd duration_seconds=0.000121166 err="failed to retrieve nfsd stats: unknown NFSd metric line \"wdeleg_getattr\"" ts=2024-12-20T09:32:57.469Z caller=collector.go:169 level=error msg="collector failed" name=nfsd duration_seconds=0.000246625 err="failed to retrieve nfsd stats: unknown NFSd metric line \"wdeleg_getattr\""
Bash
복사
만약 NFSd 메트릭이 꼭 필요하지 않다면,아래 명령어를 통해 nfsd 수집기를 비활성화 한다.
./node_exporter --no-collector.nfsd
Shell
복사
Node Exporter 실행확인
Node Exporter는 기본적으로 9100 포트에서 메트릭 데이터를 노출한다. 아래 명령어를 사용하여 실행 상태를 확인할 수 있다.
ps aux | grep node_exporter curl http://localhost:9100/metrics
Bash
복사

1.(방법2)Dockerfile에 Node Exporter 설치하기

이 방법은 Spring Boot 애플리케이션 컨테이너에 Node Exporter를 포함하여 설정하는 방법이다.
Dockerfile (coupon-api 예시)
# coupon-api 컨테이너 이미지 FROM --platform=$BUILDPLATFORM gradle:8-jdk17 AS builder WORKDIR /home/gradle COPY .. /home/gradle RUN ./gradlew build -x test FROM eclipse-temurin:17-jre WORKDIR /app RUN apt-get update && apt-get install -y mysql-client redis-tools curl tar && apt-get clean # Node Exporter 설치 RUN curl -L https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz | tar xz \ && mv node_exporter-1.6.0.linux-amd64/node_exporter /usr/local/bin/ \ && chmod +x /usr/local/bin/node_exporter \ && rm -rf node_exporter-1.6.0.linux-amd64 # Spring Boot 애플리케이션 복사 COPY --from=builder /home/gradle/coupon-api/build/libs/coupon-api.jar /app/coupon-api.jar # Node Exporter와 Spring Boot를 병렬로 실행 CMD ["/bin/sh", "-c", "/usr/local/bin/node_exporter --no-collector.nfsd & java -jar -Dspring.profiles.active=docker /app/coupon-api.jar"] EXPOSE 8081 9100
Bash
복사
구분
설명
Node Exporter 설치
Node Exporter 바이너리를 다운로드하고 /usr/local/bin/ 디렉토리에 설치
설치 명령
curl 명령어를 사용하여 Node Exporter 바이너리를 압축 해제 실행 가능한 상태로 설정(chmod +x)
설치 후 정리
설치 완료 후 임시 디렉토리를 제거하여 컨테이너 이미지 크기를 최소화
병렬 실행 설정
CMD 명령을 통해 Node Exporter와 Spring Boot 애플리케이션을 병렬로 실행
Node Exporter 옵션
--no-collector.nfsd 옵션을 사용하여 NFS 관련 메트릭 수집을 비활성화
Spring Boot 실행
java -jar 명령으로 실행하며 docker 프로파일을 활성화
포트 노출
808X: Spring Boot 애플리케이션 9100:Node Exporter 메트릭 노출
coupon-api, coupon-consumer, kakao-be에 각 서비스에 Node Exporter 설치 작업이 반복된다. 반복되는 작업을 줄이기 위해 공통 셸 스크립트를 활용하고, 이를 Dockerfile에 통합하여 적용한다.
setup_node_exporter.sh
#!/bin/bash set -e # 에러 발생 시 스크립트 중단 # 필요한 패키지 업데이트 및 설치 echo "[-] Updating package list and installing required packages..." apt-get update && apt-get install -y \ mysql-client \ redis-tools \ curl \ tar \ && apt-get clean # Node Exporter 다운로드 및 설치 NODE_EXPORTER_VERSION="1.6.0" NODE_EXPORTER_URL="https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" INSTALL_DIR="/usr/local/bin" echo "[-] Downloading Node Exporter version ${NODE_EXPORTER_VERSION}..." curl -L ${NODE_EXPORTER_URL} | tar xvfz echo "[-] Installing Node Exporter to ${INSTALL_DIR}..." mv node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter ${INSTALL_DIR}/ chmod +x ${INSTALL_DIR}/node_exporter rm -rf node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64 # 설치 확인 echo "[-] Verifying Node Exporter installation..." if [ -f "${INSTALL_DIR}/node_exporter" ]; then echo "Node Exporter installed successfully!" else echo "Node Exporter installation failed!" exit 1 fi # Node Exporter 실행 echo "[-] Starting Node Exporter with --no-collector.nfsd option..." ${INSTALL_DIR}/node_exporter --no-collector.nfsd & echo "[-] Node Exporter is now running on port 9100." # 실행 상태 확인 sleep 2 if pgrep -f node_exporter > /dev/null; then echo "Node Exporter is running successfully!" else echo "Failed to start Node Exporter." exit 1 fi # 포트 정보 출력 echo "[-] Exposed ports: 9100 (Node Exporter), others as configured."
Bash
복사

Dockerfile

공통 셸 스크립트를 활용하여 각 서비스에 맞게 Dockerfile을 수정한다.
Dockerfile (coupon-api 예시)
# coupon-api 컨테이너 이미지 FROM --platform=$BUILDPLATFORM gradle:8-jdk17 AS builder WORKDIR /home/gradle COPY .. /home/gradle RUN ./gradlew build -x test FROM eclipse-temurin:17-jre WORKDIR /app COPY setup_node_exporter.sh /usr/local/bin/setup_node_exporter.sh RUN chmod +x /usr/local/bin/setup_node_exporter.sh COPY --from=builder /home/gradle/coupon-api/build/libs/coupon-api.jar /app/coupon-api.jar CMD ["/bin/sh", "-c", "/usr/local/bin/setup_node_exporter.sh && java -jar -Dspring.profiles.active=docker /app/coupon-api.jar"] EXPOSE 8081 9100
Bash
복사
다른 서비스 적용 (coupon-consumer, kakao-be)하여 변경한다.
JAR 파일 경로: 각 서비스에 맞는 경로로 수정.
애플리케이션 포트: 각 서비스가 사용하는 Spring Boot 포트 수정.
예: coupon-consumer(8082), kakao-be (8080)
단, Node Exporter 컨테이너의 포트는 동일하게 9100으로 설정해도 문제가 없다. 도커 네트워크에서 컨테이너 이름으로 서비스에 접근하기 때문이다.

2.(공통) Prometheus 설정

Prometheus가 Node Exporter를 통해 메트릭을 수집하도록 설정한다.
prometheus.yml
scrape_configs: - job_name: 'kakao-be-exporter' static_configs: - targets: [ 'kakao-be:9100' ] - job_name: 'coupon-api-exporter' static_configs: - targets: ['coupon-api:9100'] - job_name: 'coupon-consumer-exporter' static_configs: - targets: [ 'coupon-consumer:9100' ]
YAML
복사
설정 항목
설명
job_name
수집 작업 이름
targets
Exporter 주소 (:9100)
Prometheus 컨테이너를 재시작한다.
docker-compose restart prometheus
Shell
복사
prometheus UI 쿼리 확인:
Prometheus UI (http://<Prometheus-Server-IP>:9090)접근한다.

3.(공통) Grafana 설정

데이터 소스 추가

1.
Grafana 접속: http://<Grafana-Server-IP>:3000
2.
Data sources › Add data source > Prometheus 선택
3.
URL 지정
URL: http://<Prometheus-Server-IP>:9090 (Docker 네트워크 기준)
host.docker.internal:9090
prometheus:9090
host.docker.internal은 Docker 컨테이너에서 호스트 머신에 접근할 수 있도록 제공되는 특별한 DNS 이름이다. host.docker.internal을 사용하면, 컨테이너에서 호스트 머신의 IP 주소를 명시하지 않고도 접근할 수 있다.
로컬 환경에서 Docker 컨테이너와 호스트 간 통신을 위해 host.docker.internal이 필요할 수 있다.
그러나 Prometheus와 Grafana가 동일한 Docker 네트워크에서 실행 중이라면, http://prometheus:9090을 사용하는 것이 권장된다.
4.
Save & Test 클릭

대시보드 설정하기

1.
Dashboards > New > Import 선택
2.
Grafana에서 대시보드 가져오기
Dashboad ID: 1860
3.
데이터 소스 설정하기
위에서 설정한 데이터 소스를 지정한다.
4.
대시보드 확인

결론

주요메트릭

Q&A

Node Exporter와 JVM Actuator의 차이는 무엇인가요?
Node Exporter의 9100 포트는 모든 컨테이너에서 동일하게 설정해도 문제없나요?
NFSd 관련 에러는 어떻게 해결하나요?
셸 스크립트를 사용하는 이유는 무엇인가요?
Search
Main PageCategoryTagskkogggokkAbout MeContact