Springboot로 디자인이 하나도 없고 매우 간단한 게시판을 구현하는 시리즈입니다.

최종 소스는 깃헙에서 확인하실 수 있습니다.


이 글에서는 "Hello World!" 페이지를 응답하는 매우 간단한 애플리케이션을 배포해서 기본적인 방법을 익힌 다음,

지금까지 구현한 게시판 애플리케이션을 배포하는 방법에 대해 알아보도록 하겠습니다.






1. Hello World 애플리케이션 배포하기

지금까지 구현한 게시판 애플리케이션을 배포하지 않고, 왜 번거롭게 새로운 애플리케이션을 만들어서 배포해야 하는지 궁금하실 수 있을 것 같습니다.

게시판 애플리케이션을 배포하는 과정에서 여러 에러들이 발생하는데, 나중에 새로운 다른 애플리케이션을 배포할 때 발생하는 에러들은 게시판 애플리케이션을 배포할 때 발생한 에러들과 독립적인 에러라는 것을 강조하고 싶어서입니다.

즉, 배포시 발생하는 에러들은 애플리케이션 환경마다 다르기 때문에 통용되는 해결책을 제공할 수가 없습니다.

그래서 Hello World 애플리케이션을 배포함으로써, 통용되는 방법을 먼저 소개해드리고자 합니다.



1) 애플리케이션 준비 작업

구현하기

먼저, "Hello World" 페이지를 응답할 수 있도록 컨트롤러와 HTML 파일을 후딱 만들도록 합니다. ( Hello World 애플리케이션 - 참고 )


Github에 Push

Hello World 애플리케이션을 깃헙에 푸시합니다. ( 깃헙 푸시 방법 - 참고 )





2) EC2 준비 작업

다음으로 AWS EC2 인스턴스를 생성해야 합니다.

EC2 인스턴스 생성 방법은 이글을 참고해주시기 바랍니다.

또한 EC2 인스턴스에 접근하기 위해서는 터미널 툴을 사용해야 하는데, 그 방법은 이글을 참고하시길 바랍니다.


처음 EC2를 접해보셨다면, 터미널로 EC2를 접근하기까지 꽤 많은 시간이 걸렸으리라 생각됩니다.

여기까지 왔다면 Hello World 애플리케이션을 배포하기까지 70%는 끝났습니다 ^^





3) 배포하기 - 패키지 설치

애플리케이션을 배포할 때 필요한 패키지들을 설치합니다.

1] git 설치

[ec2-user@ip-172-31-40-7 ~]$ sudo yum install -y git

[ec2-user@ip-172-31-40-7 ~]$ git --version git version 2.23.1



2] java 설치

[ec2-user@ip-172-31-40-7 ~]$ sudo amazon-linux-extras install java-openjdk11

[ec2-user@ip-172-31-40-7 ~]$ java -version openjdk version "11.0.5" 2019-10-15 LTS OpenJDK Runtime Environment 18.9 (build 11.0.5+10-LTS) OpenJDK 64-Bit Server VM 18.9 (build 11.0.5+10-LTS, mixed mode, sharing)


*** 참고 ***

java 설치는 $ sudo yum -y install java-11-openjdk java-11-openjdk-devel 명령어로 설치하려 했으나, 아래의 경고창이 뜨면서 가이드를 제공합니다.

여기서는 그 가이드를 따라서 진행한 것입니다.

[ec2-user@ip-172-31-40-7 ~]$ sudo yum -y install java-11-openjdk java-11-openjdk-devel ... To use, run # sudo amazon-linux-extras install java-openjdk11





4) 배포하기 - git clone

다음으로 깃헙에 올라가 있는 Hello World 애플리케이션 소스를 EC2 인스턴스로 clone 합니다.

clone 주소는 아래의 사진에서 확인하실 수 있습니다.

( 해당 저장소는 삭제될 예정이므로, 각자의 저장소를 사용하시길 바랍니다. )



[ec2-user@ip-172-31-40-7 ~]$ mkdir apps [ec2-user@ip-172-31-40-7 ~]$ cd apps/ [ec2-user@ip-172-31-40-7 apps]$ git clone https://github.com/victolee93/demo.git Cloning into 'demo'... remote: Enumerating objects: 27, done. remote: Counting objects: 100% (27/27), done. remote: Compressing objects: 100% (17/17), done. remote: Total 27 (delta 0), reused 27 (delta 0), pack-reused 0 Unpacking objects: 100% (27/27), done.


