톰캣 WAR 배포 3단계: 만들기·넣기·켜기는 다른 일이었다

톰캣에 WAR 배포하는 법. mvn package는 만들기까지고 webapps 복사와 톰캣 실행은 별개다. WEB-INF가 뭔지, provided 의존성이 왜 WAR에 안 들어가는지까지.

조회
목차

서블릿 하나를 브라우저에서 확인하는 단계. 코드는 다 썼고 띄우기만 남았다.

프론트에서는 pnpm dev 하나면 됐는데, 자바는 아니었다.

mvn package 하면 뜨는 줄 알았다

세 개가 다 다른 일이었다.

명령하는 일
mvn packageWAR 만들기 (target/board.war)
cp ... webapps/톰캣에 넣기
catalina run톰캣 켜기

mvn package는 만들기까지다. 만든 WAR이 톰캣 폴더로 안 가면 아무 일도 안 일어난다.

그리고 파일을 고칠 때마다 mvn package를 다시 해야 한다. WAR은 그 시점의 복사본이라 원본을 고쳐도 WAR 안은 안 바뀐다.

WAR이 어디 있는지 몰랐다

target/ 안이다. Maven이 만드는 결과물 폴더고, 프론트의 dist.next 자리다. 소스가 아니라 만들어진 거라 .gitignore에 넣는다.

target/
├── board.war        묶인 파일
├── board/           같은 내용을 폴더로 풀어놓은 것
└── classes/         컴파일된 .class

WAR은 배포용으로 묶은 압축 파일이다. 톰캣 webapps에 넣으면 톰캣이 알아서 풀고 같은 이름 폴더가 생긴다.

개발할 때는 보통 압축하지 않는다. 폴더 그대로 두고 톰캣이 그 폴더를 바로 읽게 한다. 매번 압축하고 푸는 게 느려서다. 압축이든 폴더든 안쪽 구조는 같다.

WEB-INF가 뭘 하는 폴더인지 몰랐다

"WAR로 묶이는 것들을 관리하는 폴더"라고 생각했는데 아니었다. WAR 안에 들어가는 건 WEB-INF 밖에도 있다.

기준은 하나다. 브라우저가 직접 열 수 있느냐.

myapp/                 ← 이게 통째로 WAR가 된다
├── index.html         주소로 바로 열 수 있다
├── css/, js/, img/    열 수 있다
└── WEB-INF/           ← 브라우저가 못 연다. 서버만 본다
    ├── web.xml
    ├── classes/       내 자바 클래스
    └── lib/           라이브러리

WEB-INF 안의 파일은 주소를 직접 쳐도 안 열린다. 톰캣이 막는다. 그래서 자바 클래스와 설정 파일을 여기 둔다 — 소스가 노출되면 안 되니까.

여기서 이어지는 게 JSP 위치다. JSP를 WEB-INF 밖에 두면 사용자가 주소로 직접 열 수 있다. 안에 두면 반드시 서블릿을 거쳐야 한다. "서블릿이 받고 JSP가 그린다"는 규칙을 지키려면 안에 둬야 한다.

WEB-INF/lib이 비어 있어서 이상했다

pom.xml에 라이브러리를 두 개 넣었는데 WAR 안에는 lib 폴더가 아예 없었다. provided 때문이었다.

톰캣이 이미 서블릿 API를 갖고 있다.

/opt/homebrew/opt/tomcat@9/libexec/lib/servlet-api.jar

provided는 **"컴파일할 때만 쓰고 WAR에는 넣지 마"**라는 뜻이다. 안 그러면 내 WAR에도 같은 게 들어가서 톰캣 것과 두 개가 되고 충돌한다.

내 코드 에러인 줄 알았던 게 남의 앱 응답이었다

브라우저에 이게 떴다.

{"code":"INTERNAL_ERROR","message":"서버 오류가 발생했습니다."}

톰캣 에러가 아니었다. 톰캣은 HTML 에러 페이지를 준다. 저건 JSON에 한글 메시지다.

8080을 다른 앱(내 다른 프로젝트)이 잡고 있었고, 톰캣은 아예 못 떴다. 브라우저 요청이 그 앱한테 갔고, 그 앱이 준 500이었다.

포트 충돌일 때 톰캣 로그에 나오는 줄은 이거다.

Address already in use

톰캣 포트를 8081로 바꿨다. 8080은 자바 진영 기본 포트라 계속 부딪힌다.

남길 것

  • pnpm dev 하나로 되던 게 자바에서는 세 단계다. 만들기·넣기·켜기. 나중에 IDE가 자동으로 해주는데, 한 번 손으로 해봐야 뭘 대신해주는지 안다.
  • 에러 응답을 보면 누가 답했는지 알 수 있다. 내 서버가 안 떴는데 다른 서버가 대신 답할 수 있다.
  • WEB-INF는 "브라우저가 못 여는 방"이다. 이 한 문장이면 왜 클래스와 설정이 거기 있는지, 왜 JSP를 거기 넣는지가 다 풀린다.
  • 의존성을 넣는다고 다 WAR에 들어가는 게 아니다. 서버가 이미 가진 건 빼야 한다.
  • 포트는 미리 비켜두는 게 싸다. 8080은 자바에서 계속 겹친다.

더 봐야 할 것

  • IDE에 톰캣을 붙이면 이 세 단계가 어떻게 하나로 합쳐지나
  • autoDeploy가 실패하는 경우가 있는지, 어떨 때 재시작이 필요한지

사이트 내 검색

제목·태그·설명·본문으로 발행 글을 찾습니다