관리 메뉴

나구리의 개발공부기록

액츄에이터, 프로덕션 준비 기능이란?, 프로젝트 설정 및 액츄에이터 시작, 엔드 포인트 설정, 다양한 엔드포인트, 헬스 정보, 애플리케이션 정보, 로거, HTTP 요청 응답 기록, 액츄에이터와 보안 본문

인프런 - 스프링 완전정복 코스 로드맵/스프링 부트 - 핵심 원리와 활용

액츄에이터, 프로덕션 준비 기능이란?, 프로젝트 설정 및 액츄에이터 시작, 엔드 포인트 설정, 다양한 엔드포인트, 헬스 정보, 애플리케이션 정보, 로거, HTTP 요청 응답 기록, 액츄에이터와 보안

소소한나구리 2024. 12. 6. 18:12

출처 : 인프런 - 스프링 부트 - 핵심 원리와 활용(유료) / 김영한님  
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용


1. 프로덕션 준비 기능이란?

1) 모니터링의 중요성

  • 서비스를 운영할 때에는 장애는 언제든지 발생할 수 있기 때문에, 이에 빠르게 대응하기 위해서 모니터링(경계)을 잘 하는 것이 중요함
  • 개발자가 애플리케이션을 개발할 때 기능 요구사항만 개발하는 것이 아니라 서비스를 실제 운영 단계에 올리게 되면 또 다른 중요한 업무가 있는데 바로 서비스에 문제가 없는지 모니터링하고 지표들을 심어서 감시하는 것임
  • 이러한 비 기능적인 요구사항은 기획자나 고객의 요청사항으로 요구사항이 반영되지 않기 때문에 프로젝트 일정을 짜야할 때 이런 숨겨진 작업까지 고려해서 프로젝트 일정을 짜야함
  • 운영 환경에서 서비스를 할 때 필요한 이런 기능들을 프로덕션 준비 기능이라함
  • 즉 프로덕션을 운영에 배포할 때 준비해야 하는 비 기능적인 요소들을 뜻하며 지표(metric), 추적(trace), 감사(auditing), 모니터링 등이 있음
  • 구체적으로는 애플리케이션이 현재 살아있는지, 로그 정보는 정상 설정 되었는지, 커넥션 풀은 얼마나 사용되고 있는지 등등을 확인할 수 있어야 함
  • 스프링 부트가 제공하는 액추에이터는 이런 프로덕션 준비 기능을 매우 편리하게 사용할 수 있는 다양한 편의기능을 제공함
  • 더 나가가서 마이크로미터, 프로메테우스, 그라파나 같은 최근 유행하는 모니터링 시스템과 매우 쉽게 연동할 수 있는 기능도 제공함

** 참고

  • 액추에이터는 시스템을 움직이거나 제어하는데 쓰이는 기계 장치라는 뜻

2. 프로젝트 설정 및 액츄에이터 시작

1) 프로젝트 설정

(1) 프로젝트 설정 - build.gradle

  • 제공된 프로젝트를 사용
  • 스프링 부트로 제공된 프로젝트
  • 사용된 라이브러리: Spring Boot Actuator, Spring web, Spring Data JPA, H2 Database, Lombok
  • 테스트 코드에서 lombok을 사용할 수 있도록 설정을 추가
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.2'
    id 'io.spring.dependency-management' version '1.1.0'
}

group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator' //actuator 추가

    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    //test lombok 사용
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

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

2) 액츄에이터 시작

(1) 동작 확인

  • 프로젝트 설정 시 액츄에이터 라이브러리를 추가 했으므로 애플리케이션 실행 후 localhost:8080/actuator로 접속하면 동작을 확인할 수 있음
  • 포스트 맨으로 실행해도 결과를 확인할 수 있음
  • health 결과를 제공하는 URL(localhost:8080/actuator/health)를 실행해보면 현재 서버가 잘 동작하고 있는지 애플리케이션의 헬스 상태를 나타냄
  • 지금 눈에 보이는 기능은 헬스 상태를 확인할 수 있는 기능 뿐이며 액츄에이터는 헬스 상태 뿐만 아니라 수 많은 기능을 제공하는데 이런 기능이 웹 환경에서 보이도록 노출해야함

 

