[AWS] EC2 서버에 프로젝트를 배포하기

Kaite.Kang·2023년 2월 23일
0
post-thumbnail

목표

  • AWS EC2에 스프링 부트 프로젝트를 배포한다.

1. EC2에 프로젝트 Clone 받기

깃허브에서 코드를 받아올 수 있게 EC2에 깃을 설치한다.
EC2로 접속해서 다음과 같이 명령어를 입력한다.

#리포지토리 확인
$ yum repolist
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
repo id                                     repo name                                      status
!amzn2-core/2/x86_64                        Amazon Linux 2 core repository                 29,823
amzn2extra-docker/2/x86_64                  Amazon Extras repo for docker                      79
amzn2extra-kernel-5.10/2/x86_64             Amazon Extras repo for kernel-5.10                245
repolist: 30,147

#git을 제공하는 패키지 검색
$ yum provides git |tail -5
git-2.39.1-1.amzn2.0.1.x86_64 : Fast Version Control System
Repo        : amzn2-core

#현재 시스템에 git이 설치되어 있는지 확인
$ rpm -qa|grep git
lm_sensors-libs-3.4.0-8.20160601gitf9185e5.amzn2.x86_64
crontabs-1.11-6.20121102git.amzn2.noarch
net-tools-2.0-0.22.20131004git.amzn2.0.2.x86_64
screen-4.1.0-0.27.20120314git3c2946.amzn2.x86_64
python-pillow-2.0.0-23.gitd1c6db8.amzn2.0.1.x86_64

#git 설치
$ sudo yum install git

...

Installed:
  git.x86_64 0:2.39.1-1.amzn2.0.1

Dependency Installed:
  git-core.x86_64 0:2.39.1-1.amzn2.0.1             git-core-doc.noarch 0:2.39.1-1.amzn2.0.1
  perl-Error.noarch 1:0.17020-2.amzn2              perl-Git.noarch 0:2.39.1-1.amzn2.0.1
  perl-TermReadKey.x86_64 0:2.30-20.amzn2.0.2

Complete!

#설치 후 git 버전확인
$ git --version
git version 2.39.1

git이 설치되면 git clone으로 프로젝트를 저장한다.

#프로젝트를 저장할 디렉터리 생성
$ mkdir -p ~/app/step1

$ ls -al ~/app/step1/
total 0
drwxrwxr-x 2 ec2-user ec2-user  6 Feb  7 15:44 .
drwxrwxr-x 3 ec2-user ec2-user 19 Feb  7 15:44 ..

$ cd ~/app/step1/
$ pwd
/home/ec2-user/app/step1

#github 웹페이지에서 https 주소를 복사해서 git clone을 진행
$ git clone https://github.com/KangJuHui/springboot2-webservice.git
Cloning into 'springboot2-webservice'...
remote: Enumerating objects: 912, done.
remote: Counting objects: 100% (912/912), done.
remote: Compressing objects: 100% (472/472), done.
remote: Total 912 (delta 291), reused 784 (delta 164), pack-reused 0
Receiving objects: 100% (912/912), 360.20 KiB | 2.08 MiB/s, done.
Resolving deltas: 100% (291/291), done.

#프로젝트들이 잘 복사되었는지 확인
$ ls
springboot2-webservice

$ cd springboot2-webservice/

$ ll
total 20
drwxrwxr-x 7 ec2-user ec2-user   84 Feb  7 15:46 build
-rw-rw-r-- 1 ec2-user ec2-user 1474 Feb  7 15:46 build.gradle
drwxrwxr-x 3 ec2-user ec2-user   21 Feb  7 15:46 gradle
-rwxrwxr-x 1 ec2-user ec2-user 5774 Feb  7 15:46 gradlew
-rw-rw-r-- 1 ec2-user ec2-user 2674 Feb  7 15:46 gradlew.bat
drwxrwxr-x 4 ec2-user ec2-user   36 Feb  7 15:46 out
-rw-rw-r-- 1 ec2-user ec2-user   45 Feb  7 15:46 settings.gradle
drwxrwxr-x 4 ec2-user ec2-user   30 Feb  7 15:46 src

#코드들이 잘 수행되는지 테스트로 검증
$ ./gradlew test
Downloading https://services.gradle.org/distributions/gradle-7.2-bin.zip
..........10%...........20%...........30%...........40%...........50%...........60%...........70%...........80%...........90%...........100%

Welcome to Gradle 7.2!

Here are the highlights of this release:
 - Toolchain support for Scala
 - More cache hits when Java source files have platform-specific line endings
 - More resilient remote HTTP build cache behavior

For more details see https://docs.gradle.org/7.2/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :compileJava
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

> Task :test
2023-02-07 15:50:10.958  INFO 27379 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2023-02-07 15:50:10.960  INFO 27379 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
Hibernate: drop table if exists posts
2023-02-07 15:50:10.966  WARN 27379 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 90121, SQLState: 90121
2023-02-07 15:50:10.966 ERROR 27379 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper   : Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
2023-02-07 15:50:10.967  WARN 27379 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 90121, SQLState: 90121
2023-02-07 15:50:10.973 ERROR 27379 --- [ionShutdownHook] o.h.engine.jdbc.spi.SqlExceptionHelper   : Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
2023-02-07 15:50:10.974  WARN 27379 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter    : Invocation of destroy method failed on bean with name 'entityManagerFactory': org.hibernate.exception.JDBCConnectionException: Unable to release JDBC Connection used for DDL execution
2023-02-07 15:50:10.975  INFO 27379 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2023-02-07 15:50:10.991  INFO 27379 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

BUILD SUCCESSFUL in 2m 47s
5 actionable tasks: 5 executed

2. 배포 스크립트 만들기

