질문, 피드백 등 모든 댓글 환영합니다.
Heroku를 이용하여 프로젝트를 배포하겠습니다. Heroku는 배포가 쉬운 편이며 서버와 db를 일정 범위 내에서 무료로 제공합니다. 단순한 프로젝트를 제작하며 공부하는 우리들에겐 괜찮은 선택일 수 있습니다. 대신 속도가 느립니다...
(수정 : Heroku는 free dyno
서비스를 2022년 11월 28일부로 종료했습니다. 대신 저비용 서비스인 eco dyno
를 출시했습니다. 프로젝트 배포 과정은 거의 비슷하며 차이점과 eco dyno
를 등록하고 free dyno
에서 전환하는 내용은 블로그 참고해 주세요.)
jar를 배포하기 전에 추가 설정이 필요합니다.
system.properties
프로젝트 root에 system.properties 생성해줍니다. heroku의 자바는 기본 8버전으로 설정되어 있으므로 11로 지정해주어야 합니다.
java.runtime.version=11
추가해줍니다.
Procfile
프로젝트 root에 확장자 없이 Procfile을 생성합니다. (Profile이 아니라 Procfile입니다!)
Procfile에서 jar의 위치를 지정해주겠습니다.(원래 위치는 gitignore로 처리되어 있음)
web: java -Dserver.port=$PORT $JAVA_OPTS -jar target/todo-0.0.1-SNAPSHOT.jar
build.gradle
jar의 생성 위치를 변경해 줍니다. 맨 아래에 추가해주겠습니다.
bootJar {
destinationDirectory = file("./target")
}
git.ignore
heroku에서 gradle/wrapper을 참조해야 하므로 gitignore에서 제외시켜줍니다.
jar 파일 생성
터미널에서 ./gradlew bootjar
입력하여 jar파일 생성
H2 -> MySQL
h2는 heroku에서 사용할 수 없으므로 heroku 에서 지원하는 db인 MySQL로 바꿔주겠습니다.
build.gradle에서 H2 -> MySQL로 바꿔줍니다.
dependencies {
runtimeOnly 'mysql:mysql-connector-java'
// runtimeOnly 'com.h2database:h2'
}
이제 heroku 사이트에서 MySQL을 연동해주어야 합니다. (회원가입과 app 추가, 깃 연동 등 heroku 설정은 생략하겠습니다. 위 블로그를 참조해주세요.)
Resources -> find more add-ons -> JawsDB MySQL
연동 과정은 간단하니 생략하겠습니다. 위 블로그 참고해 주세요. 연동이 완료되면 Resources에서 JawsDB MySQL을 클릭하여 DB연동 정보를 확인합니다.
이를 기반으로 application.yml을 수정해주겠습니다.
application.yml
spring:
datasource:
url: jdbc:mysql://username:password@host......
username: username
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
적절하게 db 정보를 추가해줍니다. (url 앞에 jdbc:를 추가해주세요)
ddl을 none으로 설정 뒤 MySQL에서 직접 테이블을 생성해줍니다.
jar 생성
이제 모든 사전 작업이 끝났으니 터미널에 ./gradlew bootjar
를 입력해 jar를 생성해줍니다.
그리고 heroku에 연결할 git repository에 모든 변경사항을 push 합니다.
우리가 작성한 application.yml에 db 접속 정보가 그대로 노출돼있기 때문에 public이 아닌 private 리포지토리에 업로드 해주셔야 합니다. (사실 private 리포지토리가 연동 되는 줄 모르고 application.yml 파일을 깃에 암호화에서 업로드하는 방법을 몇 시간 동안 찾아본....)
배포
heroku에서 git을 연동하고 Deploy -> Manual deploy에서 deploy를 해주면 배포가 완료 됩니다.
배포 후 해당 url로 접속하니 첫 화면은 잘 나와서 배포가 잘 된 줄 알았으나...
/login 으로 접속하니 500 error 가 발생했습니다.. heroku 로그를 살펴보니 아래와 같았습니다.
2022-10-11 16:37:24.627 ERROR 4 --- [io-17757-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/login/form], template might not exist or might not be accessible by any of the configured Template Resolvers] with root cause
로컬에서는 문제가 없었지만 배포 시에 문제가 발생했습니다.
설마 Thymeleaf를 사용하려면 heroku에서 추가로 설정이 필요한가 생각이 들어 관련 부분을 검색했고 블로그에서 답을 찾았습니다.
정리하자면 스프링(타임리프)의 디폴트 경로가 templates/
이므로 컨트롤러에서 "/login/form"
을 반환하면 templates//login/form"
경로로 연결되므로 오류가 발생하고 로컬에서는 이를 IntelliJ가 잡아서 오류가 발생하지 않았던 것입니다.
때문에 모든 컨트롤러의 반환값을 수정하고 다시 배포하니 정상적으로 동작하였습니다.
블로그로 작성하니 배포에 큰 힘을 들이지 않은 것 같지만 실은 좌충우돌 그 자체였습니다...
사실 배포까지 하는 건 계획에 없던 일이지만 이왕 프로젝트 시작한 김에 끝까지 해보자는 생각이 들었습니다. 조잡하지만 배포까지 끝내고 나니 뿌듯함이 느껴졌습니다.
다음 시간엔 마지막으로 프로젝트를 되돌아 보며 마무리짓도록 하겠습니다.