./gradlew build 명령어로 gradle을 통해 build를 하면 build/lbis 폴더가 생기고 그 안에 jar 파일이 생깁니다.
springboot 2.5.0 부터는 아래 그림처럼 두개의 jar 파일이 생성됩니다.
❓ 왜일까요?
Plain Jar가 생기는 이유는 스프링부트의 버전에 따른 gradle 플러그인의 Packaging 기본 설정 차이 때문입니다.
springboot 2.5.0 이전에는 bootJar 가 기본적으로 설정되고 Jar 는 스킵되어서 jar 파일이 하나만 생성되었는데 2.5.0 부터 Jar 도 무조건 실행되는 것으로 바뀌어서 jar 파일도 두개가 생긴 것입니다.
실제로 빌드시 차이를 봅시다.
2.5.0 이전에는 Jar task 가 skip 되지만 이후부터는 같이 동작하는 것을 볼 수 있습니다.
bootJar와 Jar는 둘 다 Java 프로젝트를 패키징하여 jar 파일을 생성하는 Gradle 명령어입니다. 그러나 두 명령어는 몇 가지 차이가 있습니다.
gradle tasks --all로 두 명령어의 설명을 보면
bootJar Assembles an executable jar archive containing the main classes and their dependencies.
jar Assembles a jar archive containing the main classes.
라고 나옵니다.
정리하자면 bootJar는 실행 가능한 jar 아카이브를 생성합니다. 이 아카이브에는 주요 클래스와 이들에 대한 종속성(dependencies)이 포함됩니다. 즉, 실행 가능한 jar 파일을 생성하기 위해 메인 클래스와 필요한 라이브러리 등이 포함되며, 실행을 위해 필요한 Manifest 파일도 생성됩니다. 이렇게 생성된 jar 파일은 "executable archive"라고도 불립니다. 이 파일을 사용자는 'java -jar 파일이름' 명령을 통해 실행할 수 있습니다.
반면에 jar 명령어는 주요 클래스만을 포함한 jar 아카이브를 생성합니다. 즉, 소스 코드의 클래스 파일과 리소스 파일만을 포함하며, 실행에 필요한 종속성은 포함되지 않습니다. 따라서 이러한 jar 파일은 "plain archive"라고 불리며, 의존성이 포함되지 않았기 때문에 'java -jar 파일이름' 명령으로 실행할 수 없습니다. 실행 시 "no main manifest attribute" 오류가 발생할 것입니다.
❓ 그러면 -plain.jar 는 왜 만들고 어디에 쓰일까요?
바로 개발자가 자체적으로 작성한 라이브러리를 패키징하여 배포하고자 할 때 사용됩니다. 다른 프로젝트에서 공유하고 재사용하기 위해 개발자가 작성한 기능을 패키징하는 것이죠. 그래서 실행 가능한 JAR 파일로 패키징하지 않고 단순한 형태의 JAR 파일로 제공하는 것입니다.
❓ 이렇게 jar 파일이 두개가 생기면 언제 문제가 생길까요?
저는 도커파일을 만들때 영향을 받았습니다.
지난 글에서 github action을 이용해서 컨테이너 이미지를 만들고 docker hub에 업로드하기 위해 도커파일을 만들었는데요.
https://orange-makiyato.tistory.com/87
# JRE (Java Runtime Environment) 버전을 사용합니다.
# JRE는 Java 애플리케이션을 실행하는 데 필요한 최소한의 구성 요소만 포함합니다.
# 개발 시 JRE만 필요한 경우에 유용합니다.
# 가벼운 이미지이며 실행환경에 최적화되어 있습니다.
FROM adoptopenjdk:11-jre-hotspot
# build/libs/ 디렉토리에 있는 JAR 파일을 app.jar로 복사합니다.
COPY build/libs/*.jar app.jar
# java -jar app.jar 명령을 실행하도록 설정합니다.
# 컨테이너가 올라가면 바로 스프링부트 애플리케이션이 동작합니다.
ENTRYPOINT ["java", "-jar", "app.jar"]
작성된 부분중 COPY build/libs/*.jar app.jar 에서 문제가 생길 수 있습니다. 한개가 생긴다고 생각해서 모든( * ) jar 파일을 카피했는데 2개의 jar 가 생기는 바람에 제대로 동작하지 않는 상황이 생길 수 있습니다.
❓ 그래서 해결 방법은?
build.gradle에 아래와 같이 jar task 를 동작시키지 않겠다고 명시하는 코드를 추가하면 됩니다.
그러면 앞에서 보았던 2.5.0 이전 build 그림처럼 Jar task 가 skip 되고 build/libs 폴더에는 -plain.jar 가 생성되지 않게 됩니다.
그리고 도커파일도 명시적으로 수정했습니다. (굳이 하지 않아도 되지만..)
COPY build/libs/*SNAPSHOT.jar app.jar
추가로 build.gradle 에 아래의 코드를 추가해서 bootJar task로 생성되는 jar 파일의 이름을 직접 설정할 수 있습니다.
참고
'CI CD' 카테고리의 다른 글
springboot 서버 github action으로 컨테이너 이미지 만들고 docker hub에 업로드하기 (0) | 2023.05.18 |
---|---|
./gradlew build JAVA_HOME 에러 (0) | 2023.05.17 |
댓글