[AWS] Application Monitoring 실습 세팅

Hyunjun Kim·2025년 7월 9일

실습 - (AWS 환경)

목록 보기
38/61

1.1 Prometheus Simple Client

Prometheus 에서는 각 언어별로 client library 를 제공한다. 링크

Prometheus format 으로 노출할 수 있는 설정, 각 언어별로 기본 모니터링 시스템(java의 경우 JMX)을 이용해 메트릭 정보 추출, custom metric을 남기는 기능 등을 할 수 있다.

1.2 실습 Application

Spring Boot가 API서버를 빠르게 만들 수 있어서
Spring Boot Application 으로 간단한 application 을 만들고,
Prometheus simple client java 로 Prometheus 형식의 메트릭을 노출한다.

1.2.1 실습 아키텍처

지금까지는 Prometheus 서버 내에서 기본 구성을 실습했다. Prometheus 서버를 띄우고, 해당 서버 자체에 node_exporter를 설치하여 자신의 시스템 메트릭을 수집하도록 구성했다. 또한 pushgateway를 설치하여 외부에서 메트릭을 푸시받을 수 있는 환경을 만들었고, Grafana를 설치해 Prometheus에 저장된 메트릭을 시각화할 수 있도록 연동하였다.

이제는 애플리케이션용 서버(App Server)를 별도로 하나 더 준비한다. 이 App Server 역시 독립적인 서버이므로 해당 서버의 시스템 상태를 모니터링하기 위해 node_exporter를 설치한다. Prometheus는 이 App Server의 node_exporter에서 메트릭을 수집할 수 있도록 동일한 잡 이름(job: node)으로 설정한다.

이후 App Server에 Spring Boot 애플리케이션을 배포한다. 이 애플리케이션은 Prometheus simple client for Java 라이브러리를 이용하여 메트릭 데이터를 노출한다. 애플리케이션은 예를 들어 1234번 포트에 Prometheus 형식의 메트릭을 HTTP endpoint로 제공하도록 구성된다. Prometheus는 이 endpoint에 접근하여 job: spring 이름으로 메트릭을 스크랩하도록 설정한다.

이와 같이 구성하면, Prometheus는 시스템 메트릭(node_exporter)과 애플리케이션 메트릭(Prometheus client를 통해 노출된 메트릭)을 각각 job: node와 job: spring으로 구분하여 수집할 수 있으며, Grafana를 통해 이 데이터를 시각화할 수 있다.

1.2.2 build.gradle

