5장까지 만든 프로젝트를 이제 배포해보는 과정이다.
putty에 로그인 한 후 git을 EC2에 설치한다.
sudo yum install git
이후 cd 명령어로 ~/app/step1 디렉토리를 생성하고 해당 디렉토리에 git 프로젝트를 클론할 것이다.
git clone https://github.com/Youthhing/springboot1.git
이후 클론 진행을 확인하고 cd 명령어로 프로젝트를 들어간다.
./gradlew test
명령어로 코드들이 잘 수행되는지 확인하자.
두 가지의 오류가 발생할 수 있다.
1. 테스트가 실패했다.
이 경우 우선, 코드를 수정해야한다. 수정한 코드를 깃허브에 다시 푸쉬했다면 다음 명령어를 통해 프로젝트를 다시 가져오자.
git pull
2. 실행권한이 없다
-bash: ./gradlew: Permission denied
위와 같은 명령어가 뜬다면,
chome +x ./gradlew 를 입력해 권한을 추가해주자.
나는 권한이 없어서 권한을 추가해줬다.
그러나, 이후 테스트가 실패했는데 코드 관련 에러가 떴다.
package javafx.geometry does not exist import javafx.geometry.Pos;
해당 에러가 계속 뜨길래.. 뭐지 하고 일단 쓰지 않는 패키지라 코드를 지워야했다.
인텔리제이에서 프로젝트를 들어가서 관련 코드를 삭제하고 다시 pull하는 과정에서 애를 먹었으나 pull을 한 후 다시 test를 진행했음에도 실패.
그래서 로컬디렉토리를 확인해봤다.
pull이 제대로 되지 않았던것 같다.src/main/java..로 해당 파일을 직접 푸티에서 수정하고 테스트를 진행했다.
그러나, 테스트가 또 실패했다.
내 github에 실수로 build 디렉토리를 같이 올렸었는데 이 디렉토리가 같이 있어서일까라는 생각이 들었다. 그러나 build는 디렉토리라 단순 rm 명령어로는 지워지지 않아서 git 명령어를 사용해 지워주었다.
우선 원격저장소에서 git rm --cached -r build명령으로 깃헙에서 build 폴더를 삭제하고 커밋했다.
(해당 명령어는 원격저장소에 있는 내용만 삭제하는 코드이다. 따라서 , 실행 후 commit, push를 해주자 꼭!)
로컬에서는 rm -rf dir 명령어를 사용해서 지울 수 있다.
-rf 옵션은 삭제 권한이 없는 디렉토리까지 지우는 옵션이다.
결국 새로운 디렉토리 step11을 파고 해당 폴더에 다시 클론을 해서 테스트를 진행했다.
수정내역
- 깃헙에서 build 폴더 삭제
- 안쓰는 패키지 삭제
그러니 정말 신기하게도 테스트가 성공했다 ㅋㅋㅋ 코드는 같은데 왜 실패했던걸까 의문이 들긴하지만 뭐지 아무튼 성공~
8.2 배포 스크립트 만들기
배포란?
작성한 코드를 실제 서버에 반영하는 것을 배포라고 함.
- git clone , pull을 통해 새 버전의 프로젝트를 받는것.
- Gradle이나 Maven을 통해 프로젝트 테스트와 빌드
- EC2 서버에서 해당 프로젝트를 실행 및 재실행
앞선 과정을 배포할때마다 하나하나 명령어를 실행하면 어려움이 많음. 따라서 이를 쉘 스크립트로 작성해 스크립트만 실행해 과정이 잘 진행되도록하자.
쉘스크립트란?
.sh라는 확장자를 가진 파일. 리눅스에서 기본적으로 작동할 수 있는 스크립트 파일이다.
빔(VIM)은 단지 리눅스같은 GUI(마우스를 사용하지 않는 환경)에서 사용할 수 있는 편집도구이다.
쉘 스크립트를 deploy.sh를 다음과 같이 작성한다.
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step11
PROJECT_NAME=springboot1
cd $REPOSITORY/$PROJECT_NAME/
echo "> Git Pull"
git pull
echo "> 프로젝트 Build 시작"
./gradlew build
echo "> step11 디렉토리 이동"
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 &
쉘 스크립트 설명
REPOSITORY=/home/ec2-user/app/step11
- 프로젝트의 주소는 자주 사용되는 곳이므로 기억해놓는다. 전역 변수? cpp #define이랑 비슷한 느낌이다.
같은 방법으로 PROJECT_NAME=springboot1도 사용하는 프로젝트 이름으로 고정한다.
$ + {변수명}으로 사용한다.
ex : $REPOSITORY
git pull
- 디렉토리를 이동한 후 git의 master브랜치의 최신 내용을 당겨온다.
./gradlew build
gradlew을 사용해서 프로젝트 빌드를 진행한다.
cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/
프로젝트 내부의 jar파일을 모아놓은 파일을 우리 repository로 복사해온다.
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}.*.jar)
- 현재 실행중인 스프링부트 어플리케이션을 종료한다. 뭘로..?
실행중인 스프링부트 어플리케이션은 current_pid 가 zero( -z)가 아닐 시, kill -15 명령어를 통해 해당 프로세스를 중단시킨다.
pgrep : ps + grep 명령어가 합쳐진 명령어로, 지정한 형식에 맞는 프로세스를 반환하는 명령어다.
- ps : 프로세스 정보를 표기하라
-f : 문자열 패턴에 맞는 프로세스 반환
-z : if 문 안에 있는 조건 같은데 if [ -z $"CURRENT_PID"];이면 현재 PID가 zero이면? 없으면 이런 의미로 쓰이고
chatgpt에게 물어본 결과 아래와 같이 대답했다.
pgrep -f ~~ 이면
pgrep -z ~~이면 현재 프로세스 그룹외에 다른 디렉토리는 찾지 않는다는 뜻인것 같다.
deploy.sh에서 현재 프로세스 그룹은 app/step11이고, 그곳에서만 실행중인 jar 파일을 찾으면
kill -15 : 리눅스 / 유닉스에서 프로세스를 종료시키는 명령어. 프로세스에게 SIGTERM 시그널( 정상 프로세스 종료 )을 보내고 해당 <PID>를 가진 프로세스를 종료시킨다.
sleep 5 : 현재 실행중인 프로세스를 5초동안 대기 시키는 역할.
JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1)
새로 실행할 jar 파일을 찾자.
jar 파일이 여러개 생기기 때문에 tail -n으로 가장 나중의 jar(최신파일)을 변수에 저장하자.
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &
- 찾은 jar 파일로부터 해당 jar 파일을 nohup으로 실행하자.
- 스프링의 특징으로 외장 톰캣을 따로 설치하는 것이 아닌 내장 톰캣을 사용해 jar파일로 웹 어플리케이션 서버를 실행한다.
- java -jar 명령어를 사용할땐, 터미널 접속이 끊어지면 어플리케이션도 끊어진다. 따라서, nohup을 사용해 터미널이 종료어도 어플리케이션이 구동되도록하자.
실행하고 나서 chmod +x ./deploy.sh로 권한 추가를 해주고 ./deploy.sh를 실행하면 다음과 같이 성공 메세지가 뜬다.
잘 실행되었으니 nohup.out 파일을 열어 로그를 확인해보자.
했는데.. nohup.out이 아무리봐도 없어서 한참 고생했다. 그런데 확인해보니 springboot1디렉토리가 아니라 step11 즉, 상위 폴더에 deploy.sh를 설정해줘야했다. 따라서 기존 파일을 지우고 다시 원 위치에서 생성하니 nohup.out이 제대로 등장했다.
근데 결국 deploy.sh 내에서 디렉토리 이동을 하니까 이 또한 큰 문제는 아니었던 것 같은데..? 결국 여러번 실행된게 문젠가?
실행 관련 로그가 nohup.out에 저장되어있다. 여기서 보이는 로그를 바탕으로 실행과정에서의 오류를 찾아보자.
책에서는 오류..가 뜬다는데 나는 왜 안뜨지..?
책에서 떠야할 오류가 안뜨고 있다. 왜그럴까 생각을 해본다.
* 실행중인 어플리케이션 Pid가 존재하면 안되는데 왜 존재하지..? 라는 생각이 먼저 들었다. 실수로 구동한 프로젝트가 계속 실행되는 것이다. 게다가 나는 nohup도 제대로 못찾고 초기 nohup.out도 확인을 못했기에 그곳에 그런 오류가 뜨지 않을까? 생각해봤다.
우선 나는 springboot1 어플리케이션을 초기에 다른 폴더에서 실행을 했다.
따라서 해당 프로세스가 종료되지 않았다면 deploy스크립트를 반복실행할 때, kill로 매번 실행을 종료하고 새로운 걸 실행하니 PID가 매번 바뀌는 것이 아닐까 생각했다.
Nohup 명령어 : 무중단 배포이므로 세션이 끝나도 어플리케이션ㅇ이 진행됨. 따라서 kill 명령어를 의도적으로 사용하는 스크립트도 작성했다.
따라서 다른 테스트 쉘 스크립트를 작성해서 실행중인 어플리케이션을 확인해봤다. 제발 여기서 실마리가 잡히지 않으면 8장을 다시 시작해야했기에... 제발...
REPOSITORY=/home/ec2-user/app/step11
cd $REPOSITORY
CURRENT_PID=$(pgrep -f springboot1.*.jar)
if [ -z "$CUURENT_PID"]; then
echo ">현재 실행중인거 없음~"
else
echo ">이녀석이 실행중이었다. $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
결과 : tes.sh를 다음과 같이 작성해 실행중인 프로세스를 확인했으나 없었다. 따라서 이 가설은 틀림!
따라서, 우선 8장까지의 내용을 다시 해봐야겠다. 다시 실행한 기록은 다른 글에 정리하도록하겠다.
(이 실패와 고뇌의 과정은 따로 정리했습니다. ㅠㅠ)
해결!!!!!!!! 8.3장에서 application-oauth.properties가 없어서 오류가 생긴ㅎ다했는데 내 github에 바보같이 application-oauth.properties가 올라가 있었다... 이거 보안관련해서 중요한 사항인데 .gitignore 설정을 제대로 안했다.
따라서 해당 파일을 깃헙이랑 로컬에서 지워주고 deploy.sh를 실행하니 해결되었다
8.3 외부 security 파일 등록하기
책에서 제시한 ClientRegistrationRepository를 생성할때 ID,Secret이 필요한데 우리는 .gitignore에 의해 application-oauth.properties를 제외시키고 다운했으니 인증 오류가 발생한다는 이야기이다.
따라서 직접 깃허브에 ClientId와 ClientSecret을 올릴 수 없으니 서버에서 직접 설정파일을 작성해주어야한다.
application-oauth.properties에 있는 내용을 복붙해서 ~/app 디렉토리에 저장을 하고, deploy.sh에 아래 코드를 추가로 넣어준다.
(application-oauth.properties의 내용은 보안사항이니 작성하지 않았음.)
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는 파일이 외부에 존재하므로 절대경로로 설정해주어야한다.
이후 다시 실행을 하면 다음과 같은 결과가 나온다.
정상 실행완료.
'BE > 6기 코테이토 - Spring Study' 카테고리의 다른 글
4회(2). Ch8 - EC2서버에 프로젝트를 배포해보자 (0) | 2023.02.17 |
---|---|
4.5회. Ch8. 다시도전 (그래도 실패를 곁들인) (0) | 2023.02.17 |
4회. Ch7 - AWS에 데이터베이스 환경을 만들어보자. - AWS RDS (0) | 2023.02.14 |
4회. ch6 AWS 서버 환경을 만들어보자 - AWS EC2 (0) | 2023.02.11 |
3회 - Ch.5(2) 스프링 시큐리티와 OAuth 2.0으로 로그인 기능 구현하기 (0) | 2023.02.08 |