Spring Actuator를 적용하면 Web Application Server가 실행 되고 나서 현재 상태에 대한 정보를 api 형태로 제공해줍니다. 애플리케이션이 현재 살아있는지, 로그 정보는 정상 설정 되었는지, 커넥션 풀은 얼마나 사용되고 있는지 등을 확인할 수 있습니다.
Gradle을 사용하고 있다면 해당 의존성을 추가해주면 됩니다.
implementation 'org.springframework.boot:spring-boot-starter-actuator' //
/**
* Swagger와 actuator가 충돌하는 부분을 해결하기 위한 설정.
* https://stackoverflow.com/questions/70695150/how-to-befriend-spring-boot-2-6-x-with-actuator-dependency-and-swagger-starter-3
*/
@Configuration
public class SpringfoxHandlerProviderBeanPostProcessorConfig {
@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider
|| bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(
List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
}
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
}
}
}
management:
endpoints:
web:
exposure:
include: "*"
엔드포인트 목록 예시
자세한 내용은 공식문서를 참조하면 좋습니다.
특별한 설정을 하지 않는 다면 Actuator는 8080포트에서 활성화 됩니다. 문제는 사용자 요청 포트와 동일하기 때문에 아무나 어플리케이션 정보를 볼 수 있게 될 수 있습니다. 이를 방지하는 방법이 두 가지 정도 있습니다.
처음에 두번째 방법을 적용하려고 했지만 Prometheus 활용시 JWT토큰을 재발급 해주어야 하는등 까다로운 부분이 있어 그냥 1의 방법과 AWS의 Security Group등을 활용해 외부에서 접근 불가능하도록 설정하였습니다. 아래와 같이 yml파일에 작성하면 10090포트에서 actuator정보에 접근할 수 있습니다.
management:
server:
port: 10090
위에서 Actuator에 대해서 알아보았습니다. Actuator에서 수집한 정보를 Prometheus에 보내어 수집하도록 할것입니다. 그런데 여기서 문제가 발생하는데 Actuator가 주는 metrics형식이 Prometheus에서 원하는 형식과 다르다는 점입니다. Micrometer는 중간자 역할을 하여 Actuator의 정보를 추출하려는 대상에 따라 Actuator의 metrics를 Prometheus에서 원하는 방식으로 변경 해줍니다. Micrometer 구현체를 원하는 모니터링 수집 툴에 따라 라이브러리에 추가해주면 AutoConfiguration을 통해 필요한 Bean객체들을 등록해줍니다.(마치 DB종류에 따라 라이브러리 설정만 변경해주면 구현체가 달라져서 개발자는 일관된 방식으로 코드를 작성할 수 있는것과 유사합니다.).
implementation 'io.micrometer:micrometer-registry-prometheus' //추가
Prometheus는 모니터링 metrics들을 수집할 수 있는 저장소라고 생각하면 됩니다.
Alertmanager등을 설정하여 자동적으로 알림이 가도록 할 수 있으며 지표들을 주기적으로 scrape하여 수집할 수 있습니다. PromQL이라는 쿼리 언어를 통해 DB처럼 조회하는 것도 가능합니다.
Spring Actuator는 Application 서버와 관련된 지표들을 제공할 수 있지만 시스템 자체와 관련된 지표는 제공할 수 없습니다. 만약 시스템 지표와 관련된 데이터를 수집하고 싶다면 node_exporter를 해당 시스템에 설치하고 이를 prometheus가 scrape하도록 설정해야합니다.
다음 링크에 가서 운영체제에 맞게 설치하면 됩니다.
https://prometheus.io/download/
설치 디렉토리내에 prometheus라는 실행파일을 실행하면 됩니다. 이때 기본적으로 같은 경로에 있는 prometheus.yml이라는 설정파일을 활용합니다. 이 설정파일을 수정하는 것이 prometheus를 주로 할 일입니다.
./prometheus
VPC내에 Private Subnet(public subnet에 하게 되면 보안사항에 문제가 생길 수 있습니다)에 Prometheus를 위한 EC2를 생성하고 prometheus를 설치합니다. wget {download 링크}, tar xf {압축 파일}
해당 EC2 Security Group Inbound는 만약 prometheus 서버를 직접 접속하고 싶다면 load balancer를 따로 구축하고 load balancer에 대해서 허용해줍니다. 또한, 추후 Grafana EC2를 마찬가지로 구축할텐데 해당 EC2에 대한 Security Group도 inbound에 가해줍니다. prometheus서버가 동작하는 기본 포는 9090이기 때문에 이 포트를 허용해줍니다.
WAS EC2들의 경우 저는 actuator노출 포트를 10090으로 설정했으므로 inbound 10090 포트에 prometheus EC2 Security Group(Prometheus EC2가 변하는 상황을 위해 Security Group을 등록해야합니다)을 추가해줍니다.
본격적으로 prometheus.yml 파일을 수정하여 설정해줍니다.설정 내용은 다음과 같습니다.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
ec2_sd_configs:
- region: ap-northeast-2
port: 80
access_key: ""
secret_key: ""
filters:
- name: tag:PrometheusScrape
values:
- Enabled
relabel_configs:
- source_labels: [__meta_ec2_tag_Name]
target_label: instance
- source_labels: [__meta_ec2_private_ip]
regex: '(.*)'
replacement: '${1}:10091'
action: replace
target_label: __address__
- source_labels: [__meta_ec2_tag_group]
target_label: group
- source_labels: [__meta_ec2_instance_type]
target_label: instance_type
static_configs:
- targets: []
./prometheus로 실행 후 설정이 잘 적용되었는지 확인하려면 grafana의 ec2 9090포트 /targets 경로로 요청하면 됩니다. prometheus를 외부에서 접속하게 설정한 상태라 접속 해보면 잘 적용되었음을 확인할 수 있습니다.
Prometheus도 수집한 metrics들을 query를 통해 확인할 수는 있지만 아무래도 시각화면에서 기능이 부족합니다. Grafana는 prometheus와 같이 메트릭이 수집된 서버에 요청하여 정보를 가져와 시각화 해줍니다.