plugins {
id 'java'
id 'org.springframework.boot' version '2.7.6'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'io.prometheus:simpleclient:0.16.0'
implementation 'io.prometheus:simpleclient_hotspot:0.16.0'
implementation 'io.prometheus:simpleclient_httpserver:0.16.0'
implementation 'io.prometheus:simpleclient_pushgateway:0.16.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

bootJar {
mainClass = 'de.monitoring.prometheus.PrometheusMonitoringAppApplication'
}

tasks.named('test') {
useJUnitPlatform()
}

실습에서 사용하는 org.springframework.boot 버전은 2.7.6 버전인데 3 버전을 쓰고 싶다면 java8을 쓰면 안되고 버전을 높여줘야 한다.


simpleclient : Prometheus 메트릭을 Java 애플리케이션 내에서 직접 생성하고 관리할 수 있는 핵심 클라이언트 라이브러리이다. Counter, Gauge, Histogram, Summary 등의 기본 메트릭 타입을 정의하고 사용할 수 있다.

simpleclient_hotspot : JVM 내부 메트릭(예: 메모리 사용량, GC 횟수, 클래스 로딩 수 등)을 수집하는 Collector가 포함되어 있다. 이름의 hotspot은 JVM 구현체 중 하나인 HotSpot VM에서 유래하며, 현재 대부분의 OpenJDK 배포판이 HotSpot 기반이므로 일반적으로 사용된다.

simpleclient_httpserver : Prometheus가 스크랩할 수 있도록 메트릭을 HTTP endpoint로 노출하는 경량 내장 HTTP 서버를 제공한다. 애플리케이션에 별도의 웹 프레임워크(Spring 등)가 없거나 빠르게 테스트용 서버를 만들 때 유용하다. 기본 포트는 1234, 기본 경로는 /metrics이다.

simpleclient_pushgateway : PushGateway로 메트릭을 푸시할 수 있게 해주는 라이브러리이다. 짧은 생명주기를 가지는 Job(Batch Job 등)에서 메트릭을 푸시할 때 사용한다. 현재 실습에서는 사용하지 않지만, 필요 시 해당 라이브러리를 통해 Push 방식으로 메트릭 전송이 가능하다.


패키지는 de.monitoring.prometheus로 구성하였고, 메인 클래스는 PrometheusMonitoringAppApplication이다. 이 메인 클래스를 Gradle의 bootJar 플러그인에서 사용하는 mainClass 속성에 미리 지정해두면, 빌드 시 해당 클래스를 기준으로 실행 가능한 JAR 파일을 생성한다. 이를 통해 애플리케이션 실행 시 명확한 진입점을 설정할 수 있다.


![](https://velog.velcdn.com/images/leo4study/post/d2635d2a-690e-400f-b4ca-2b3d81598fbe/image.png)

1.2.3 project 구조

package: de.monitoring.prometheus

classes

  • PrometheusMonitoringAppApplication: main class
  • ApiController: API contoller
  • Greeting: data object

1.2.4 classes

PrometheusMonitoringAppApplication.java

package de.monitoring.prometheus;

import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import io.prometheus.client.exporter.HTTPServer;
import io.prometheus.client.hotspot.DefaultExports;

@SpringBootApplication
public class PrometheusMonitoringAppApplication {
    public static void main(String[] args) throws IOException {
        DefaultExports.initialize();
        HTTPServer server = new HTTPServer.Builder().withPort(1234).build();
        SpringApplication.run(PrometheusMonitoringAppApplication.class, args);
    }
}

Greeting.java

package de.monitoring.prometheus;

public class Greeting {
    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

ApiController.java

package de.monitoring.prometheus;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


@RestController
public class ApiController {
    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }

    @GetMapping("/cpurun")
    public ResponseEntity<String> runCpu(
            @RequestParam(value = "divider", defaultValue = "65536") long divider) {
        long counter = 0;
        do {
            counter++;
        } while (counter <= (Long.MAX_VALUE / divider));
        return ResponseEntity.ok("finished");
    }

    @GetMapping("/users/{userId}")
    public ResponseEntity<String> getUser(@PathVariable String userId) {
        return ResponseEntity.ok("user_id: " + userId);
    }

    @GetMapping("/website")
    public ResponseEntity<String> getSite(
            @RequestParam(value = "site", defaultValue = "http://www.example.com") String site) {
        RestTemplate restTemplate = new RestTemplate();
        System.out.println("site: " + site);
        String response = restTemplate.getForObject(site, String.class);
        return ResponseEntity.ok(response);
    }
}

코드가 잘 작동해 프로메테우스로 수집이 잘 되는지 확인해보자.

localhost:1234

metric 잘 나오는 모습.

jvmmemory
jvmthreads

jvmgc_collection_seconds*
*_fds

등 여러가지 보임

API 호출하고시으면 기본 포트/API 해야됨.

localhost:8080/greeting

이렇게 쿼리스트링으로 들어가면 기본적인 body가 와서 보여진다.

localhost:8080/website?http://google.com

1.2.5 Application Server 에 Java 설치

어플리케이션 서버로 이동하자.

EC2에 java 가 설치 되어있지 않은경우

sudo apt install openjdk-8-jre-headless

1.2.6 Build후 Jar 파일 생성

intellij 로 돌아가서 바이너리를 생성하자

version = '0.0.1-SNAPSHOT' 으로 한 다음에
bootJar 왼쪽 초록화살표로 Run 실행시켜도 되고

터미널로 이동해서

./gradlew bootJar

입력해도 된다.

아까 bootJar Run을 시키면

build > libs 에 들어가보면 생성된 Jar가 보일 것.


확인해보고 싶으면

터미널에서

java -jar ~~.jar

로 실행할 수 있다.

사이트에 접속이 잘 되는 모습.

터미널에서 ctrl + c 로 종료시켜주자.

1.2.7 Application Server 에 Jar 전송

java 어플리케이션의 build 결과물인 jar를 scp 로 EC2에 전송하자.

  1. key 파일이 있는 디렉토리로 이동해서
pwd | pbcopy

다음 intelliJ 터미널로 이동해서 Jar 파일을 복사하고

이렇게 잘 들어왔으면 이 파일을 scp로 전송을 해보자.

그 전에 앱서버에서 폴더 생성하고

mkdir monitoring_app

scp로 보내주자.

scp -i $your_key $your_jar $ec2_user@$ec2_public_address:$path_to_locate

  • $your_key : ec2 접속 credential( .pem 파일)
  • $your_jar : local의 jar 파일 위치와 이름
  • $ec2_user : EC2에 접속할 username
  • $ec2_public_address : EC2의 public IP 또는 dns
  • $path_to_locate : 위치시킬 경로

경로/. 를 해줘야 들어간다.

1.2.8 EC2에서 Application 실행

java -jar prometheus_monitoring_app-0.0.1-SNAPSHOT.jar

로 실행시켜 보자

EC2 ip주소:8080/api주소 입력해보자

http://3.39.194.51:8080/greeting

똑같이 잘 나오는 모습

nohup java -jar $your_jar > server.log 2>&1 & echo $! > run.pid
  • 다음 URL로 API 요청을 확인해본다.
    • $IP:8080/greeting
    • $IP:1234/metrics

1.2.9 Application Server 에 node exporter 설정

[Node Monitoring] 에서 배운 방법대로 새로운 서버에도 Node exporter 를 설치하고 실행한다.

1.3 Prometheus 에서 Application Metric 수집

프로메테우스 서버로 돌아와서 수정하자.

1.3.1 prometheus.yml 수정

job: node 에 새로운 application server 의 node_exporter endpoint 추가

- job_name: node
	static_configs:
		- targets: ["localhost:9100", "$your_ip:9100"]
  • $your_ip 를 변경한다.

job: spring 의 새로운 job을 만든다. 여기서 사용하는 endpoint 는 app server 에서 노출한 별도의 prometheus endpoint이다.

- job_name: "spring"
	static_configs:
		- targets: ["$your_ip:1234"]
  • $your_ip 를 변경한다.

1

2

3
프로메테우스 사이트 들어와서 JVM 관련 매트릭들 확인해보자.

job="spring"이고 1234 port가진 인스턴스로 잘 수집이 되고 있는 걸 알 수 있다.

4
일단 앱서버 실행시켰던 거 정지 시켜주고

5 계속 수집을 해야 되니까 계속 띄워놓을 수 있는 스크립트

nohup java -jar $your_jar > server.log 2>&1 & echo $! > run.pid

tail -f server.log 로 확인할 수 있따.

여기에 이제 나온 노드들의 정보도 알아야 한다.
그래서 앞에서 배운 노드 모니터링에서 배운 것처럼 Application server 노드에도
노드익스포터 설치하고 실행한다.

잘 된 모습!

이제 프로메테우스 서버로 돌아가서
prometheus.yml에서 노드에 대상을 추가해주자.

수정이 되었다면

프로메테우스를 정지했다가 다시 시작해주고

프로메테우스 9090 포트 들어가서
node 관련 정보를 조회했을 때,

localhost만 나오는 게 아니라 Appserver의 노드도 스크랩되어 나왔다면 잘 설정이 된 것이다.

profile
Data Analytics Engineer 가 되

0개의 댓글