[ec2-user@ip-172-31-40-7 apps]$ cd demo/ [ec2-user@ip-172-31-40-7 demo]$ ll total 20 -rw-rw-r-- 1 ec2-user ec2-user 543 Feb 21 05:04 build.gradle drwxrwxr-x 3 ec2-user ec2-user 21 Feb 21 05:04 gradle -rw-rw-r-- 1 ec2-user ec2-user 5296 Feb 21 05:04 gradlew -rw-rw-r-- 1 ec2-user ec2-user 2176 Feb 21 05:04 gradlew.bat -rw-rw-r-- 1 ec2-user ec2-user 26 Feb 21 05:04 settings.gradle drwxrwxr-x 4 ec2-user ec2-user 30 Feb 21 05:04 src





5) 배포하기 - 빌드

다음으로 프로젝트를 빌드해줍니다.

그 전에 빌드하기 위해서는 실행권한이 있어야 하므로, 권한을 수정해주도록 합니다.

[ec2-user@ip-172-31-40-7 demo]$ sudo chmod 777 ./gradlew [ec2-user@ip-172-31-40-7 demo]$ ll ./gradlew -rwxrwxrwx 1 ec2-user ec2-user 5296 Feb 21 05:04 ./gradlew [ec2-user@ip-172-31-40-7 demo]$ ./gradlew build Downloading https://services.gradle.org/distributions/gradle-6.0.1-bin.zip .......................................................................................... Welcome to Gradle 6.0.1! ... Starting a Gradle Daemon (subsequent builds will be faster) ... BUILD SUCCESSFUL in 2m 17s 5 actionable tasks: 5 executed



[ec2-user@ip-172-31-40-7 demo]$ cd build/libs/

[ec2-user@ip-172-31-40-7 libs]$ ll

total 17144

-rw-rw-r-- 1 ec2-user ec2-user 17553666 Feb 21 05:14 demo-0.0.1-SNAPSHOT.jar

이렇게 빌드가 성공하면 build 디렉토리가 생성되고, build/libs 디렉토리 아래에 jar 파일이 생성됩니다.





6) 배포하기 - 서버 실행

SpringBoot는 톰캣 서버가 내장되어있으므로, 빌드된 파일(jar)만 실행해주면 서버가 가동됩니다.
[ec2-user@ip-172-31-40-7 libs]$ java -jar demo-0.0.1-SNAPSHOT.jar





7) 배포하기 - 인바운드 규칙 설정

마지막으로 EC2 인스턴스 인바운드 규칙에 8080포트가 설정되어 있어야 합니다.


애플리케이션 앞 단에 웹서버가 존재한다면 80포트를 그대로 두고 웹 서버에서 설정을 통해 처리하면 되지만,

지금은 웹서버 없이 바로 애플리케이션에 접근하는 것이므로 인바운드 규칙이 필요합니다.

( iptables를 활용하여 포트포워딩을 해도 무방합니다. )


인바운드 규칙을 추가하는 방법은 다음과 같습니다.





8) 테스트

이제 브라우저에서 접근하여 Hello World가 잘 출력되는지 확인합니다.

도메인은 EC2 인스턴스의 IPv4 퍼블릭 IP를 그대로 입력합니다.




이렇게 EC2에 애플리케이션을 배포하여 외부에서도 접근할 수 있게 되었습니다.

이제 지금까지 구현한 게시판 애플리케이션을 배포하면서, 발생하는 이슈들을 어떻게 처리해야 하는지 알아보도록 하겠습니다.







2. 게시판 애플리케이션 배포하기


1) git clone

먼저 게시판 애플리케이션 소스를 clone합니다. ( 깃헙링크 )

[ec2-user@ip-172-31-40-7 ~]$ cd /home/ec2-user/apps/ [ec2-user@ip-172-31-40-7 apps]$ git clone https://github.com/victolee93/Springboot-boardCRUD.git

[ec2-user@ip-172-31-40-7 apps]$ cd Springboot-boardCRUD/



2) build 실패 (1)

다음으로 빌드를 해봅니다.

[ec2-user@ip-172-31-40-7 Springboot-boardCRUD]$ sudo chmod 777 ./gradlew [ec2-user@ip-172-31-40-7 Springboot-boardCRUD]$ ./gradlew build


위와 같이 JDBCConnectionException이 발생하고 빌드에 실패했다면 예상된 오류이므로 괜찮습니다.


