개발놀이터

aws 배포 ec2 (4) : 모놀리식 배포 본문

배포/AWS

aws 배포 ec2 (4) : 모놀리식 배포

마늘냄새폴폴 2022. 8. 12. 19:29

이번엔 쉘 스크립트를 작성해서 git pull부터 빌드해서 실행하기 까지의 과정을 자동화시키려고 한다.

 

일단은 이전에 clone에서 받은 프로젝트 폴더로 들어가보겠다. 필자는 chatting이라는 리포지토리 이름을 사용하고 있다. 

 

우선 이 폴더를 sources라는 폴더로 통째로 옮긴다.

 

# sources 폴더 생성
mkdir sources

# chatting 폴더를 sources 폴더 내부로 옮기기
mv chatting ./sources/

# sources 폴더로 들어가기
cd sources

그리고 chatting 폴더에 들어가서 gradlew의 권한을 바꿔준다.

 

# chatting 폴더로 들어가기
cd chatting

# gradlew의 권한 변경
chmod + ./gradlew

# 이전 디렉토리로 복귀
 cd ..

 

빌드 스크립트 작성

프로젝트 폴ㄹ더가 있는 위치에서 빌드 스크립트를 작성한다. 일단 먼저 파일을 만든다.

 

vim deploy.sh

 

그리고 deploy.sh 라는 파일이 생성되었다면, 다음과 같이 스크립트를 입력한다.

 

# 프로젝트 폴더가 위치해있는 디렉토리
REPOSITORY=/home/ec2-user/sources	
// sources가 있는 리포지토리 파일은 사람마다 다르다
// sources가 있는 루트에서 pwd 명령어를 통해 현재 본인의
// 위치를 파악하고 ec2-user 자리에 넣으면 된다.

# 프로젝트 디렉토리로 들어가기
cd $REPOSITORY/order-example

echo "> GIT PULL"

git pull

echo "> START TO BUILD PROJECT"

chmod +x gradlew					
// gradlew의 권한이 자꾸 부족하다고 뜨고 vi 밖에서
// 해결하려고 해봐도 권한이 644에서 755로 바뀌지 않아서
// 스크립트 내부에서 직접적으로 권한을 부여해줬음

./gradlew build

echo "> COPY JAR FILES"