(2) application.yml 추가

  • application.properties를 사용해도 되지만 실무에서 더 자주 사용하는 application.yml을 사용
  • 액츄에이터 기능을 웹에 노출하도록 설정 추가
management:
  endpoints:
    web:
      exposure:
        include: "*"

 

(3) 동작 확인

  • 실행해보면 액츄에이터가 제공하는 수 많은 기능을 확인할 수 있음 (너무 많아서 결과 생략)
  • 액츄에이터가 제공하는 기능 하나하나를 엔드포인트라 하며 각각의 엔드포인트는 /actuator/{엔드포인트명}과 같은 형식으로 접근할 수 있음
  • localhost:8080/actuator/health: 애플리케이션 헬스 정보
  • localhost:8080/actuator/beans: 스프링 컨테이너에 등록된 빈 정보

3. 엔드 포인트 설정

1) 엔드 포인트 설정

(1) 엔드포인트를 사용하기 위한 과정

  • 엔드포인트를 사용하려면 엔드포인트를 활성화하고 엔드포인트를 노출 하는 2가지 과정이 필요함
  • 엔드포인트를 활성화 한다는 것은 해당 기능 자체를 사용할지 말지 on, off를 선택하는 것
  • 엔드포인트를 노출하는 것은 활성화된 엔드포인트를 HTTP에 노출할지 아니면 JMX에 노출할지 선택하는 것임
  • 즉 엔드포인트를 활성화하고 추가로 HTTP를 통해서 웹에 노출할지, JMX를 통해서 노출할지 두 위치에 모두 노출할지에 대해 노출 위치를 지정해 주어야 하며 활성화가 되어있지 않으면 노출도 되지 않음
  • 대부분의 엔드포인트는 기본으로 활성화가 되어있으며 노출이 되어있지 않을 뿐임(shutdown 제외, 해당 엔드포인트를 호출하면 서버가 내려가버림)
  • 따라서 어떤 엔드포인트를 노출할지 선택하기만 하면 되며 보통 JMX는 잘 사용하지 않으므로 HTTP에 어떤 엔드포인트를 노출할지 선택하면 됨
  • 2강에서 application.yml에 입력한 설정이 모든 엔드포인트를 웹에 노출한 설정이였으며, 엔드포인트 활성화 + 엔드포인트 노출이 둘다 적용되어야 사용할 수 있음

(2) application.yml - shutdown 엔드포인트 활성화

  • 특정 엔드포인트를 활성화 하려면 management.endpoint.{엔드포인트명}.enabled=true를 적용하면 됨
  • 애플리케이션을 실행해보면 기존에는 없던 shutdown 엔드 포인트가 노출되어있는 것을 확인할 수 있음
  • HTTP GET으로 호출하면 동작하지 않으므로 Postman 등을 활용해서 POST로 localhost:8080/actuator/shutdown을 호출하면 메시지와 함께 실제 서버가 종료되는 것을 확인할 수 있음
  • 물론 이 기능은 매우 주의해서 사용해야 하며 그렇기 때문에 기본으로 비활성화 되어 있음
management:
  endpoint:
      shutdown:
        enabled: true
  endpoints:
    web:
      exposure:
        include: "*"

 

(3) 엔드포인트 노출

  • 스프링 공식 매뉴얼이 제공하는 엔드포인트 노출 설정 예제
  • jmx에 health, info를 노출
  • web에 모든 엔드포인트를 노출하지만 env, beans는 제외
management:
  endpoints:
    jmx:
      exposure:
        include: "health,info"
        
---        
management:
  endpoints:
    web:
      exposure:
        include: "*"
        exclude: "env,beans"

4. 다양한 엔드포인트

1) 다양한 엔드 포인트

  • 각각의 엔드포인트를 통해서 개발자는 애플리케이션 내부의 수 많은 기능을 관리하고 모니터링 할 수 있음
  • 스프링 부트의 actuator를 사용하는 것만으로도 이룬 수많은 기능이 제공되는 것이 개발자 입장에서는 매우 편리함

