오늘의 글 요약
•
핵심 : Spring Boot Actuator를 이용해 git 정보를 expose 해주는 방식으로 버전 번호 관리함
◦
gradle-git-properties 플러그인을 이용해 build 시 git.properties 파일을 생성하게 해줌
◦
git.properties 파일 내용을 info endpoint에 넣어줌
•
장점 : 로컬 개발이 아닌 개발서버, 운영서버에 구동중인 application이 생각과 다르게 동작할때, 이게 어떤 git commit까지 반영된건지, branch가 어떤건지를 actuator 를 통해 확인할 수 있음
•
이슈 : Spring actuator 의존성 추가 시 [Failed to start bean 'documentationPluginsBootstrapper'] 에러 남
◦
Springfox는 Spring MVC가 Ant-based path matcher를 기본값으로 하여 경로를 찾는 것으로 가정하는데 Spring MVC가 2.6.X부터 기본값을 Ant-based path matcher에서 PathPattern-based matcher로 변경하여서 발생하는 버그였음
◦
WebEndpointServletHandlerMapping 추가해서 해결해줌
•
결론 : /actuator/info 엔드포인트에서 아래와 같이 commit message 내용으로 버전 확인 가능함
{
"git": {
"branch": "master",
"commit": {
"time": "2023-09-22T08:56:26Z",
"message": {
"full": "v1.0.0\n",
"short": "v1.0.0"
},
...
}
JSON
복사
Spring actuator 이용한 애플리케이션 모니터링 (+버전관리)
•
서론)
◦
이전에 github actions 초록불만 보고서 배포가 잘 되었다고 생각했는데, 알고보니 docker image pull을 실패하고서 계속 과거의 특정 이미지만 배포하고 있었던 적이 있었다.
◦
api 배포서버에 올렸는데 프론트에서 자꾸 없다해서 이상하다,,,싶다가 좀 뒤늦게 잘못된 걸 찾았다.
◦
이런 일을 방지하기 위해선 배포된 플젝의 버전을 확인할 수 있어야 한다. 이번 프로젝트에서 프론트로부터 해당 요청을 받았다.
◦
그럼 배포된 프로젝트가 가장 최신에 배포한 버전으로 제대로 배포되었는지 어떻게 확인할 수 있을까?
1.
build.gradle에 버전을 명시하는 방법이 있을 거고
2.
docker tag를 사용해도 가능하고
3.
github tag를 사용하는 것도 좋다.
◦
다만 2번이나 3번 방식의 단점은,,, docker hub와 github 에 종속적이게 된 단 거다. 우리 팀은 코드단으로 버전을 관리하고 싶었다.
◦
그렇다면, 1번 방식밖에 답이 없는 것일까?
◦
1번 방식의 크리티컬한 단점은 자동화가 불편하단 점이다. cicd를 구축했을 때 코드단의 버전을 바꾸는 커밋을 날리는 시점이 애매하다.
◦
내가 생각한 가장 간단한 방법은 3번이다, 오잉? 3번은 github에 종속적이라 싫다매요. 라고 묻는다면
◦
Spring Actuator를 잘 활용하면 된다고 답하겠다.
◦
그래서 오늘은 Spring Actuator를 이용해 어떻게 버전 관리를 github에 종속적이지 않게 할 수 있는지 그 방법을 적겠다.
•
본론)
◦
원리
▪
먼저 gradle-git-properties 플러그인을 사용해 build 시 현재 git 정보를 코드 상으로 저장하게 한다.
▪
그리고, spring actuator 의존성을 추가하면 spring boot가 기본으로 제공하는 엔드포인트인 /actuator/info 를 이용해 아래와 같이 git 정보를 확인할 수 있다.
{
"git": {
"branch":"master",
"commit":{
"time":"2023-09-25T09:03:07Z",
"message":{
"full":"v1.1.0\n\nv1.1.0",
"short":"v1.1.0"},
...
JSON
복사
▪
이 프로세스 대로 배포된다면 우린 배포 환경에서도 해당 엔드포인트로 git 정보를 확인해 배포된 버전 정보까지 확인할 수 있을 것이다. 뭐,,, cicd 과정에서 git tag를 달아주는 것도 좋지만 우리팀은 일단 커밋메시지(겸 릴리즈 pr 제목)으로 확인하기로 했다. 추후에 이 커밋 메시지(v1.1.0)으로 깃 태그까지 함께 달아주면 더할 나위 없이 좋을 것이다. 이 부분은 별도의 포스트로 작성하겠다.
◦
적용
▪
build.gradle → 플러그인, 의존성 추가
plugins {
...
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
JSON
복사
▪
application.yml → actuator 엔드포인트 추가
management:
endpoints:
web:
exposure:
include: info
info:
git:
mode: full
JSON
복사
▪
끝입니다,,,ㅋㅋㅋㅋㅋ 자 이제 build 후 실행 해서 localhost:8080/actuator/info 로 들어가보세용 요걸 배포하면 인제 배포환경에서도 해당 엔드포인트를 쓸 수 있는거구요~
•
결론) spring actuator 정말 편하다! 다들 꼭 써보길 추천한다
•
Spring actuator 의존성 추가 npe 해결
•
gradle로 실행할 때만 뜸,,,
•
cicd 환경은 gradle 로 빌드하기에 일단 해결해주기로 함
•
이게,,, actuator 의존성이 swagger 의존성이랑 충돌하는 게 특정 버전에서만 생기는 버그라 한다
◦
요 두 녀석이다
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
Java
복사
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Java
복사
•
버전을 내리긴 싫어서 아래 코드 추가해줘서 해결했다.
@Configuration
@EnableSwagger2
public class SwaggerConfig {
// 요 녀석이랑
@Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment,
basePath);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping, null);
}
// 요 녀석 두 개 추가해줬다.
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
String basePath) {
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
@Bean
public Docket restAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Fis-police Spring Boot REST API")
.version("1.0.0")
.description("swagger api ")
.build();
}
}
Java
복사