[토이프로젝트] Scouter와 PagerDuty로 장애 감지부터 On-call까지: (2) Spring Boot 애플리케이션에 Scouter Agent 연동
Scouter Server를 구성했다고 해서 애플리케이션의 운영 정보가 자동으로 수집되지는 않습니다. 모니터링 대상 애플리케이션에 Scouter Agent가 연동되어야 운영 정보가 수집될 수 있습니다.
1. Scouter Agent 준비
Scouter Agent를 연동하려면 scouter.agent.jar 파일이 필요합니다. 이전 포스팅에서 Scouter 2.20.0 배포 파일인 scouter-all-2.20.0.tar.gz를 다운로드 했습니다.
이 파일의 압축을 해제하면 scouter/agent.java 디렉터리에서 scouter.agent.jar 파일을 찾을 수 있습니다.
참고
1.1. Scouter Agent 파일 배치
Scouter Agent는 JVM이 시작될 때 -javaagent 옵션을 통해 모니터링 대상 애플리케이션과 함께 로드됩니다. 따라서 Docker 이미지를 생성할 때 Agent 파일도 함께 포함될 수 있도록 애플리케이션 프로젝트에 agent 디렉터리를 추가했습니다.
참고
그리고 agent 디렉터리에 scouter.agent.jar 파일을 복사했습니다.
1.2. scouter.conf 작성
Scouter Agent가 운영 정보를 Scouter Server로 전송하는 데 필요한 설정은 scouter.conf 파일에서 정의하게 됩니다.
agent 디렉터리에 scouter.conf 파일을 아래와 같이 작성했습니다.
net_collector_ip=192.168.56.13
net_collector_udp_port=6100
net_collector_tcp_port=6100
obj_host=app-server
obj_type=tomcat
각 설정의 의미는 다음과 같습니다.
| 설정 | 설명 |
|---|---|
net_collector_ip |
Scouter Server 주소 |
net_collector_udp_port |
Collector UDP 포트 |
net_collector_tcp_port |
Collector TCP 포트 |
obj_host |
Scouter에서 애플리케이션이 속한 호스트를 구분하기 위한 이름 |
obj_type |
애플리케이션 종류 |
두 컨테이너는 동일한 애플리케이션의 인스턴스이므로 obj_host는 app-server로 동일하게 설정했습니다. 대신 각 컨테이너의 obj_name을 api-01, api-02로 다르게 지정해 개별 인스턴스를 구분하도록 구성했습니다.
또한 Spring Boot 애플리케이션은 내장 Tomcat을 사용하므로 obj_type을 tomcat으로 설정했습니다.
2. 애플리케이션 Docker 이미지 준비
애플리케이션과 함께 Scouter Agent를 실행하려면 scouter.agent.jar와 scouter.conf 파일도 Docker 이미지에 포함되어야 합니다. 이를 위해 simple-api 프로젝트에서 사용하던 Dockerfile을 수정하고, 이미지를 새로 빌드했습니다.
2.1. 애플리케이션 프로젝트 구조
simple-api
├── Dockerfile
├── agent
│ ├── scouter.agent.jar
│ └── scouter.conf
├── build.gradle
└── src
2.2. Dockerfile 수정
GitHub 저장소에 등록되어 있는 simple-api의 Dockerfile은 아래와 같이 작성되어 있습니다.
변경 전 Dockerfile
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY build/libs/simple-api-0.0.1-SNAPSHOT.jar simple-api.jar
ENTRYPOINT ["java", "-jar", "simple-api.jar"]
그래서 scouter.agent.jar와 scouter.conf 파일이 이미지에 포함되도록 Dockerfile을 아래와 같이 수정했습니다.
변경 후 Dockerfile
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY build/libs/simple-api-0.0.1-SNAPSHOT.jar simple-api.jar
COPY agent/scouter.agent.jar agent/scouter.agent.jar
COPY agent/scouter.conf agent/scouter.conf
ENTRYPOINT ["java", "-jar", "simple-api.jar"]
Dockerfile의 ENTRYPOINT에는 -javaagent 옵션을 직접 추가하지 않았습니다. 동일한 이미지를 사용하는 각 컨테이너에 서로 다른 obj_name을 설정하기 위해 Agent 실행 옵션은 docker-compose.yml의 JAVA_TOOL_OPTIONS를 통해 전달하도록 구성했습니다.
2.3. Docker 이미지 빌드
이어서 수정된 Dockerfile 파일을 이용해서 simple-api-scouter라는 이름의 새로운 Docker 이미지를 빌드했습니다.
docker build -t simple-api-scouter .
참고
Docker는 이전 빌드 결과를 캐시로 재사용할 수 있습니다. 변경한 파일이 이미지에 반영되지 않은 것으로 보이는 경우
docker build --no-cache -t simple-api-scouter .명령으로 캐시를 사용하지 않고 다시 빌드할 수 있습니다.
3. 애플리케이션 실행
docker run 명령으로 애플리케이션의 컨테이너를 실행해도 되지만, 실행 옵션을 한 곳에서 관리하기 위해 Docker Compose를 사용했습니다.
동일한 이미지로 두 개의 컨테이너를 실행하지만, Scouter에서는 각각을 별도의 모니터링 대상으로 식별해야 합니다. 따라서 컨테이너별로 서로 다른 obj_name을 설정하고, JVM 시작 시 -javaagent 옵션을 전달하도록 구성했습니다.
3.1. Docker Compose 구성
Docker Compose를 사용해서 애플리케이션을 실행하기 위해 docker-compose.yml 파일을 아래와 같이 작성했습니다.
services:
simple-api-1:
image: simple-api-scouter
container_name: api-01
ports:
- "8081:8000"
environment:
SERVER_NAME: api-01
JAVA_TOOL_OPTIONS: >-
-javaagent:/app/agent/scouter.agent.jar
-Dscouter.config=/app/agent/scouter.conf
-Dobj_name=api-01
simple-api-2:
image: simple-api-scouter
container_name: api-02
ports:
- "8082:8000"
environment:
SERVER_NAME: api-02
JAVA_TOOL_OPTIONS: >-
-javaagent:/app/agent/scouter.agent.jar
-Dscouter.config=/app/agent/scouter.conf
-Dobj_name=api-02
docker-compose.yml 파일에서 정의한 두 컨테이너는 동일한 simple-api-scouter 이미지를 사용합니다. 하지만 일부 속성은 다른 값으로 설정해야 합니다.
| 구분 | simple-api-1 서비스 |
simple-api-2 서비스 |
|---|---|---|
| 컨테이너 이름 | api-01 |
api-02 |
| 포트 매핑 | 8081 → 8000 |
8082 → 8000 |
Scouter obj_name |
api-01 |
api-02 |
JAVA_TOOL_OPTIONS는 JVM이 시작될 때 자동으로 읽는 환경변수입니다. 이를 이용해 Dockerfile의 ENTRYPOINT를 변경하지 않고도 -javaagent와 Scouter 관련 시스템 프로퍼티를 JVM에 전달할 수 있습니다.
-javaagent는 Scouter Agent를 JVM에 로드하고, -Dscouter.config는 Agent 설정 파일의 위치를 지정합니다. -Dobj_name은 두 애플리케이션 인스턴스를 Scouter에서 구분하기 위해 각각 다른 값으로 설정했습니다.
3.2. 컨테이너 실행
만약 Nginx로 Reverse Proxy 구성하기 시리즈에서 사용했던 api-01과 api-02 컨테이너가 남아 있다면 먼저 삭제해야 합니다. Docker에서는 같은 이름의 컨테이너를 중복해서 생성할 수 없으므로 기존 컨테이너가 남아 있으면 Docker Compose 실행 과정에서 이름 충돌이 발생하기 때문입니다.
기존 컨테이너가 남아 있었기 때문에, 다음 명령으로 삭제했습니다.
$ docker rm -f api-01 api-02
이후 새로 빌드한 simple-api-scouter 이미지를 사용해 컨테이너를 실행했습니다.
$ docker compose up -d
3.3. Scouter Agent 로드 확인
애플리케이션 시작 로그를 통해 api-01과 api-02 두 개의 컨테이너에 Scouter Agent가 모두 정상적으로 로드된 것을 확인할 수 있었습니다.
$ docker logs api-01
Picked up JAVA_TOOL_OPTIONS: -javaagent:/app/agent/scouter.agent.jar -Dscouter.config=/app/agent/scouter.conf -Dobj_name=api-01
____ _
/ ___| ___ ___ _ _| |_ ___ _ __
\___ \ / __/ \| | | | __/ _ \ '__|
___) | (_| (+) | |_| | || __/ |
|____/ \___\___/ \__,_|\__\___|_|
Open Source S/W Performance Monitoring
Scouter version 2.20.0
20260822 06:25:08 [SCOUTER] Version 2.20.0 2023-05-29 05:14 GMT_ENV_java8plus
20260822 06:25:08 [SCOUTER] loaded by system classloader
20260822 06:25:08 [SCOUTER] jar:file:/app/agent/scouter.agent.jar
20260822 06:25:09 [SCOUTER] objType:tomcat
20260822 06:25:09 [SCOUTER] objName:/78afd06c5c17/api-01
20260822 06:25:09 [A113] Counter Collector Started (#19)
20260822 06:25:09 [A113] InteractionCounter Collector Started (#19)
20260822 06:25:09 [SCOUTER] Configure -Dscouter.config=/app/agent/scouter.conf
20260822 06:25:09 [A100] agent boot seed=x1k4k2a0r1
20260822 06:25:10 [A119] Agent UDP local.port=0
설정한 JAVA_TOOL_OPTIONS가 JVM에 그대로 전달되었고, scouter.agent.jar가 시스템 클래스 로더를 통해 로드되었습니다. objType이 tomcat으로 설정되고 objName 끝에 api-01이 표시되는 것을 통해 Scouter Agent 설정도 정상적으로 적용되었음을 확인할 수 있었습니다.
참고
로그의
Agent UDP local.port=0은 Collector의 UDP 포트가 아니라 Agent가 사용하는 로컬 UDP 포트를 의미합니다.scouter.conf파일의net_collector_udp_port=6100은 Scouter Agent가 데이터를 전송할 대상인Scouter Server의 UDP 포트이므로 서로 다른 값입니다.또한 Docker 환경에서는 Scouter Agent 로그의
objName에 컨테이너의hostname과-Dobj_name으로 설정한 값이 함께 표시될 수 있습니다. 위 로그에서도objName이/78afd06c5c17/api-01로 출력되었습니다.78afd06c5c17은 Docker 컨테이너에 부여된hostname이며,api-01은 JVM 시스템 프로퍼티인-Dobj_name으로 지정한 값입니다.
4. 다음 포스팅
이번 포스팅에서는 Spring Boot 애플리케이션에 Scouter Agent를 연동하고, 애플리케이션 실행 시 Agent가 정상적으로 로드되는 것까지 확인했습니다.
다음 포스팅에서는 Windows용 Scouter Client를 설치하고 Scouter Server에 접속하여, 두 애플리케이션 컨테이너의 운영 정보가 정상적으로 수집되고 있는지 확인해보겠습니다.