(1) 자주 사용하는 엔드포인트 목록

  • beans: 스프링 컨테이너에 등록된 스프링 빈을 보여줌
  • conditions: condition을 통해서 빈을 등록할 때 평가 조건과 일치하거나 일치하지 않는 이유를 표시함
  • configprops: @ConfigurationProperties를 보여줌
  • env: Environment 정보를 보여줌
  • health: 애플리케이션 헬스 정보를 보여줌
  • httpexchanges: HTTP 호출 응답 정보를 보여줌, HttpExchangeRepository를 구현한 빈을 별도로 등록해야 함
  • info: 애플리케이션 정보를 보여줌
  • loggers: 애플리케이션 로거 설정을 보여주고 변경할 수 있음
  • metrics: 애플리케이션의 메트릭 정보를 보여줌
  • mappings: @RequestMapping 정보를 보여줌
  • threaddump: 쓰레드 덤프를 실행해서 보여줌
  • shutdown: 애플리케이션을 종료함, 기본적으로 비활성화 되어있음
  • 전체 엔드포인트 공식 매뉴얼

5. 헬스 정보

1) 헬스 엔드포인트

  • 애플리케이션에 문제가 발생했을 때 문제를 빠르게 인지할 수 있음

(1) 기본 동작

  • 헬스 정보는 단순히 애플리케이션이 요청에 응답할 수 있는지 판단하는 것을 넘어서 애플리케이션이 사용하는 데이터베이스가 응답하는지, 디스크 사용량에는 문제가 없는지와 같은 다양한 정보들을 포함해서 만들어짐

(2) application.yml - show-details 옵션

  • management.endpoint.health.show-details=always를 application설정에 적용하면 헬스 정보를 더 자세히 볼 수 있음
  • 해당 옵션을 적용하면 각각의 항목이 매우 자세하게 노출됨
management:
  endpoint:
      health:
        show-details: always

 

(3) application.yml - show-components 옵션

  • 너무 자세하게 노출되는 것이 부담스럽다면 show-components=always로 해당 옵션을 사용하면 됨
  • 각 헬스 컴포넌트의 상태 정보만 간략하게 노출함
  • 헬스 컴포넌트 중에 하나라도 문제가 생기면 전체 상태를 표시하는 status도 DOWN으로 표시가 됨

 

** 참고

  • 액츄에이터는 db, mongo, redis, diskspace, ping과 같은 수 많은 헬스 기능을 기본으로 제공함
  • 공식 매뉴얼
  • 원하는 경우 직접 헬스 기능을 구현해서 추가할 수 있으나 직접 구현하는 일은 많지 않기 때문에 필요한 경우만 아래의 매뉴얼을 참고해서 구현하면 됨
  • 직접 구현 매뉴얼

6. 애플리케이션 정보

1) Info 엔드포인트

  • 애플리케이션의 기본 정보를 노출

(1) 기본으로 제공하는 기능들

  • java: 자바 런타임 정보
  • os: OS 정보
  • env: Environment에서 info.로 시작하는 정보
  • build: 빌드 정보, META-INF/build-info.properties파일이 필요함
  • git: git정보, git.properties파일이 필요함
  • env, java, os는 기본으로 비활성화 되어 있음

(2) application.yml - java, os

  • management.info.<id>.enabled의 값을 true로 지정하면 활성화가 됨
  • info는 특이하게 management.endpoint하위가 아니라 management 바로 다음에 info가 나오는것에 주의해야함
  • 실행 후 엔드포인트에 접속해보면 java와 os의 정보가 노출되는 것을 확인할 수 있음
management:
  info:
    java:
      enabled: true
    os:
      enabled: true

 

(3) application.yml - env

  • Environment에서 info.로 시작하는 정보를 출력
  • management.info.env.enabled: true를 추가하고 info정보를 추가한뒤 엔드포인트에 접속해보면 입력해둔 info 환경변수 정보들이 노출되는 것을 확인할 수 있음

 

