AWS Auto Scaling Group EC2 WAS 대상Actuator Prometheus Grafana Micrometer 모니터링 적용

taehee kim·2023년 4월 20일
5
post-custom-banner

0.모니터링 적용 배경

  • AWS로 Spring Boot Web Application Server를 배포하고 이를 운영하던 중 해당 WAS가 원인 모르게 종료되거나 하는 일이 종종 발생했습니다. Auto Scaling Group을 적용 했었기에 자동적으로 복구 되었지만 어떤 원인으로 해당 문제가 발생했는지 파악하지 못하고 있었습니다. 이런 부분에 대해서 무지한 것을 애써 회피하고 있다가 마음을 먹고 제대로 적용해보기로 결정했습니다.
  • 개발 코드를 작성하면 해당 코드가 제대로 작성하는지 테스트 코드를 작성하는 것이 그 코드 자체의 완성이 듯 배포된 서버 관점에서도 배포를 하면 이를 관리하고 모니터링하는 것 또한 필수라고 할 수 있습니다.
  • 또한 배포 시 여러 시스템 옵션들(DB Connection, Thread Pool, JVM 메모리등)을 현재 배포 환경과 시스템에 맞도록 튜닝하기 위해서 모니터링을 적용해보려고 합니다.
  • 이 이후의 내용에서는 모니터링을 어떻게 적용 했는지와 사용된 기술의 개념에 대해서 소개하려고 합니다. 이를 요약하면 다음과 같습니다.
  1. 스프링 부트 액츄에이터와 마이크로미터를 사용하면 수 많은 메트릭을 자동으로 생성한다.
    마이크로미터 프로메테우스 구현체는 프로메테우스가 읽을 수 있는 포멧으로 메트릭을 생성한다.
  2. 프로메테우스는 이렇게 만들어진 메트릭을 지속해서 수집한다.
  3. 프로메테우스는 수집한 메트릭을 내부 DB에 저장한다.
  4. 사용자는 그라파나 대시보드 툴을 통해 그래프로 편리하게 메트릭을 조회한다. 이때 필요한 데이터는
    프로메테우스를 통해서 조회한다.

1. Spring Actuator

Spring Actuator란?

Spring Actuator를 적용하면 Web Application Server가 실행 되고 나서 현재 상태에 대한 정보를 api 형태로 제공해줍니다. 애플리케이션이 현재 살아있는지, 로그 정보는 정상 설정 되었는지, 커넥션 풀은 얼마나 사용되고 있는지 등을 확인할 수 있습니다.

Spring Actuator 적용방법

Gradle을 사용하고 있다면 해당 의존성을 추가해주면 됩니다.

