BOOK 2 - 스프링부트와 AWS로 혼자 구현하는 웹 서비스(7)
스프링부트와 AWS로 혼자 구현하는 웹 서비스 - 7
EC2 서버에 프로젝트 배포
git clone 후 테스트 수행
git 설치 및 프로젝트 클론
-
EC2 접속 후 인스턴스에 git을 먼저 설치한다.
sudo yum install git- 설치 후
git --version명령어로 설치 상태를 확인한다.
- 설치 후
-
git 설치 후 디렉토리를 생성하여 프로젝트를 클론한다.
mkdir ~/app/step1 git clone [깃허브 주소]
프로젝트 테스트 수행
-
프로젝트 디렉토리로 이동하여 테스트를 실행한다.
./gradlew test
-
만약 gradlew 실행 권한이 없으면 실행 권한을 추가한 뒤 다시 수행하면 된다.
chmod +x ./gradlew -
현재 EC2에는 gradle을 설치하지 않았지만 프로젝트 내부에 포함된
gradlew파일로 gradle task를 수행할 수 있다.gradlew: gradle이 설치되지 않은 환경 혹은 버전이 다른 상황에서도 해당 프로젝트에 한해서 gradle을 쓸 수 있도록 지원하는 wrapper 파일
-
배포 스크립트 생성
- 코드를 실제 서버에 반영하는 것을 배포라고 하고, 넓게는 다음의 과정을 모두 포함한다.
git clone혹은git pull을 통해 새 버전의 프로젝트를 받음- Gradle이나 Maven을 통해 프로젝트 테스트와 빌드
- EC2 서버에서 해당 프로젝트 실행 및 재실행
- 위의 모든 과정을 배포할 때마다 개발자가 명령어를 실행하는 것은 불편하고 비효율적이다.
- 해당 명령어들을 shell script로 작성하여 자동으로 위 과정들이 진행되도록 한다.
deploy.sh
-
vim으로
deploy.sh스크립트 파일을 프로젝트 디렉토리 하위에 생성한다.vim ~/app/step1/deploy.sh
#! /bin/bash
REPOSITORY=/home/ec2-user/app/step1
PROJECT_NAME=all-review
cd $REPOSITORY/$PROJECT_NAME/
echo "> Git Pull"
git pull
echo "> Project Build Start"
./gradlew build
echo "> Move to REPOSITORY directory"
cd $REPOSITORY
echo "> Copy Build File"
cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}*.jar)
echo "> Check Application PID : $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
echo "> There's no executing application"
else
echo "> Kill $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
JAR_NAME=$(ls -tr $REPOSITORY/ | grep *.jar | tail -n 1)
echo "> New Applicaion Deployment : $JAR_NAME"
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &
REPOSITORY=/home/ec2-user/app/step1- 프로젝트 디렉토리 주소와 프로젝트 이름은 스크립트 내에서 자주 사용하는 값이기 때문에 변수로 저장한다.
- shell에서는 타입 없이 선언한다.
$변수명으로 변수를 사용할 수 있다.
./gradlew build: 프로젝트 내부의gradlew로 build를 수행한다.CURRENT_PID=$(pgrep -f ${PROJECT_NAME}*.jar)- 기존에 수행중이던 springboot application의 pid값을 추출한다.
pgrep은 process id만 추출하는 명령어이다.-f옵션은 프로세스 이름으로 탐색하는 옵션이다.
- 기존에 수행중이던 springboot application의 pid값을 추출한다.
JAR_NAME=$(ls -tr $REPOSITORY/ | grep *.jar | tail -n 1)- 새로 실행할 jar 파일명을 추출한다.
- 여러 jar 파일 중 최신 jar 파일을 찾아 이름을 저장해야 하기 때문에
tail -n명령어를 사용한다.
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &- 찾은 jar 파일명으로 해당 jar 파일을
nohup으로 실행한다. - 일반적으로 자바를 실행할 때는
java -jar라는 명령어를 사용하지만, 이렇게 실행할 경우 사용자가 터미널 접속을 끊을 때 application도 같이 종료된다. - 실행자가 터미널을 종료해도 application은 계속 구동될 수 있도록
nohup명령어를 사용한다.
- 찾은 jar 파일명으로 해당 jar 파일을
deploy.sh 스크립트 파일 실행
-
다음 명령어로 스크립트 파일을 실행한다.
./deploy.sh -
실행되는 application에서 출력되는 모든 내용은
nohup.out파일을 통해 확인할 수 있다.vim nohup.out
Security 파일 등록
- 이전에
application-oauth.properties파일을 git에서 제외시켜 현재 ec2 서버에는 해당 파일이 존재하지 않는다.- 서버에서
clientId와clientSecret값을 직접 가지고 있도록 한다.
- 서버에서
application-oauth.properties
-
app디렉토리에 해당 설정 파일을 생성한다.vim /home/ec2-user/app/application-oauth.properties -
로컬 설정 파일에 있는 내용을 그대로 붙여넣는다.
deploy.sh에 설정 파일 지정
-
application-oauth.properties설정 파일을 프로젝트가 사용하도록deploy.sh파일을 수정한다.... nohup java -jar \-Dspring.config.location=classpath:/application.properties,/home/ec2-user/app/application-oauth.properties \$REPOSITORY/$JAR_NAME 2>&1 &Dspring.config.location- 스프링 설정 파일 위치를 저장한다.
- 기본 옵션을 담고 있는
application.properties파일과 OAuth 설정을 담고 있는application-oauth.properties파일의 위치를 지정한다. classpath가 붙으면 jar 안에 있는resources디렉토리를 기준으로 경로가 생성된다.application-oauth.properties파일은 외부에 존재하기 때문에 절대경로를 사용한다.
deploy.sh 스크립트 실행
-
수정한
deploy.sh스크립트를 다시 실행한다.
SpringBoot 프로젝트에 RDS 연동
RDS 테이블 생성
Entity 테이블 생성
CREATE TABLE review (
id bigint not null auto_increment primary key,
title varchar(500) not null,
content TEXT not null,
userId bigint not null,
createdAt datetime,
modifiedAt datetime
) engine=InnoDB;
CREATE TABLE user (
id bigint not null auto_increment primary key,
name varchar(255) not null,
email varchar(255) not null,
picture varchar(255),
role varchar(255) not null,
createdAt datetime,
modifiedAt datetime
) engine=InnoDB;
Spring Session 테이블 생성
-
schema-mysql.sql파일에 스프링 세션 테이블 생성 쿼리문이 있어 해당 쿼리문을 실행해주면 된다.CREATE TABLE SPRING_SESSION ( PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, EXPIRY_TIME BIGINT NOT NULL, PRINCIPAL_NAME VARCHAR(100), CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
프로젝트 설정
-
MariaDB 드라이버를
build.gradle에 등록한다.compile("org.mariadb.jdbc:mariadb-java-client") -
src/main/resources하위에application-production.properties파일을 생성하여 production 환경의 RDS 설정을 추가해준다.application-production.properties파일을 생성하면profile=production인 환경이 구성된다.
spring.profiles.include=oauth,prod-db spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect spring.session.store-type=jdbc
EC2 설정
- RDS 접속 정보 역시 github 같은 공개적인 저장소에 업로드할 수 없는 보호해야할 정보이므로 EC2 서버에 직접 설정 파일을 생성한다.
prod-db 설정 파일 생성
-
app디렉토리에application-prod-db.properties파일을 생성한다.spring.jpa.hibernate.ddl-auto=none spring.datasource.url=jdbc:mariadb://rds주소:포트번호/DB명 spring.datasource.username=db계정 spring.datasource.password=db계정 비밀번호 spring.datasource.driver-class-name=org.mariadb.jdbc.Driverspring.jpa.hibernate.ddl-auto=none- JPA로 테이블이 자동 생성되는 옵션을 none으로 지정한다.
- 즉, 스프링부트에서 테이블을 새로 생성하지 않도록 설정해준다.
deploy.sh에 production profile 설정
...
nohup java -jar \-Dspring.config.location=classpath:/application.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-prod-db.properties -Dspring.profiles.active=production \$REPOSITORY/$JAR_NAME 2>&1 &
Dspring.profiles.active=productionapplication-production.properties설정 파일을 활성화 시킨다.application-production.properties의spring.profiles.include옵션 때문에prod-db역시 함께 활성화 된다.
- 수정 후
deploy.sh파일을 다시 실행하면 어플리케이션이 정상적으로 구동되는 것을 확인할 수 있다.- application 구동 후
[인스턴스의 퍼블릭 DNS]:8080/hello로 요청을 보내면 정상적으로 oauth 로그인 페이지가 나오는 것을 볼 수 있다.
- application 구동 후
마지막으로 해당 EC2 인스턴스의 도메인 주소를 구글과 로그인 oauth2 클라이언트의 Callback URL(Redirection URI)로 설정해주면 인스턴스 서버에서 로그인이 가능해진다.