cp ./build/libs/*.jar $REPOSITORY/

echo "> 현재 구동중인 어플리케이션의 PID 확인"

CURRENT_PID=$(pgrep -f devops-test)

if [ -z $CURRENT_PID ]; then
        echo "현재 구동중인 APPLICATION이 없으므로 종료하지 않습니다."
else
        echo "kill -15 $CURRENT_PID"
        kill -15 $CURRENT_PID
        sleep 5
fi

echo "DEPLOY NEW APPLICATION"

JAR_NAME=$(ls -tr $REPOSITORY |grep jar | tail -n 1)

echo "JAR NAME : $JAR_NAME"

# nohup을 통한 무중단 배포
nohup java -jar $REPOSITORY/$JAR_NAME &

 

한 줄씩 해석해서 살펴보자

 

# 프로젝트 폴더가 위치해있는 디렉토리
REPOSITORY=/home/ec2-user/sources

# 프로젝트 디렉토리로 들어가기
cd $REPOSITORY/order-example

일단은 프로젝트가 위치한 폴더 내부로 들어가기 위한 코드이다. REPOSITORY에는 pwd 커맨드를 통해서 획득한 sources의 디렉토리를 복사해서 넣어주면 된다.

 

git pull

 

만일 최신의 프로젝트가 존재한다면 pull을 하여 최신화 시켜준다.

 

./gradlew build

 

현재 우리의 프로젝트는 gradle 기반이기 때문에 위의 코드를 통해서 프로젝트를 빌드할 수 있다.

 

cp ./build/libs/*.jar $REPOSITORY/

 

빌드의 결과로 생겨난 jar파일들을 모두 REPOSITORY로 복사한다.

 

CURRENT_PID=$(pgrep -f chatting)

if [ -z $CURRENT_PID ]; then
        echo "현재 구동중인 APPLICATION이 없으므로 종료하지 않습니다."
else
        echo "kill -15 $CURRENT_PID"
        kill -15 $CURRENT_PID
        sleep 5
fi

현재 이 프로젝트를 기반으로한 프로세스가 동작중이라면, 그 프로세스를 죽이고 새 프로세스를 실행하기 위한 코드이다.

 

우선 CURRENT_PID에는 현재 프로젝트가 프로세스로 올라가있다면, 그 프로세스의 ID 값이 얼마인지 저장한다. 필자의 프로젝트 이름은 chatting으로 정했기 때문에 chatting으로 pgrep -f 옵션을 통해 검색을 한다.

 

만약 PID 값이 존재한다면 프로세스를 kill 하고 5초를 sleep을 걸어준다.

 

JAR_NAME=$(ls $REPOSITORY |grep 'chatting' | tail -n 1)

 

REPOSITORY에서 디렉토리를 탐색하여서 chatting 이라는 이름을 가진 파일을 찾아내되, 이름이 겹치는 경우에는 최신의 파일을 가리키게 JAR_FILE 변수를 선언한다. 

 

nohup java -jar $REPOSITORY/$JAR_NAME &

nohup을 통해서 jar file을 무중단 실행시킨다. &를 통해서 nohup을 통해 배포된 프로젝트가 백그라운드에서 동작하게 한다. 

 

이제 빌드스크립트를 모두 작성했으니, 이제 실행할 차례이다. 

 

그 전에 위의 코드를 실행하다보면 다양한 에러에 직면하게 될텐데 자잘한 문제 말고 해결하는데 꽤 고생했던 에러들을 모아뒀다.

 

스프링부트 ec2 배포 중 fatal : not a git repository (or any of the parent directories) : .git

https://coding-review.tistory.com/163

 

스프링부트 ec2 배포 중 fatal : not a git repository (or any of the parent directories) : .git

git remote origin으로 연결을 안해서 생긴 문제 git remote add origin 리포지토리주소 로 해결

coding-review.tistory.com

 

스프링 부트 ec2 배포중 gradlew 빌드 후 Execution failed for task ':test' 에러

https://coding-review.tistory.com/164

 

스프링 부트 ec2 배포중 gradlew 빌드 후 Execution failed for task ':test' 에러

몇시간 동안 별에별 짓은 다해봤다. 1. gradle 버전를 바꾸면 된다고 해서 wrapper폴더에 있는 gradle.properties에 버전을 4.10.2로 바꿔보기 2. swap 메모리 4.0기가로 늘리기 3. gradle 깔고 gradle --debug b..

coding-review.tistory.com

 

스프링부트 ec2 배포 중 ./gradlew: Permission denied

https://coding-review.tistory.com/165

 

스프링부트 ec2 배포 중 ./gradlew: Permission denied

gradlew에 권한이 없어서 생기는건 구글링해보니 지겹도록 알겠다. 문제는 구글링해서 나오는 chmod 755 gradlew chmod +x gradlew 이런거 다안통하더라 그래서 짜증나서 deploy.sh 파일 열어서 build gradlew하기

coding-review.tistory.com

 

deploy.sh를 실행하면 다음과 같은 창이 뜨면서 프로젝트를 빌드하고, 동시에 배포를 진행한다.

 

배포가 안정적으로 되었는지 체크해보자. 본인의 인스턴스 퍼블릭 IP를 통해 http 요청을 하나 보내보면

 

잘뜨는것을 확인할 수 있다.

 

 

아직 끝나지 않았다

위와 같은 배포 방식에는 문제점이 다소 있다. 대표적인 문제점은 다음과 같다.

  • 다수의 트래픽을 감당하기엔 무리가 있다. 왜냐하면, 하나의 인스턴스에 대해서 배포를 진행하고 있기 때문이다.
  • 배포 인스턴스의 이미지를 이용해서 여러 인스턴스로 불려내서 Load Balancing을 진행한다고 하더라도 충분히 문제의 소지는 있다. 이 경우에는 각각의 인스턴스를 직접 관리해야한다.
  • 어찌저찌 관리한다고 하더라도, 장애 복구와 관련된 문제가 있다. 장애 복구가 자동화 되어있지 않기 때문에 실제 서비스에서 이러한 방식을 채택한다면 크게 문제가 발생할 수도 있다.

그래서 다음 주제는 DevOps의 끝판왕! docker와 관련된 주제로 살펴보겠다.