*** 참고 ***

DaemonConnectionException이 발생하여 빌드에 실패했을 경우, build 디렉토리를 지워줍니다.

$ ./gradlew clean




3) build 실패 (1) - DB 연결 :: RDS 생성 및 연결정보 수정

위에서 빌드가 실패한 이유는 JDBCConnectionException 이름에서 알 수 있듯이 DB 커넥션이 안되었기 때문입니다.

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/board?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 1234

기존의 application.yml에 작성한 datasource의 DB 커넥션 정보가 localhost로 되어 있는데요.

EC2의 local에서 mysql 접근이 안되고 있어서 에러가 발생한 것입니다.


그래서 mysql에 접근이 가능하도록 해야하느데, EC2에 내부에 DB가 존재하는 구조는 좋지 못하므로 AWS RDS 서비스를 사용하려 합니다.

RDS 인스턴스를 생성하는 방법은 이글을 참고해주세요.



RDS 인스턴스가 생성되었으면, application.yml 파일의 datasource를 수정합니다.

이 때, EC2에서 직접 수정하는 것이 아니라 개발 환경(IDE)에서 수정해서 깃헙(remote repository)에 push 후, EC2 인스턴스에서 pull 하는 방식이 바람직합니다.

배포 서버에서 코드를 수정하는 행위는 절대 하지 말아야 한다고 생각하는 것이 좋습니다.

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://{RDS 인스턴스 엔드포인트}:3306/board?serverTimezone=UTC&characterEncoding=UTF-8
username: {마스터 사용자 이름}
password: {마스터 암호}

마스터 사용자이름과 암호는 RDS 인스턴스를 생성했을 때의 값을 입력해주면 됩니다.





4) build 실패 (1) - git ignore


application.yml 파일은 꼭 .gitignore가 되어야 합니다.

해당 파일에 DB 연결정보가 포함되어 있으므로, 꼭 gitignore 해줘야 합니다. ( 참고 )


.gitignore

### my ignore ###
src/main/resources/application.yml

application.yml 파일을 수정했으므로 깃헙에 다시 push를 해줘야 하는데, gitignore 때문에 push 할게 없을겁니다.
형상관리가 필요한 다른 파일을 수정 했더라면 push 후, EC2에서 소스코드를 다시 pull을 해야하지만,

지금은 형상관리가 필요없는 파일이므로 직접 EC2에서도 수정해주도록 합니다.


아까는 EC2에서 직접 하지말라면서, 지금은 또 직접하라고 하니 헷갈릴 수 있는데요.

결론적으로는 아래의 내용을 강조하고 싶어서입니다.

  • 배포 서버에서는 코드를 수정하지 말자
  • apllication.yml 같은 주요 정보 파일은 gitignore를 하자




5) build 실패 (2)

RDS 인스턴스가 생성되었고 application.yml 파일을 수정했으면, 다시 빌드를 해보겠습니다.

[ec2-user@ip-172-31-40-7 Springboot-boardCRUD]$ ./gradlew build


이번에는 JDBCConnectionException 예외가 아닌, SQLSyntaxErrorException 예외가 발생했네요.





6) build 실패 (2) - database 생성

분명 배포하기 전에 개발 환경에서는 잘 돌았던 소스인데, 문법 에러라니...

그 이유는 application.yml 파일의 datasource.url에 board database에 접근하도록 작성해줬기 때문입니다. ( jdbc:mysql://{RDS 인스턴스 엔드포인트}:3306/board )


따라서 EC2에서 RDS 인스턴스에 접근한 후, database를 생성합니다.

$ mysql -u {마스터 사용자 이름} -p -h {RDS 인스턴스 엔드포인트}

> 비밀번호 입력



mysql> CREATE database board default character set UTF8;


*** 참고 ***

database를 생성할 때 character을 UTF-8로 명시해준 이유는 한글 데이터를 처리해주기 위함입니다.

그냥 database만 생성했다면, 게시판 글쓰기 과정에서 한글을 입력했을 때 에러가 발생합니다.

이러한 처리가 귀찮다면 RDS 파라미터 생성을 통해 해결할 수 있습니다.





7) build 성공 및 서버 실행

이제 다시 빌드를 해봅니다.

[ec2-user@ip-172-31-40-7 Springboot-boardCRUD]$ ./gradlew build


오.... 이번엔 잘 성공했네요.

이어서 서버까지 실행해보죠!

