본문 바로가기
Web Development/MicroService Architecture

[MSA / Spring Cloud / Docker / jsp] jsp 프로젝트를 Docker Container에 올리기(feat. war & jar)

by 감자맹고우 2023. 4. 24.
728x90
반응형

Spring Boot로 작성된 프로젝트를 JAR로 패키징하여 Docker 컨테이너로 올리는 것은 자료도 많고, 큰 막힘 없이 잘 된다.

 

그러나 레거시 환경으로 개발하던 팀에게, 기존 환경으로도 MSA 구성이 가능하다는 것을 보여주기 위해서는 thymeleaf같은 호환되는 템플릿 엔진이 아닌 기존의 jsp를 사용하는 프로젝트도 개발해서 연동해야했다. 그리고 Docker 까지 사용하게 되었으니 이 프로젝트도 도커 컨테이너로 올릴 수 있어야 했다. 이것이 큰 과제가 되었다.

 

- 실패 경험 -

 

일단 진행하면서 가장 처음으로 만난 문제는, Spring Boot가 기본적으로 jsp를 지양한다는 문제이다. 그렇기 때문에 별도 설정을 통해 프로젝트에 jsp 경로를 지정해주어야만 jsp를 사용할 수 있다.

 

spring:
  application:
    name: test-service
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp

 

두 번째로 만난 문제는 패키징이다. Spring Boot는 주로 JAR로 패키징을 하고 JAR에는 내장형 톰캣이 포함되며, jsp는 포함되지 않는다. 그러나 이 문제도 META-INF 등 여러 가지 우회 방법을 통해 jsp파일이 JAR 파일에 포함되도록 패키징을 할 수는 있다.

 

그럼 이제 마지막으로 만난 문제는 무엇일까? 바로 내장형 톰캣이 패키징에 포함된 jsp를 인식하지 못한다는 것이다. 이를 해결하기 위해 갖은 시도를 해보았지만, 결론을 내리게 된 내용은 JAR 패키징으로는 jsp 인식이 불가능하다는 것이었다.

 

그럼 이제 WAR로 패키징을 해서 목적을 달성해야 한다. 목적 달성이야 레거시 환경에서 배포하듯 처리하면 되니 어려운 과정은 아니겠지만, 도커에 올린다고 생각하니 'JAR처럼 내장형 톰캣으로 WAR 파일을 읽는 방법이 있지 않을까'라는 생각이 들었다.

그래서 나는 JAR를 조사할 때처럼 WAR로만 패키징해서 톰캣이 인식하도록 해보려고 했고, 팀원은 자료를 수집했다.

그래서 나온 결과는 bootWar였다. bootWar를 이용하면 내장형 톰캣으로 WAR를 읽을 수 있다. JAR를 도커에 올릴 때처럼 처리가 가능한 것이다. 그러나... Maven 환경에서는 bootWar를 사용할 수 없었다. bootWar는 Gradle에서만 제공하는 기능이었기 때문이다.

 

결국 최종으로 도달한 결과는, 외부 톰캣에 WAR를 배포해서 실행하는 방법 뿐이었다.

이제 그 방법으로 Docker에 jsp가 포함된 WAR 파일을 도커 컨테이너에 띄우는 법을 알아보자.

 

 

[ 해결 방법 ]

 

일단, Dockerfile이 익숙하지 않은 상태이기 때문에, 어떻게 Tomcat을 가진 도커 컨테이너를 띄울까 생각했다. 생각하다보니 From으로 openjdk 도커 이미지를 받아왔었는데, 거기에 tomcat 이미지를 받아오면 될 것 같다는 생각이 들었다.

그래서 도커 허브에서 tomcat을 검색했고, tomcat 태그에서 팀에서 사용하는 버전인 10.1.5를 검색해서 tomcat:10.1.5를 찾았고 jdk가 적혀있는 태그가 있길래 tomcat:10.1.5-jdk17을 선택하여 Dockerfile을 작성하기로 했다.

 

일단 최종으로 작성한 Dockerfile 내용은 아래와 같다.

 

FROM tomcat:10.1.5-jdk17
WORKDIR /usr/local/tomcat
COPY target/test-service-1.0.war webapps/test-service.war

# Update server.xml - Change port to 1000
RUN sed -i 's|port="8080"|port="1000"|' conf/server.xml

# Update server.xml - Add Context inside Host
RUN sed -i 's|<Host name="localhost"  appBase="webapps"|<Host name="localhost"  appBase=""|' conf/server.xml
RUN sed -i 's|unpackWARs="true" autoDeploy="true">|unpackWARs="true" autoDeploy="true">\n        <Context docBase="webapps/test-service" path="/" reloadable="true" />|' conf/server.xml

 

반응형

 

Line1. tomcat 이미지를 사용하여 도커 이미지를 만들 것이다
Line2. 작업 디렉토리를 톰캣이 설치된 /usr/local/tomcat으로 설정
Line3. 현재 프로젝트의 target 폴더에 있는 test-service-1.0.war 파일을 컨테이너의 webapps폴더 내에 test-service.war로 복사
Line6. conf 폴더의 server.xml 파일에서 port="8080"을 port="1000" 으로 변경
Line9, 10. ※ 경로를 기본 URL(/)로 바로 연결될 수 있도록 설정 ※ 하는 내용으로 server.xml 파일 수정

(# Update server.xml - Add Context inside Host 부분의 두 가지 RUN을 한번에 처리하려면 공백 처리를 잘 인식하지 못하는 문제로 수정이 안됩니다.)

 

이렇게 Docker file을 작성하면 되는데 jsp를 읽기 위해서는 추가 코드 작성이 필요하다.

바로 SpringApplicationBuilder 작성이다. 이를 작성해야만 읽을 수 있다.

 

@SpringBootApplication
@EnableDiscoveryClient
public class TestServiceApplication extends SpringBootServletInitializer {
	
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		return builder.sources(TestServiceApplication.class);
	}
	
	public static void main(String[] args) {
		SpringApplication.run(TestServiceApplication.class, args);
	}

}

 

이제 프로젝트를 build, docker build, docker push까지 해서 실행시키면 해당 컨테이너의 tomcat이 실행되면서 webapps 폴더의 war를 읽어 실행한다. 정상 실행되면 localhost:1000을 통해 페이지 출력을 확인할 수 있다.

 

그러나 아직 끝나지 않았다!

discovery service와의 연동이 남았다.

 

만약 랜덤포트로 지정했다면, WAR 의 경우에는 지정포트로 변경해야한다. 갖은 수를 써서 호스트만 랜덤포트로 지정해보기도 하고, 설정을 여러가지 바꾸어보기도 했지만 호스트 포트와 컨테이너 포트를 모두 지정포트로 바꾸기 전까지는 모두 실패했다. 모두 지정 포트로 설정하니 정상 동작하는데, 아무래도 WAR로는 랜덤포트로 도커 컨테이너를 올려 discovery service와 연동하는 것이 불가능한 것 같다.

 

아무튼 이제 discovery service와 연동이 잘 되었는지, tomcat이 잘 실행되어 war 파일을 잘 읽고 프로젝트가 잘 실행되었는지 각각의 콘솔에서 확인해보자. 문제가 없다면 정상적으로 도커 컨테이너가 동작하는 것이다!

 

🤞 도움이 되셨기를 바랍니다. 한 번의 클릭과 댓글은 어딘가의 누군가에게 진실로 큰 힘이 됩니다. 🐱‍🏍

 

728x90
반응형

댓글