management:
  info:
    env:
      enabled: true
      
info:
  app:
    name: hello-actuator
    company: guri


(4) build.gradle - build

  • 빌드 정보를 노출하려면 빌드 시점에 META-INF/build-info.properties파일을 만들어야함
  • gradle에 아래의 내용을 추가하고 빌드를 해보면 build 폴더안에 resources/main/META-INF/build-info.properties파일을 확인할 수 있음
  • 파일 내용을 보면 애플리케이션의 기본 정보와 버전, 빌드 시간을 확인할 수 있음
  • 엔드포인트에 접속해보면 파일의 정보처럼 build정보가 노출되는 것을 확인할 수 있음
// build.gradle에 추가

springBoot {
    buildInfo()
}

// 생성된 build-info.properties 파일 내용
build.artifact=actuator
build.group=hello
build.name=actuator
build.time=2024-12-06T07\:33\:54.258335Z
build.version=0.0.1-SNAPSHOT

 

(5-1) build.gradle - git

  • build와 유사하게 빌드 시점에 사용한 git 정보도 노출할 수 있으며 git정보도 노출하려면 git.properties 파일이 필요함
  • 물론 프로젝트가 git으로 관리 되어있어야 하며 그렇지 않으면 빌드시 오류가 발생함
  • build.gradle의 plugins에 아래처럼 입력하여 플러그인을 추가 후 커밋을 실행
  • 빌드를 해보면 build 폴더안에 resources/main/git.properties파일을 확인할 수 있음
  • 엔드포인트에 접속해보면 git의 branch와 commit 정보가 노출되는 것을 확인할 수 있음
  • 애플리케이션을 배포할 때 다른 커밋이나 다른 브랜치의 내용이 배포된 경우가 되어기대와 전혀 다르게 동작할 때가 있는데 이럴때 큰 도움이 됨
// build.gradle의 plugins에 git 추가
plugins {
    // ... 기존 설정 생략
    id "com.gorylenko.gradle-git-properties" version "2.4.1" //git info
}

// 생성된 git.properties
git.branch=main
git.build.host=namo.local
git.build.user.email=hayani0000@gmail.com
git.build.user.name=nagul2
git.build.version=0.0.1-SNAPSHOT
git.closest.tag.commit.count=
git.closest.tag.name=
git.commit.id=92413f9a7dfbabfb1cfed96f966240556f3522a4
git.commit.id.abbrev=92413f9
git.commit.id.describe=
git.commit.message.full=start\n
git.commit.message.short=start
git.commit.time=2024-12-06T16\:40\:56+0900
git.commit.user.email=hayani0000@gmail.com
git.commit.user.name=nagul2
git.dirty=true
git.remote.origin.url=
git.tags=
git.total.commit.count=1

 

(5-2) application.yml - git

  • git에 대한 자세한 정보를 노출하고 싶다면 application.yml에 옵션을 적용하면 됨
management:
  info:
    git:
      mode: full

 

** 참고

  • info의 사용자 정의 기능을 추가하고 싶으면 공식 매뉴얼을 참고하면 됨, 그러나 적용할 일은 많지 않음
  • 매뉴얼

7. 로거

1) Loggers 엔드포인트

  • 로깅과 관련된 정보를 확인하고 로깅 레벨을 실시간으로 변경할 수 있음

(1) LogController

  • controller 패키지를 생성 후 작성
  • 여러 레벨의 로그를 남기는 단순한 컨트롤러
package hello.controller;

@Slf4j
@RestController
public class LogController {

    @GetMapping("/log")
    public String log() {
        log.trace("trace log");
        log.debug("debug log");
        log.info("info log");
        log.warn("warn log");
        log.error("error log");
        return "ok";
    }
}

 

(2) application.yml 설정 및 실행

  • 로그 레벨을 hello.controller 패키지와 그 하위는 DEBUG 레벨로 출력하도록 설정하여 LogController 클래스가 DEBUG 레벨의 영향을 받도록 설정
  • 애플리케이션을 실행 후 localhost:8080/log에 접속해보면 로그가 DEBUG 부터 error까지 출력되는 것을 확인할 수 있음
