본문 바로가기

Study/Server

[Jenkins] (3) 빌드 후 애플리케이션 자동 실행 설정 시도하기 (권장❌)

로컬에서 빌드 후 애플리케이션 자동 실행 스크립트 작성하기 

이번 글에서는 Jenkins 빌드 후 자동 실행 스크립트를 작성해 애플리케이션 서버를 띄워볼 것이다. 

 

 

1. Jenkins 빌드 파일 저장 위치 확인

로컬에 설치한 Jenkins에서 빌드된 파일이 저장되는 위치는 다음과 같다. JAR 혹은 WAR 파일이 생성된다. 

/Users/<사용자 이름>/.jenkins/workspace/<프로젝트 이름>/target/

 

나의 경우에는 빌드된 파일이 JAR 파일이다. 

 

 

 

2. 아티팩트(빌드 파일) 실행하기

아래 빌드 파일의 종류에 따라 터미널에서 아래 명령어를 입력하면 애플리케이션을 실행할 수 있다. 

JAR 파일 실행 명령어

$ java -jar /Users/<사용자 이름>/.jenkins/workspace/<프로젝트 이름>/target/<아티팩트 이름>.jar

WAR 파일 실행 명령어

$ cp /Users/<사용자 이름>/.jenkins/workspace/<프로젝트 이름>/target/<아티팩트 이름>.war /path/to/tomcat/webapps/

 

 


에러 해결하기

... Factory method 'getNaverMailerApi' threw exception with message: Failed to load credentials from the ./src/main/resources/credentials.properties file ....

 

위의 JAR 실행 명령어로 파일을 실행했더니 위와 같은 에러가 발생했다. 이 메세지를 가지고 chatGPT에게 물어보니 애플리케이션이 'credentials.properties' 파일을 로드할 수 없어서 발생하는 문제라고 한다. InteliJ에서 실행할 때는 이 파일이 정상적으로 로드되지만, Jenkins에서 빌드한 JAR 파일을 실행할 때는 해당 파일을 찾지 못하는 상황이다. 

 

 

이 문제를 해결하기 위해 시도한 순서는 다음과 같다.

 

시도 1. src/main/resources/credentials.properties 파일이 build된 JAR 파일 안에 (BOOT-INF/classes/credentials.properties 경로) 저장되어 있는지 확인 > 정상이지만 해결

 

JAR 파일 내부에 BOOT-INF 디렉토리가 있는지(해당 디렉토리 안에 있는 파일이 있는지) 확인하는 명령어는 아래와 같다.

$ jar tf your-application.jar | grep BOOT-INF

 

현재 build할 때 src/main/resources/에 있던 파일들이 빌드된 JAR 파일에서는 BOOT-INF/classes/ 위치에 정상적으로 생성된 것을 확인했다. 그럼에도 불구하고 코드가 실행될 때 .properties 파일이 잘 불러지지 않은 이유를 찾아보니, 내부 소스코드에서 특정 경로로 박혀있었기 때문인 것 같다. (실행 환경에 따라 해당 파일을 불러올 때 파일의 상대 경로가 달라짐)

 

getClass().getClassLoader().getResourceAsStream("credentials.properties")처럼 클래스패스를 통해 접근하는 코드는 JAR 파일 내부의 BOOT-INF/classes/credentials.properties를 자동으로 참조하지만, 나는 기존 코드를 수정하지 않고 해결하기 위해 다른 방법을 알아보았다. 

 

 

시도 2. JAR 파일 실행시 외부 파일 경로를 지정하기

 

애플리케이션 실행시 내부에서 생성된 파일 경로로 자동 참조하지 않고(혹은 나의 경우처럼 특정 경로가 고정되어서 자동 참조되지 않을 때), 외부 파일을 사용하는 방법에는 두 가지가 있다. 

 

(1) JAR 파일 내부에 있는 'credential.properties' 파일을 참조하기 > 실패 ❌

빌드될 때 JAR 내부에 생성되는 파일을 참조하도록 명령줄 인자를 추가했지만, 여전히 파일을 찾지 못했다... 