implementation 'org.springframework.boot:spring-boot-starter-actuator' //
  • Swagger와 Actuator를 같이 사용할 경우 충돌이 발생할 수 있습니다. 이 경우 다음 Bean을 추가해주면 됩니다.
    /**
     * 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);
                    }
                }
            };
        }
    }

동작확인

  • /actuator 경로로 요청하면 여러 지표들을 조회할 수 있는 경로들이 나오게 됩니다. 해당 경로들로 요청하면 metric들을 받을 수 있습니다.
{
"_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
    }  
  }
}

Actuator Endpoint Exposure

  • 해당 api가 모두 노출 되기 원한다면 해당 설정을 통해 할 수 있습니다. 노출을 특정하거나 세부적으로 설정할 수도 있습니다. 저는 모두 노출하는 것으로 설정했습니다.
management:
    endpoints:
      web:
        exposure:
          include: "*"

EndPoint 활성화

  • Endpoint들은 활성화 + 노출을 모두 해주어야 사용가능합니다. 기본적으로 비활성화 되어있는 기능들은 설정을 통해 활성화 합니다.(대부분은 활성화 되어있지만 shutdown등은 비활성화 되어있습니다.)

다양한 Endpoint들

엔드포인트 목록 예시

  • health : 애플리케이션 헬스 정보를 보여준다.
  • info : 애플리케이션 정보를 보여준다.
  • loggers : 애플리케이션 로거 설정을 보여주고 변경도 할 수 있다.
  • metrics : 애플리케이션의 메트릭 정보를 보여준다.
  • mappings : @RequestMapping 정보를 보여준다.
  • threaddump : 쓰레드 덤프를 실행해서 보여준다.
  • shutdown : 애플리케이션을 종료한다. 이 기능은 기본으로 비활성화 되어 있다.

자세한 내용은 공식문서를 참조하면 좋습니다.

actuator 공식 문서

Actuator 보안 문제

특별한 설정을 하지 않는 다면 Actuator는 8080포트에서 활성화 됩니다. 문제는 사용자 요청 포트와 동일하기 때문에 아무나 어플리케이션 정보를 볼 수 있게 될 수 있습니다. 이를 방지하는 방법이 두 가지 정도 있습니다.

  1. 임의의 다른 port에서 Actuator를 활성화 시키고 사용자가 접근하지 못하도록 차단
  2. 1이 불가능 할경우 /actuator/* 하위 경로에 Spring Security등을 활용해서 인증을 해야하면 접근 가능하도록 변경

처음에 두번째 방법을 적용하려고 했지만 Prometheus 활용시 JWT토큰을 재발급 해주어야 하는등 까다로운 부분이 있어 그냥 1의 방법과 AWS의 Security Group등을 활용해 외부에서 접근 불가능하도록 설정하였습니다. 아래와 같이 yml파일에 작성하면 10090포트에서 actuator정보에 접근할 수 있습니다.

management:
  server:
    port: 10090

metrics 수집과 시각화

  • Actuator는 지표를 저장하는 기능을 따로 제공하지 않고 시각화기능을 제공하지 않습니다.
  • 따라서 Prometheus에 Actuator에서 추출한 metrics들을 저장하고 이를 Grafana를 통해서 시각화 해서 보도록 설정할 것입니다.

2. Micrometer

Micrometer의 필요성

위에서 Actuator에 대해서 알아보았습니다. Actuator에서 수집한 정보를 Prometheus에 보내어 수집하도록 할것입니다. 그런데 여기서 문제가 발생하는데 Actuator가 주는 metrics형식이 Prometheus에서 원하는 형식과 다르다는 점입니다. Micrometer는 중간자 역할을 하여 Actuator의 정보를 추출하려는 대상에 따라 Actuator의 metrics를 Prometheus에서 원하는 방식으로 변경 해줍니다. Micrometer 구현체를 원하는 모니터링 수집 툴에 따라 라이브러리에 추가해주면 AutoConfiguration을 통해 필요한 Bean객체들을 등록해줍니다.(마치 DB종류에 따라 라이브러리 설정만 변경해주면 구현체가 달라져서 개발자는 일관된 방식으로 코드를 작성할 수 있는것과 유사합니다.).

Micrometer Prometheus 구현체 추가

implementation 'io.micrometer:micrometer-registry-prometheus' //추가

3. Prometheus

Prometheus란?

Prometheus는 모니터링 metrics들을 수집할 수 있는 저장소라고 생각하면 됩니다.

Alertmanager등을 설정하여 자동적으로 알림이 가도록 할 수 있으며 지표들을 주기적으로 scrape하여 수집할 수 있습니다. PromQL이라는 쿼리 언어를 통해 DB처럼 조회하는 것도 가능합니다.

node_exporter

Spring Actuator는 Application 서버와 관련된 지표들을 제공할 수 있지만 시스템 자체와 관련된 지표는 제공할 수 없습니다. 만약 시스템 지표와 관련된 데이터를 수집하고 싶다면 node_exporter를 해당 시스템에 설치하고 이를 prometheus가 scrape하도록 설정해야합니다.

설치

다음 링크에 가서 운영체제에 맞게 설치하면 됩니다.

https://prometheus.io/download/

실행

설치 디렉토리내에 prometheus라는 실행파일을 실행하면 됩니다. 이때 기본적으로 같은 경로에 있는 prometheus.yml이라는 설정파일을 활용합니다. 이 설정파일을 수정하는 것이 prometheus를 주로 할 일입니다.

./prometheus

AWS AutoScaling Group에 속한 EC2내의 Spring boot 서버에서 actuator metrics수집하도록 설정

  1. VPC내에 Private Subnet(public subnet에 하게 되면 보안사항에 문제가 생길 수 있습니다)에 Prometheus를 위한 EC2를 생성하고 prometheus를 설치합니다. wget {download 링크}, tar xf {압축 파일}

  2. 해당 EC2 Security Group Inbound는 만약 prometheus 서버를 직접 접속하고 싶다면 load balancer를 따로 구축하고 load balancer에 대해서 허용해줍니다. 또한, 추후 Grafana EC2를 마찬가지로 구축할텐데 해당 EC2에 대한 Security Group도 inbound에 가해줍니다. prometheus서버가 동작하는 기본 포는 9090이기 때문에 이 포트를 허용해줍니다.

  3. WAS EC2들의 경우 저는 actuator노출 포트를 10090으로 설정했으므로 inbound 10090 포트에 prometheus EC2 Security Group(Prometheus EC2가 변하는 상황을 위해 Security Group을 등록해야합니다)을 추가해줍니다.

  4. 본격적으로 prometheus.yml 파일을 수정하여 설정해줍니다.설정 내용은 다음과 같습니다.

    • alerting.alertmanagers: 이메일 등으로 문제사항 발생 시 알림을 보내도록 설정할 수 있습니다. 저는 따로 설정하지 않았습니다.
    • rule_files: 마찬가지로 그대로 두었습니다.
    • scrape_configs: metrics들을 수집할 job을 지정합니다.
      • job_name하나당 scrape하나를 지정합니다. 기본으로 있는 prometheus는 prometheus자기 자신을 모니터링합니다.
      • spring-actuator에서 ASG EC2내의 Spring Server들에서 metrics를 수집하도록 설정해야합니다. 이 부분이 설정의 주요 내용입니다. metrics_path는 수집 경로 scrape_interval는 수집 간격 static_configs.targets는 수집할 서버 ip, 포트 를 지정하면됩니다.
      • 여기서 가장 큰 문제는 ASG의 경우 EC2가 사라지고 새로 생성되는 것을 전제로 하기 때문에 ip주소가 계속 수정되는 것입니다. 따라서 static_configs는 사용할 수 없습니다.
      • prometheus는 이런 경우를 위해 동적으로 AWS 에서 메타정보를 수집하고 이를 수정하는 ec2_sd_configs와 relabel_configs라는 기능을 가지고 있습니다.
      • ec2_sd_configs는 AWS로 부터 ASG내의 metrics를 수집할 모든 EC2의 정보를 수집할 수 있도록 합니다.
        • 세부 설정은 다음 메뉴얼을 참고했습니다.
        • 이를 위해 ASG내의 EC2내의 Instance들에 특정 tag를 붙여줘야 합니다. 저는 PrometheusScrape:Enabled 라고 Launch Template에 추가하였습니다.
        • 그리고 AmazonEC2ReadOnlyAccess policy를 부여받은 user를 생성하여 access key, secret key를 입력해줍니다.
        • 요청 포트와 region도 알맞게 설정해줍니다. 이렇게 하면 기본적으로 __meta_ec2_private_ip와 같은 aws 라벨 정보를 가져와 줍니다 이 라벨은 private ip주소입니다.
      • relabel_configs는 scrape시 label을 변경해주는 설정이라고 보면됩니다. ec2_sd_configs로 private ip는 알아냈지만 port번호는 지정이 안되어있기 때문에 요청 시 label을 port번호까지 붙여서 보내야합니다.
      • source_labels 는 변경할 label을 말합니다. regex를 지정하여 만족하는 경우만 relabel을 적용합니다. replacement는 해당 패턴으로 변경함을 의미합니다. ${1}에 source_labels의 첫번째 정보가 들어갑니다. actuator를 10090에 활성화 했기 때문에 해당 포트로 지정해줍니다(제 설정파일에 10091로 되어있는 이유는 중간에 Nginx reverse proxy가 적용되어 포트를 변경했습니다).
    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: []
  5. ./prometheus로 실행 후 설정이 잘 적용되었는지 확인하려면 grafana의 ec2 9090포트 /targets 경로로 요청하면 됩니다. prometheus를 외부에서 접속하게 설정한 상태라 접속 해보면 잘 적용되었음을 확인할 수 있습니다.

4. Grafana

Prometheus도 수집한 metrics들을 query를 통해 확인할 수는 있지만 아무래도 시각화면에서 기능이 부족합니다. Grafana는 prometheus와 같이 메트릭이 수집된 서버에 요청하여 정보를 가져와 시각화 해줍니다.

Grafana설정

  1. aws private subnet에 EC2를 생성하고 Grafana를 설치합니다. 다음 링크를 활용하여 wget을 해도 되고 apt, yum들을 활용해도 됩니다.
    1. https://grafana.com/grafana/download
  2. Grafana는 local pc에서 접속할 수 있어야합니다. Grafana 서버는 기본적으로 3000포트를 열어놓습니다. load balancer를 앞단에 두고 Grafana EC2의 Security Group inbound rule 3000포트에 load balancer를 추가해줍니다. 또한 위에서 언급했듯 Grafana는 Prometheus에 접근할 수 있어야 하기때문에 Promethes EC2 inbound rule 9090포트에 Grafana Security Group을 추가해줍니다.
  3. Grafana를 실행해줍니다. (yum으로 설치했다면 sudo systemctl restart grafana-server)
  4. local pc에서 3000포트로 Grafana에 접속해 봅니다. 이런 화면이 나오면 성공입니다. 회원가입을 하고 로그인해줍니다.

  1. 대시 보드를 만들 수 있고 해당 대시보드에 panel을 추가하여 모니터링을 할 수 있습니다. custom으로 대시보드를 만들수도 있지만 꽤 학습할 사항이 많기 때문에 다른 사람이 만들어놓은 대시보드를 일부수정하여 활용하면 됩니다.
  2. 아래 링크에 가서 마음에 드는 대시보드를 찾은후 import number를 찾아 import해주면 대시보드가 자동으로 구축 됩니다.
    1. https://grafana.com/grafana/dashboards/

5. 이후에 추가적으로 공부하고 적용 해볼 내용들

  1. 모니터링 뿐만 아니라 Logging을 어떻게 어디에 남길 지에 대해서도 정리하고 적용할 필요가 있다고 느꼈습니다.
  2. 모니터링 지표중에 JVM 관련 지표들이 많은데 이에 대해서 더 알아봐야 할 필요가 있다고 느꼈습니다. GC와 같은 JVM내의 구조에 대해 개념적으로는 알고 있다고 생각했지만 막상 모니터링 수치 보았을 때 어떻게 인지해야할지 판단이 잘 되지 않았습니다. 그리고 잘 모르겠는 지표도 있어서 이들을 정리해보려고 합니다. 다음 포스트 들에서 정리하려고 합니다.
  3. 부하, 스트레스 상황에서 테스트를 진행해보려고 합니다. 이 내용 또한 다음 포스트에서 정리할 계획입니다.
profile
Fail Fast
post-custom-banner

0개의 댓글