logging:
  level:
    hello.controller: debug

 

(3) loggers 엔드포인트 호출

  • localhost:8080/actuator/loggers로 접속하여 엔드포인트를 호출
  • 로그를 별도로 설정하지 않으면 스프링 부트는 기본으로 로그레벨을 INFO를 사용하여 실행 결과를 보면 ROOT의 configuredLevel이 INFO인 것을 확인할 수 있음
  • application.yml 설정으로 hello.controller는 DEBUG로 설정했는데, 해당 부분의 결과를 보면 configuredLevel이 DEBUG로 설정 되었으며 그 하위인 LogController도 당연히 DEBUG 레벨이 적용된 것을 확인할 수 있음

(4) 더 자세히 조회하기

  • 아래와 같은 패턴을 사용해서 특정 로거 이름을 기준으로 조회할 수 있음
  • localhost:8080/actuator/loggers/{로거이름}

2) 실시간 로그 레벨 변경

(1) 실시간 로그 레벨 변경 상황 예시

  • 로컬 PC는 로그 레벨을 TRACE나 DEBUG로 사용하고 개발 서버는 보통 DEBUG로 사용함
  • 운영 서버는 요청이 매우 많아 로그도 많이 남기 때문에 DEBUG 로그까지 출력하게되면 성능이나 디스크에 영향을 주게되어 INFO 로그 레벨을 주로 사용함
  • 그러나 운영중에 문제가 있어서 급하게 DEBUG나 TRACE로 로그를 남겨서 확인해야 하고 싶은 상황이 발생했다면 일반적으로는 로깅 설정을 변경하고 서버를 다시 시작해야함
  • loggers 엔드포인트를 사용하면 애플리케이션을 다시 시작하지 않고 실시간으로 로그 레벨을 변경할 수 있음

(2) Postman - POST 요청

  • 꼭 POST를 사용해야함
  • 아래처럼 JSON으로 로그 레벨을 변경하고자할 엔드포인트의 URL로 POST 요청을 보내면 204 응답이 옴(별도의 응답 메시지는 없음)
  • 변경 후 다시 GET으로 엔드포인트를 호출해보면 지정한 위치와 그 하위위치의 로그 레벨이 TRACE로 변경된 것을 확인할 수 있음
  • localhost:8080/log로 접속하여 출력된 로그 결과를 봐도 trace 로그가 출력되어 로그레벨이 변경된 것을 확인할 수 있음
  • 물론 서버를 껏다 키면 application.yml에 설정된 값으로 로그 레벨이 적용됨

 

{
    "configuredLevel" : "TRACE",
}

8. HTTP 요청 응답 기록

1) httpexchanges

(1) 활성화

  • HTTP요청과 응답의 과거 기록을 확인하고자 할때 해당 엔드포인트를 사용하면 됨
  • HttpExchangeRepository 인터페이스의 구현체를 빈으로 등록하면 httpexchanges 엔드포인트를 사용할 수 있으며 해당 빈을 등록하지 않으면 활성화되지 않음
  • 스프링 부트는 기본으로 InMemoryHttpExchangeRepository 구현체를 제공함

(2) ActuatorApplication -  InMemoryHttpExchangeRepository 추가

  • InMemoryHttpExchangeRepository는 최대 100개의 HTTP 요청을 제공하며 최대 요청이 넘어가면 과거 요청을 삭제함
  • setCapacity()로 최대 요청수를 변경할 수 있음
  • 구현체를 빈으로 등록하고 애플리케이션을 실행 후 엔드포인트를 호출해보면 지금까지 실행한 HTTP 요청과 응답 정보를 확인할 수 있음
package hello;

@SpringBootApplication
public class ActuatorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }

    @Bean
    public InMemoryHttpExchangeRepository httpExchangeRepository() {
        return new InMemoryHttpExchangeRepository();
    }
}

 

