이 글은 '스프링 부트와 AWS로 혼자 구현하는 웹 서비스' 서적을 참고하여 AWS와 스프링부트 프로젝트 연동하고, 배포하는 작업을 설명 합니다.
깃허브에 본인의 프로젝트를 올린 후 실습을 진행할 수 있습니다. AWS EC2 - Ubuntu, RDS - MySQL5.7.30 환경에서 진행합니다.
- EC2 기본 설정
- 타임존 변경
- 호스트네임 변경
- 배포 스크립트 만들기
- 실행 권한 추가
- 스프링프로젝트와 RDS 연결하기
- 데이터베이스 접속 정보 보호 (외부 Security 파일 등록)
EC2 기본 설정
Java 11 설치
원하는 자바 버전을 다운로드한다. 이 글에서는 자바 11버전을 사용한다.
(자바8의 경우, sudo apt-get install openjdk-8-jre-headless)
sudo apt-get update
sudo apt-get install openjdk-11-jre-headless
설치가 완료되면 인스턴스의 Java 버전을 11로 변경한다. (다음 명령어로 자바 버전이 여러 개일 때 원하는 버전을 선택할 수 있다. 현재는 자바 버전이 11 한 개만 존재한다.)
update-alternatives --config java
타임존 변경
EC2 서버의 기본 타임존은 UCT다. 세계 표준 시간으로 한국과 9시간 차이가 난다. 서버의 타임존을 한국 시간(KST)로 변경한다.
sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
date 명령어로 타임존이 KST로 변경된 것을 확인한다.
호스트 네임 변경
여러 서버를 관리 중일 때 IP만으로 어떤 서비스의 서버인지 확인하기 어렵다. 각 서버가 어느 서비스인지 표현하기 위해 HOSTNAME을 변경하자. 현재는 ip-172-31-11-99와 같은 호스트네임을 갖고 있다.
vim, vi, nano 등 어느 편집기를 사용해 호스트 네임을 변경한다.
sudo vim /etc/sysconfig/network
변경 후 서버를 재부팅 한다.
sudo reboot
재부팅이 끝나고 다시 접속하면 HOSTNAME이 변경되어있다.
Github을 통해 EC2에 스프링 프로젝트 Clone으로 받기
깃허브에서 코드를 받아올 수 있게 EC2에 깃을 설치한다.
sudo apt-get install git
git clone으로 프로젝트를 저장할 디렉토리를 생성한다.
mkdir ~/app && mkdir ~/app/step1
생성한 디렉토리로 이동한다.
cd ~/app/step1
본인의 깃허브 웹페이지에서 https 주소를 복사한다.
복사한 https 주소로 git clone을 진행한다.
클론된 프로젝트로 이동해 파일들이 잘 복사되었는지 확인한다.
cd 프로젝트명
코드들이 잘 수행되는지 테스트로 검증한다.
./gradlew test
만약 gradlew 실행권한이 없다는 메시지가 뜬다면, 다음 명령어로 실행 권한을 추가한 뒤 다시 테스트를 수행하자.
chmod +x ./gradlew
EC2에 그레이들(Gradle)을 설치하지 않고, Gradle Task를 수행할 수 있었던 이유는 프로젝트에 포함된 gradlew 파일 덕분이다. 이는 그레이들이 설치되지 않은 환경 또는 버전이 달라도 해당 프로젝트에 한해서 그레이들을 쓸 수 있도록 지원하는 Wrapper 파일이다.
배포 스크립트 만들기
작성한 코드를 실제 서버에 반영하는 것을 배포라 한다. 배포는 다음 과정을 모두 포괄한다.
1. git clone 혹은 git pull을 통해 새 버전의 프로젝트 생성
2. Gradle or Maven으로 프로젝트 테스트와 빌드
3. EC2 서버에서 해당 프로젝트 실행 및 재실행
이런 과정을 배포할 때마다 개발자가 하나하나 명령어를 실행하는 것을 불편하다. 그래서 이를 쉘 스크립트로 작성해 스크립트만 실행하면 앞의 과정이 차례로 진행되도록 한다.
쉘 스크립트는 .sh 파일 확장자를 가진 파일로, 노드 JS가 .js라는 파일을 통해 서버에서 작동하는 것처럼 쉘 스크립트를 리눅스에서 기본적으로 사용할 수 있는 스크립트 파일의 한 종류다.
이제 ~/app/step1/에 deploy.sh 파일을 하나 생성한다.
vim ~/app/step1/deploy.sh
#!/bin/bash
REPOSITORY=/home/유저이름/app/step1
PROJECT_NAME=프로젝트이름
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/$PROJECT_NAME.jar
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 &
코드설명
1) REPOSITORY=/home/유저이름/app/step1
프로젝트 디렉토리 주소는 스크립트 내에서 자주 사용하기 때문에 변수로 저장한다. 동일한 이유로 PROJECT_NAME = 프로젝트이름 도 변수로 저장한다.
쉘에서는 타입 없이 선언하여 저장하고, $변수명으로 변수를 사용할 수 있다.
2)cd $REPOSITORY/$PROJECT_NAME/
git clone 받은 디렉토리(home/유저이름/app/step1/프로젝트이름)로 이동한다.
3)git pull
디렉토리 이동 후, master 브랜치의 최신 내용을 받는다.
4)./gradlew build
프로젝트 내부의 gradlew로 buid를 수행한다.
5)cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/
build 결과물인 jar 파일은 jar 파일을 모아둔 위치로 복사한다.
6)CURRENT_PID=$(pgrep -f ${PROJECT_NAME}*.jar)
기존의 수행 중이던 스프링 애플리케이션을 종료한다. pgrep은 process id만 추출하는 명령어이고, -f 옵션으로 프로세스 이름을 찾는다.
7)if ~ else ~ fi
현재 구동 중인 프로세스의 존재 여부를 판단해서 기능을 수행한다. process is 값을 보고 프로세스가 있으면 해당 프로세스를 종료한다.
8)JAR_NAME=$(s -tr $REPOSITORY/ | grep *.jar | tail -n 1)
새로 실행할 jar 파일명을 찾는다. 여러 jar 파일이 생기기 때문에 tail -n로 가장 나중에 생성된 jar 파일(최신 파일)을 변수에 저장한다.
9)nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &
찾은 jar 파일을 nohub으로 실행한다. 여기서 스프링 부트의 장점을 볼 수 있다. 외장 톰캣을 사용하지 않아도 jar 파일만 있으면 내장 톰캣으로 웹 애플리케이션 서버를 실행할 수 있다.
일반적으로 자바를 실행할 때 java -jar라는 명령어를 사용하지만, 이렇게 하면 사용자가 터미널 접속을 끊을 때 애플리케이션도 같이 종료된다. 터미널을 종료해도 애플리케이션은 계속 구동될 수 있도록 nohub 명령어를 사용한다.
실행 권한 추가
chmod +x ./deploy.sh
다음 명령어로 스크립트를 실행하자.
./deploy.sh
다음과 같은 로그와 함께 애플리케이션이 실행된다.
이때 deploy.sh 파일과 실행한 디렉토리에 nohup.out 파일이 생성되고, 여기에는 애플리케이션에서 출력되는 모든 내용이 담겨있다.
스프링프로젝트와 RDS 연결하기
스프링프로젝트 build.gradle 파일에 jpa와 mysql-connector dependency를 추가한다.
dependencies {
…
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('mysql:mysql-connector-java')
}
스프링프로젝트의 application.properties 파일의 접속할 DB 정보와 필요한 설정을 추가한다.
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
spring.sesion.store-type=jdbc
spring.jpa.hibernade.ddl=none
spring.datasource.url=jdbc:mysql://rds주소:포트명(기본 3306)/DBNAME
spring.datasource.username=db계정
spring.datasource.password=db계정 비민번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
코드설명
1)spring.jpa.hibernate.ddl-auto=none
JPA로 테이블이 자동 생성되는 옵션을 None으로 지정한다. RDS에는 실제 운영으로 사용될 테이블이 저장되므로 스프링 부트에서 새로 만들지 않도록 한다. 이 옵션이 없으면 테이블이 모두 새로 생성될 수 있으므로 주의하자.
데이터베이스 접속 정보 보호 (외부 Security 파일 등록)
스프링부트와 RDS를 연결할 때 application.properties 파일에는 RDS 접속 정보가 포함되어있었다.
spring.datasource.url=jdbc:mysql://rds주소:포트명(기본 3306)/DBNAME
spring.datasource.username=db계정
spring.datasource.password=db계정 비민번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
하지만 이런 정보는 보안을 위해 노출되면 안되므로 깃헙에 파일을 올릴때는 제거해야한다. 때문에 해당 정보를 위한 설정 파일을 EC2에 직접 만들자.
기존에 생성한 EC2의 app 디렉토리에 application-real-db.properties 파일을 만들어 다음 내용을 추가한다.
spring.datasource.url=jdbc:mysql://rds주소:포트명(기본 3306)/DBNAME
spring.datasource.username=db계정
spring.datasource.password=db계정 비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
그리고 deploy.sh가 해당 파일을 쓸 수 있도록 deploy.sh의 코드 마지막 줄을 다음과 같이 수정한다.
nohup java -jar \
-Dspring.config.location=classpath:/application.properties,/home/유저명/app/application-real-db.properties \
-Dspring.profiles.active=real \
$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
출처
스프링 부트와 AWS로 혼자 구현하는 웹 서비스
'스프링 > 스프링부트' 카테고리의 다른 글
[Spring Boot] 오류 해결: (org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing) (2) | 2021.04.28 |
---|---|
[Spring Boot] logback을 통해 스프링부트 로그 설정 시작하기 (0) | 2021.04.04 |
[Spring Boot] 스프링부트 프로젝트에 Spring Data JPA 적용하기 (0) | 2021.01.15 |
[Spring Boot] 스프링 부트에서 테스트 코드와 롬복(lombok) 사용하기 (0) | 2021.01.05 |
[Spring Boot] 인텔리제이(intellij)로 스프링부트 시작하기 (0) | 2020.12.27 |
댓글