[ec2-user@ip-172-31-40-7 Springboot-boardCRUD]$ java -jar build/libs/board-0.0.1-SNAPSHOT.jar


애플리케이션이 잘 떳네요!

DB 접속이 필요한 애플리케이션이라고 해서 특별한 것은 없고, 커넥션을 잘 처리해주면 됩니다.




8) 테스트

서버에 접근을 해보면 아래와 같이 페이지가 잘 응답되는 것을 확인할 수 있습니다!!




게시글을 한글로 작성해도 정상 동작하는 것을 확인할 수 있습니다.





이상으로 EC2에 배포하는 방법에 대해 알아보았습니다.

IDE를 통해 개발했을 때와 달리, 이처럼 서버에 올려서 배포를 하게 되면 많은 에러들을 마주하게 됩니다.

개발 환경과 다르게 동작하는 경우도 있구요.

그렇기 때문에 localhost에서 개발하는 것도 좋지만, 꼭 배포까지 해보는 것이 좋습니다.


댓글 펼치기 👇
  1. Favicon of https://ryuuun.tistory.com 릴롱궤 2020.03.30 16:25 신고

    apllication.yml 파일을 배포서버에서 새로 만들라는 말인가요??
    저는 node.js 로 배포하려고 하는데 로컬서버에 있는 dotenv 파일을 배포서버에 똑같이 만들면 되는 건가요?

  2. ㅇㅇ 2020.06.23 00:08

    감사해요!!!!!!!♥

  3. Favicon of https://goodlife-coding.tistory.com southouse 2020.08.10 14:39 신고

    안녕하세요. 실습하던 도중 thymeleaf 템플릿에서 에러 발생하길래 찾아보니...

    'BoardController.java' 파일에서 게시글 작성하는 컨트롤러에서 43번 라인인 return "/board/write.html"; 에서 return "board/write.html"; 로 변경해주어야 에러 발생하지 않습니다.

    return 에서 절대경로 사용해서 발생하는 에러라고 하네요.

    출처 : https://smallgiant.tistory.com/67

  4. Favicon of https://ecsimsw.tistory.com JinHwan Kim 2020.11.01 13:47 신고

    스프링 부트, AWS 등 많은 부분에서 큰 도움을 받았습니다.
    정말 감사합니다.
    좋은 하루 되세요.

  5. 프로야근맨 2020.11.26 00:06

    회사에서 몇년간 마이바티스 프레임웤만 사용했어서 JPA에 호기심이 생겼었는데,
    공부를 하려고 구글링을 하는 와중에 너무 좋은 예제를 찾아서 감동입니다 ㅠ

    친절한 설명 감사드립니다.

    배포 작업 과정에서 아래 내용을 참고하면 좋을 것 같아 댓글 남깁니다.

    1. 파일 권한

    [AS-IS]
    sudo chmod 777 ./gradlew
    이렇게 실행권한을 주면 해당파일의 소유자, 해당파일의 그룹, 그외 사용자(os상의 사용자 계정을 의미합니다.)에게
    해당 파일에 대한 모든권한 (7 = 4(read / 읽기) 2(write / 쓰기(수정)) 1(execute / 실행))을 주게됩니다.

    [TO-BE]
    sudo chmod u+x ./gradlew
    이렇게 실행권한을 주면 해당 파일의 소유자 즉 ec2-user에게만 해당 파일의 실행권한만을 주게 됩니다.

    [참고 url]
    https://jins-dev.tistory.com/entry/Linux-퍼미션-코드에-대해서-미정리
    https://eunguru.tistory.com/93

    현업에서는 웹 어플리케이션이 배포되는 서버에 대한 보안 취약점 점검 등, 보안 이슈가 꽤 있기 때문에 파일 권한에 대해 조금 더 알고 가면 좋을 것 같습니다.

    2. 데이터 베이스 캐릭터 셋

    [AS-IS]
    CREATE database board default character set UTF8;

    [TO-BE]
    create database board default character set utf8mb4 collate utf8mb4_unicode_ci;

    이모지와 같은 4byte utf-8 문자열 이슈를 방지 할 수 있습니다..!

    회사 일을 하면서 좀 구축된지 오래된 환경(utf8mb4 로 세팅 하지 않고, utf-8로 세팅)에서 이모지 같은 문자열이 들어갔을 때, table에 insert 가 되지 않고 관련 에러가 발생한 적이 상당히 많았습니다..!

    [참고 url]
    https://blog.lael.be/post/917