** 참고

  • 이 기능은 매우 단순하고 기능에 제한이 많기 때문에 개발 단계에서만 사용하고 실제 운영 서비스에서는 전문적인 모니터링 툴이나 핀포인트, Zipkin 같은 다른 기술을 사용하는 것이 좋음
  • 영한님 개인적으로 핀포인트를 추천한다고 함

9. 액츄에이터와 보안

1) 보안 주의

  • 액츄에이터가 제공하는 기능들은 애플리케이션의 내부 정보를 너무 많이 노출하여 공개 된 외부 인터넷 망에 액츄에이터의 엔드포인트를 공개하는 것은 보안상 좋은 방안이 아님
  • 액츄에이터의 엔드포인트들은 외부 인터넷에서 접근이 불가능하게 막고 내부에서만 접근 가능한 내부망을 사용하는 것이 안전함

(1) 액츄에이터를 다른 포트에서 실행

  • 외부 인터넷 망을 통해서 8080포트에만 접근할 수 있고 다른 포트는 내부망에서만 접근할 수 있다면 액츄에이터에 다른 포트를 설정하면됨
  • application 설정에서 아래와 같이 설정하면 기존 8080포트에서는 액츄에이터를 접근할 수 없고 설정한 포트에서만 actuator를 접근할 수 있음
  • 설정 후 애플리케이션을 실행하고 8080으로 액츄에이터를 접속해보면 에러페이지가 뜨고 설정한 포트인9292로 접속하면 액츄에이터가 실행되는 것을 확인할 수 있음
  • 애플리케이션 실행 시 로그에도 9292 포트가 활성화 되는 것을 확인할 수 있음
management:
  server:
    port: 9292

 

(2) 액츄에이터 URL 경로에 인증 설정

  • 포트를 분리하는 것이 어렵고 어쩔 수 없이 외부 인터넷 망을 통해서 접근해야 한다면 /actuator 경로에 서블릿 필터, 또는 스프링 시큐리티를 통해서 인증된 사용자만 접근 가능하도록 추가 개발이 필요함

(3) application.yml - 엔드포인트 경로 변경

  • 엔드포인트의 기본 경로를 변경하려면 설정에서 아래의 형식으로 설정하면됨
  • management.endpoints.web.base-path: "/{경로}"
  • /actuator/{엔드포인트} 대신에 /manage/{엔드포인트}로 경로가 변경됨
management:
  endpoints:
    web:
      base-path: "/manage"

 

'인프런 - 스프링 완전정복 코스 로드맵 > 스프링 부트 - 핵심 원리와 활용' 카테고리의 다른 글

모니터링 메트릭 활용, 메트릭 등록(예제 만들기/카운터/@Counted/Timer/@timed/게이지), 실무 모니터링 환경 구성 팁  (2) 2024.12.09
마이크로미터/프로메테우스/그라파나, 마이크로미터 소개, 메트릭 확인하기, 다양한 메트릭, 프로메테우스와 그라파나 소개, 프로메테우스(설치/애플리케이션 설정/ 수집 설정/ 기본 기능/게이지와 카운터), 그라파나(설치 및 연동/대시보드 만들기/공유 대시보드 활용/메트릭을 통한 문제 확인)  (2) 2024.12.08
외부설정과 프로필2, 프로젝트 설정, 외부 설정 사용(Environment/@Value/@ConfigurationProperties(시작/생성자/검증)), YAML, @Profile  (2) 2024.12.06
외부설정과 프로필1, 프로젝트 설정 및 외부 설정이란?, 외부 설정(OS 환경 변수/자바 시스템 속성/커맨드 라인 인수/커맨드 라인 옵션 인수/커맨드 라인 옵션 인수와 스프링 부트/스프링 통합), 설정 데이터(외부 파일/내부 파일 분리/내부 파일 합체), 우선순위(설정 데이터/전체)  (1) 2024.12.05
자동 구성(Auto Configuration), 순수 라이브러리 만들기, 순수 라이브러리 사용하기, 자동 구성 라이브러리 만들기, 자동 구성 라이브러리 사용하기, 자동 구성 이해(스프링 부트의 동작/ImportSelector)  (1) 2024.12.02