티스토리 뷰

728x90

<목차>

     

    작업한 Spring Boot 프로젝트를 AWS EC2에 배포하는 과정을 작성하였다. Django를 배포했을 때보다는 과정이 덜 복잡한 것 같다.

     

    AWS에서 EC2 인스턴스 생성 과정은 이전에 Django를 배포하였을 때와 동일하게 진행하였다. 

     

    🍑 EC2 환경 셋팅

    git 설치

    $ sudo apt-get install -y git
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    git is already the newest version (1:2.17.1-1ubuntu0.9).
    git set to manually installed.
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    EC2에는 기본적으로 git이 설치되어 있다.

     

    Java 설치 (version 11)

    $ sudo apt-get install openjdk-11-jdk

     

    🍑 Spring Boot 프로젝트 다운로드

    배포용 브랜치(deploy) 생성

    deploy 브랜치 프로젝트 clone

    $ git clone -b deploy https://github.com/RIANAEH/project-mnm-main-server.git

    프로젝트 디렉터리로 이동 후, gradle에 실행 권한 부여

    ~$ cd project-mnm-main-server/
    ~/project-mnm-main-server$ sudo chmod 777 ./gradlew

     

    🍑 Spring Boot 프로젝트 Build

    build

    ~/project-mnm-main-server$ ./gradlew build

    build error #1

    > Task :compileTestJava FAILED
    /home/ubuntu/project-mnm-main-server/src/test/java/com/project/mnm/repository/UserServiceTest.java:26: error: cannot find symbol
            userService.joinUser(user);
                       ^
      symbol:   method joinUser(User)
      location: variable userService of type UserService
    1 error
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':compileTestJava'.
    > Compilation failed; see the compiler error output for details.
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 2m 25s
    6 actionable tasks: 6 executed

     

    기존에 프로젝트의 변경된 내용이 적용되어 있지 않아 이를 다시 수정 후 pull

    ~/project-mnm-main-server$ git pull origin deploy

    다시 bulid

    ~/project-mnm-main-server$ ./gradlew build
    
    > Task :compileJava
    Note: Some input files use unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    
    BUILD SUCCESSFUL in 16s
    6 actionable tasks: 5 executed, 1 up-to-date

    build가 성공하면 build/libs 디렉터리에 빌드한 스프링 프로그램이 mnm-0.0.1-SNAPSHOT.jar 파일로 생성된다.

    ~/project-mnm-main-server$ cd build/libs/
    ~/project-mnm-main-server/build/libs$ ls
    mnm-0.0.1-SNAPSHOT-plain.jar  mnm-0.0.1-SNAPSHOT.jar

    해당 파일의 이름은 gradle 파일에서 설정할 수 있다. 

    // build.gradle
    version = '0.0.1-SNAPSHOT'

     

    🍑 Spring Boot 프로젝트 실행

    run

    ~/project-mnm-main-server/build/libs$ java -jar mnm-0.0.1-SNAPSHOT.jar

    run error #1 ❌ 

    Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
    2021-11-23 14:43:24.276 ERROR 20383 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 
    
    ***************************
    APPLICATION FAILED TO START
    ***************************
    
    Description:
    
    Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
    
    Reason: Failed to determine a suitable driver class
    
    
    Action:
    
    Consider the following:
            If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
            If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

    ref : Spring Boot 최초 실행 시 'Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. ' :: From Novice To Guru (tistory.com)

     

    프로젝트 배포 시 application.properties를 제거하고 배포해야해서 이를 .gitignore에 설정해주고 잊고 있었다. 

    application.properties 파일 추가 후 다시 build

    ~/project-mnm-main-server$ ./gradlew build

    인바운드 규칙 편집

    8080포트와 5050포트를 사용하므로 이를 인바운드 규칙에 추가해주어야한다.  

    📌 인바운드 규칙 변경 후 vscode에서 ssh 연결 에러가 나서 어렵사리 해결했다.

    [트러블슈팅] VSCode SSH 연결 실패 해결 (Setting up SSH Host Initializing VSCode Server) (tistory.com)

     

    [트러블슈팅] VSCode SSH 연결 실패 해결 (Setting up SSH Host Initializing VSCode Server)

    연결이 잘 되다가 VSCode를 종료시켰다가 나중에 다시 같은 서버로 SSH 요청을 수행하였을 때 다음과 같이 에러가 나거나 계속 연결 요청만 들어가고 연결 완료가 안 될 때가 있다. 나는 다음과 같

    programmer-ririhan.tistory.com

    다시 run

    ~/project-mnm-main-server$ cd build/libs/
    ~/project-mnm-main-server/build/libs$ java -jar mnm-0.0.1-SNAPSHOT.jar

    run error #2 ❌ 

    Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
    2021-11-23 15:32:19.156 ERROR 1503 --- [           main] o.s.boot.SpringApplication               : Application run failed
    
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chattingService': Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [com.project.mnm.service.ChattingService] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@1ed6993a]
            at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:289) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1302) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1219) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.12.jar!/:5.3.12]
            at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.12.jar!/:5.3.12]
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.12.jar!/:5.3.12]
            at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.6.jar!/:2.5.6]
            at com.project.mnm.MnmApplication.main(MnmApplication.java:10) ~[classes!/:na]
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
            at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
            at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
            at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[mnm-0.0.1-SNAPSHOT.jar:na]
            at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[mnm-0.0.1-SNAPSHOT.jar:na]
            at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[mnm-0.0.1-SNAPSHOT.jar:na]
            at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[mnm-0.0.1-SNAPSHOT.jar:na]
    Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.project.mnm.service.ChattingService] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@1ed6993a]
            at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481) ~[spring-core-5.3.12.jar!/:5.3.12]
            at org.springframework.util.ReflectionUtils.doWithLocalMethods(ReflectionUtils.java:321) ~[spring-core-5.3.12.jar!/:5.3.12]
            at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:267) ~[spring-beans-5.3.12.jar!/:5.3.12]
            ... 26 common frames omitted
    Caused by: java.lang.NoClassDefFoundError: org/json/simple/JSONObject
            at java.base/java.lang.Class.getDeclaredMethods0(Native Method) ~[na:na]
            at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3166) ~[na:na]
            at java.base/java.lang.Class.getDeclaredMethods(Class.java:2309) ~[na:na]
            at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463) ~[spring-core-5.3.12.jar!/:5.3.12]
            ... 28 common frames omitted
    Caused by: java.lang.ClassNotFoundException: org.json.simple.JSONObject
            at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) ~[na:na]
            at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) ~[na:na]
            at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[mnm-0.0.1-SNAPSHOT.jar:na]
            at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
            ... 32 common frames omitted

    org.json.simple.JSONObject library를 읽어오지 못해서 발생하는 에러

    보통 libs/ 디렉터리에 관련 라이브러리를 직접 추가하여 해결하는 것 같았다.

    ref : 코끼리를 냉장고에 넣는 방법 :: [JAVA] java에서 JSON 데이터 다루기. google의 json-simple 사용 방법 (tistory.com)

    하지만 생각해보니 굳이 JSONObject를 사용하지 않아도 Dto를 만들어 처리해주면 될 것 같아서 필요한 형태의 Dto를 새로 추가하여 JSONObject를 사용한 부분을 변경하였다.  

     

    프로젝트의 변경된 내용 pull

    ~/project-mnm-main-server$ git pull origin deploy

    다시 build 후 run

    run error #3 ❌ 

    http://3.35.26.150:5050/auth/login 요청 시 "java.lang.ClassNotFoundException: org.json.simple.JSONObject" 에러가 서버에 출력되었다.

    login 관련 Controller와 Service를 까보니 여기서도 JSONObject를 사용하고 있었다. 이 또한 Dto를 사용하는 방식으로 변경하였다. 

    프로젝트의 변경된 내용 pull, 다시 build 후 run

    다른 api도 요청을 테스트 해보았는데 모두 동작하였다.

     

    🍑 Spring Boot 프로젝트 백그라운드로 실행

    프로젝트 서버 백그라운드로 실행

    $ nohup java -jar project-mnm-main-server/build/libs/mnm-0.0.1-SNAPSHOT.jar &

    실행 종료

    ref : 쉽게 설명한 nohup 과 &(백그라운드) 명령어 사용법 (tistory.com)

    ps, jobs로 모두 실행중인 프로젝트 프로세스를 찾을 수 없었다. 따라서 일단 인스턴스를 재부팅하는 방식으로 프로젝트 서버를 종료시킨다.

     

    출력에 대한 설정을 해주지 않으면 기본적으로 nohup.out 파일에 서버 로그가 출력된다. (표준 출력과 표준에러가 모두 출력된다.)

    표준출력, 표준에러 출력 파일 설정

    표준출력(1) : mnm.out, 표준에러(2) : mnm.err

    ~$ mkdir log
    ~$ ls
    log  project-mnm-main-server
    
    $ nohup java -jar project-mnm-main-server/build/libs/mnm-0.0.1-SNAPSHOT.jar 1 > log/mnm.out 2 > log/mnm.err &

    확인해보니 mnm.err에 표준출력과 표준에러가 모두 출력되고 mnm.out에는 아무것도 출력되지 않았다. 생각해보니 nohup 명령어를 실행했을 때 다음과 같이 출력되었는데 내가 입력한 설정을 무시한다는 메시지였다. 

    ubuntu@ip-172-31-47-33:~$ nohup java -jar project-mnm-main-server/build/libs/mnm-0.0.1-SNAPSHOT.jar 1 > ./log/mnm.out 2 > ./log/mnm.err &
    [1] 2282
    ubuntu@ip-172-31-47-33:~$ nohup: ignoring input and redirecting stderr to stdout

    그래서 그냥 한 곳에 모두 출력하는 명령어로 바꾸어 실행하였다. 

    $ nohup java -jar project-mnm-main-server/build/libs/mnm-0.0.1-SNAPSHOT.jar > mnm.log 2>&1 &
    [1] 3060

    그리고 위의 출력에서 알 수 있듯이 내가 실행한 프로젝트 서버의 프로세스 ID가 2282임을 확인 할 수 있다. 이를 이용해 프로세스 종료 명령어를 수행해보았더니 프로세스가 잘 종료되었다. 참고하자.

    $ kill -9 2282
    [1]+  Killed                  nohup java -jar project-mnm-main-server/build/libs/mnm-0.0.1-SNAPSHOT.jar 1 2 > ./log/mnm.out > ./log/mnm.err

     


    Ref.

    [AWS] EC2: 배포하기 (spring boot) : 네이버 블로그 (naver.com)

     

    728x90
    댓글
    공지사항
    최근에 올라온 글