배포는 작성한 코드를 실제 서버에 반영하는 것이다.
배포 절차를 스크립트로 작성해서 진행할 것이다.
스크립트는 아래 과정을 통해 배포를 진행한다.

  • git clone 혹은 git pull을 통해 새 버전의 프로젝트를 받음.
  • Gradle이나 Mave을 통해 프로젝트 테스트와 빌드
  • EC2 서버에 해당 프로젝트 실행 재실행
$ cat /home/ec2-user/app/step1/deploy.sh
#!/bin/bash

REPOSITORY=/home/ec2-user/app/step1
PROJECT_NAME=springboot2-webservice

cd $REPOSITORY/$PROJECT_NAME/

echo "> Git Pull"
git pull

echo "> 프로젝트 Build 시작"
./gradlew build

echo "> step1 디렉토리로 이동"
cd $REPOSITORY

echo "> Build 파일 복사"
cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/

echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}\*.jar)

echo "현재 구종 중인 애플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
    echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않았습니다."
else
    echo "> kill -15 $CURRENT_PID"
    kill -15 $CURRENT_PID
    sleep 5
fi

echo "> 새 애플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/ |grep jar |tail -n 1)

echo "> JAR Name: $JAR_NAME"
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &

스크립트를 실행하고 로그를 확인해보자.

#스크립트에 실행 권한 추가
$ chmod +x ./deploy.sh

$ ll ~/app/step1/deploy.sh
-rwxrwxr-x 1 ec2-user ec2-user 1462 Feb  8 00:26 /home/ec2-user/app/step1/deploy.sh

#스크립트 실행
$ bash deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작

BUILD SUCCESSFUL in 3s
8 actionable tasks: 8 up-to-date
> step1 디렉토리로 이동
> Build 파일 복사
> 현재 구동중인 애플리케이션 pid 확인
현재 구종 중인 애플리케이션 pid:
> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않았습니다.
> 새 애플리케이션 배포
> JAR Name: springboot2-webservice-1.0-SNAPSHOT.jar
$ nohup: appending output to ‘nohup.out’

#로그 확인
$ cat /home/ec2-user/app/step1/nohup.out
... 생략 ...

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-02-07 17:25:43.599 ERROR 25935 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found.

Action:

Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' in your configuration.

nohup.out 파일의 내용을 보면 어플리케이션 실행이 실패하였고, ClientRegistrationRepository를 찾을 수 없다는 에러가 발생하였다.

3. 외부 Security 파일 등록하기

“ClientRegistrationRepository를 찾을 수 없다는 에러”의 원인은 application-oauth.properties가 없기 때문이다. ClientRegistrationRepository를 생성하려면 clientId와 clientSecuret가 필요하다.
로컬 PC에서 실행할 때는 해당 설정들이 application-oauth.properties파일에 있었다.
하지만 .gitignore로 git에서 제외 대상이라 깃허브에는 올라가지 않았기 때문에 서버에 배포되지 않은 것이다.
애플리케이션을 실행하기 위해 공개된 저장소에 ClientId와 ClientSecret을 올릴 수는 없으니 서버에서 이 설정을 직접 생성해주도록 하자.

#application-oauth 설정 파일 생성
$ ls /home/ec2-user/app/application-oauth.properties
/home/ec2-user/app/application-oauth.properties

#애플리케이션이 application-oauth 파일을 참조하도록 실행명령 수정
$ vi ~/app/step1/deploy.sh
...
nohup java -jar \
        -Dspring.config.location=classpath:/application.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.properties,classpath:/application-real.properties \

#배포 스크립트 실행
$ bash ~/app/step1/deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작

BUILD SUCCESSFUL in 2s
8 actionable tasks: 8 up-to-date
> step1 디렉토리로 이동
> Build 파일 복사
> 현재 구동중인 애플리케이션 pid 확인
현재 구종 중인 애플리케이션 pid:
> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않았습니다.
> 새 애플리케이션 배포
> JAR Name: springboot2-webservice-1.0-SNAPSHOT.jar
$ nohup: appending output to ‘nohup.out’

#로그 확인
$ cat nohup.out

...

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.3)

2023-02-07 17:57:42.859  INFO 11932 --- [           main] com.spring.book.Application              : Starting Application using Java 17.0.6 on freelec-springboot2-webservice with PID 11932 (/home/ec2-user/app/step1/springboot2-webservice-1.0-SNAPSHOT.jar started by ec2-user in /home/ec2-user/app/step1)
2023-02-07 17:57:42.866  INFO 11932 --- [           main] com.spring.book.Application              : The following profiles are active: oauth
2023-02-07 17:57:45.368  INFO 11932 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-02-07 17:57:45.505  INFO 11932 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 119 ms. Found 2 JPA repository interfaces.
2023-02-07 17:57:47.250  INFO 11932 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-02-07 17:57:47.275  INFO 11932 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-02-07 17:57:47.276  INFO 11932 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.56]
2023-02-07 17:57:47.417  INFO 11932 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-02-07 17:57:47.417  INFO 11932 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4365 ms
2023-02-07 17:57:47.521  INFO 11932 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-02-07 17:57:47.875  INFO 11932 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-02-07 17:57:47.905  INFO 11932 --- [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem://localhost/~/testdb'
2023-02-07 17:57:48.485  INFO 11932 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]

로그 확인 결과 애플리케이션이 정상적으로 실행된 것을 확인할 수 있다.
다음 포스팅에서는 RDS 접근 설정을 추가하여 애플리케이션이 DB에 데이터를 영구적으로 저장하도록 설정해보자.

참고

도서 - 스프링 부트와 AWS로 혼자 구현하는 웹 서비스

0개의 댓글