본문 바로가기
Back/Spring Boot

[SpringBoot] war로 배포하기, 외장 톰캣 구동 (+Trouble Shooting)

by 은z 2023. 10. 11.

 

상황

SpringBoot의 경우 기본적으로 내장 tomcat을 지원하고 이는 jar 형식으로 배포해서 사용한다.

하지만 좀 더 세부적인 톰캣 모듈 설정이 필요하거나 고객사의 요청에 의해 war로 패키징 해야하는 경우도 있다.

내 상황도 고객사의 요청에 의해 jar 방식을 war 로 바꾸어야 했다.

 

하나씩 차근차근 해보며, 트러블 슈팅하는 과정도 정리해보려고 한다.

 

 

 

실행환경 및 버전

  • OS : Ubuntu 20.04.3 LTS
  • build tool : Gradle
  • IDE : Intellij 유료버전
  • JDK : open JDK 11
  • Spring Boot : 2.7.9
  • Tomcat : 9.0.71 (SpringBoot에 내장되어있는 톰캣과 버전을 맞춤, 내장톰캣 버전 확인방법은 아래 사진 참고)

 

 


적용

 

✔️1. build.gradle 수정

✏️ war로 빌드하기 위하여 build.gradle 파일을 수정한다. id 'war' 를 추가하고 Refresh Gradle Project  후,  IDE 내 gradle task리스트를 확인해 보면 bootWar와 war가 추가된 것을 확인할 수 있다.

plugins {
   id 'java'
   id 'org.springframework.boot' version '2.7.9'
   id 'io.spring.dependency-management' version '1.0.15.RELEASE'
   id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
   id 'idea'
   
   id 'war' // war로 패키징 명시
}

.
. (중간 생략)
.

bootWar.enabled = false // bootWar : 내장 톰캣 어플리케이션으로 실행이 가능하도록 패키징하는 task (단독 실행 가능)
war.enabled = true //war : 외장 톰캣 서버에 배포할 목적으로 패키징하는 task (단독 실행 불가능)

dependencies {

	//내장톰캣이 외부톰캣에 영향을 주지 않도록 providedRuntime으로 명시해주어야 함
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 

    
    
            .
            . (중간 생략)
            .
            
}

 

📌 providedRuntime 으로 명시하는 부분

애플리케이션의 내장톰캣이 외부 서블릿컨테이너 작동에 영향을 주지 않도록 providedRuntime으로 명시해야 한다.

providedRuntime로 지정된 의존성(dependency)은 빌드가 실행되면 의존성 jar파일이 lib-provided 디렉터리에 패키지 되어 WAR파일이 생성되므로, 내/외장 서블릿 컨테이너 모두에 사용 가능한 WAR파일이 될 수 있다.

 

📌bootWar 와 war의 차이

bootWar : bootWar는 실행 가능한 war파일 생성을 위한 task로, 내장 톰캣 엔진이 포함돼서 만들어지기 때문에 단독 실행이 가능

war : war는 외장 톰캣 서버에 배포할 목적으로 war파일을 생성하는 task로, 단독 실행이 불가능하다.

 

📌 bootWar.enabled = false
      war.enabled = true

war를 사용하고 싶다면 두 태스크 간(bootWar와 war)의 충돌을 막기 위해 build.gradle에 위 소스 코드 추가가 필요하다.

 

 

✔️2. SpringBootServletInitializer 상속 

✏️ 외장 톰캣으로 서비스를 제공하기 위해서는 main 클래스에서 SpringBootServletInitializer상속 받고, configure 메서드 오버 라이딩이 추가적으로 필요하다.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class TestApplication extends SpringBootServletInitializer {
	
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(TestApplication.class);
    }

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

 

✔️3. war (gradle task) 실행

✏️ gradle task에서 war를 더블클릭 하면 build/libs 폴더 하위에 war 파일이 생성된다.

 

✔️4. WAR 배포 (외장 톰캣)

✏️ 설치한 tomcat 폴더에 webapps 하위에 war 파일을 넣고 ROOT.war로 파일명을 변경한다. 

별다른 path 설정을 하지 않기 위해 ROOT로 바꾼다. ROOT.war 가 배포되면서 ROOT 폴더가 생성되므로, 기존에 있던 ROOT폴더는 삭제한다.

 

✏️ 이제 아래와 같은 명령어를 통해 서비스를 시작할 수 있다.

해당톰캣 경로/bin/startup.sh

 

 

 


🥲Trouble Shooting

 

📌 톰캣 시작 후 404 에러 발생

 

위의 순서대로 모두 진행했는데도 404 에러가 발생했고 페이지는 뜨지 않았다.

다른 블로그 글들을 참고하여 server.xml의 context 도 변경해보았지만 소용없었다.

 

📌 원인 및 해결

혹시 버전의 문제인가 싶어서 하나씩 원인을 찾기 시작했다.

톰캣을 재시작 해봤더니, jre가 8버전인 것을 알게 됐다.

정확한 원인은 사실 모르겠지만 진행하고 있는 프로젝트의 java 버전이 11인데 톰캣의 jdk 버전이 8이라 생긴 문제였다.

톰캣 시작 시 로그

 

그래서 톰캣경로/bin/catalina.sh 를 아래와 같이 수정하여 톰캣이 바라보고 있는 자바의 버전을 변경해주었다.

아래의 경로는 예시일 뿐, 변경하고자 하는 jdk 의 경로로 설정해주면 된다.

(*참고로 저 경로 하위에는 bin/ conf/ lib/ 등의 폴더가 존재함.)

#catalina.sh 파일
JAVA_HOME=이 부분에 해당 jdk 경로

 

 

📌톰캣 재시작 후에는 설정한 버전으로 잘 시작되었고, 404 페이지 문제도 해결 완료했다!

 

댓글