$ java -jar your-application.jar --naver.mail.credentials-path=classpath:credentials.properties

 

 

(2)  JAR 파일 외부에 있는 파일을 참조하기 > 성공 ⭕️

JAR 파일을 실행할 때의 위치 기준에서 credentials.properties 파일의 상대 경로를 직접 인자로 넘겨주니 드디어 성공!

$ java -jar your-application.jar --spring.config.location=file:{상대경로}/credentials.properties

 


 

 

3. localhost:{port} 접속 확인

애플리케이션이 잘 띄워졌는지 확인하기 위해 웹 브라우저에서 swagger 페이지에 접속하니 정상적으로 잘 동작한다. 

 

 

 

4. Jenkins 빌드 후 실행 단계 추가

Jenkins > Dashboard > Item명 > Configure > Build Steps에서 "Execute shell" command에 JAR 실행 명령어를 작성한다. 

 

단, 이 때 파일 위치를 지정할 땐(JAR, properties 파일 등) 절대 경로를 사용하는 것이 좋다.

 

Jenkins 애플리케이션 실행 Command

$ java -jar /Users/{your_name}/jenkins/workspace/{item_name}/target/{jar_file_name}.jar {option}

'''나의 경우는 아래와 같다'''
$ java -jar /Users/yewon_lee/jenkins/workspace/TestMavenProject/target/testfile.jar {option}
 --naver.mail.credentials-path=/Users/yewonlee/.jenkins/workspace/TestMavenProject/target/classes/credentials.properties

Build Steps 작성 화면

 

 

 

5. 정상 작동 확인

GitHub에 Commit을 해 Jenkins에서 빌드 및 실행 까지 자동으로 실행되는지 확인하면 끝! 

 


 

하지만.... 나의 경우는 해결할 내용이 한가지 더 생겼다. Spring Scheduler 때문에 애플리케이션이 Foreground 단에서 계속 실행되기 때문에 아래 사진처럼 계속 진행중 상태로 나왔다. ;;

빌드가 끝나지 않고 무한 진행중 현상

 

 

 

이런 경우에 가장 간단히 해결할 수 있는 방법은, Background에서 실행할 수 있도록 nohup 명령을 사용할 수 있다.

 

백그라운드 실행 Command

기존 Command에서 제일 앞에 nohup과 제일 마지막에 log파일 저장 위치 &을 추가하면 된다.

$ nohup java -jar /Users/{your_name}/jenkins/workspace/{item_name}/target/{jar_file_name}.jar {option} > output.log 2>&1 &

 

2>&1는 redirection을 통해 표준 에러 출력을 표준 출력과 같은 파일로 보내는 것을 의미한다. 이를 통해 모든 출력을 한 곳에서 확인할 수 있게 한다. 

 

&을 사용해 백그라운드에서 실행하고, nohup을 사용해 터미널 세션 종료와 무관하게 프로세스가 계속 실행되도록 한다는 의미이다.

 


 

하지만 에러는 여기서 끝나지 않았다. 실행은 정상적으로 되지만, 곧바로 종료되어버렸다.. 

 

빌드 후 곧바로 세션이 종료되는 원인은?

원인을 찾아보니 Jenkins는 보통 빌드만 전담하기 때문에 빌드 스크립트가 끝나면 해당 세션을 종료시킨다고 한다. 웬만하면 젠킨스를 통해 빌드만 수행하고, 추후 빌드서버와 실행 환경을 분리 해 ssh로 붙어서 빌드된 파일을 실행 환경에 업로드 한 뒤 nohup으로 실행하는 방법을 따르는 것이 좋다고 한다. 

 

,,, 아무리 구글링해서 시도해봐도 실행이 되지 않는다. 젠킨스를 통해 자동 빌드하는 프로세스는 우선 하지 않기로...! 

 

 

 

우선 자동 빌드된 파일을 직접 실행해서 띄워보기로 한다..!ㅋㅋ

반응형