2024. 3. 5. 12:54ㆍ프로젝트
본 포스팅에서는 프로젝트를 EC2에서 배포하고, 스크립트를 작성하는 과정을 적었습니다.
CI/CD를 구현하기 전, 배포 스크립트를 짜본 것에 의의를 두려 합니다.
CI/CD 구현 과정은 다음 포스팅에 담겨있습니다.
EC2 서버 구성 과정을 자세히 살펴보겠습니다.
1. 톰캣 웹서버 설치하기
- 저희는 깃허브에서 Spring boot 프로젝트를 다운받아 실행할 것이기 때문에 톰캣이 내장되어 있습니다.
- 따라서 해당 부분은 건너뛰어도 무방합니다.
apt-cache search tomcat
sudo apt install tomcat8
tomcat8 패키지가 없다고 다른 패키지를 이용하라는 문구가 나옵니다. 기존의 ubuntu repository 저장소가 tomcat8을 들고 있지 않기 때문에 추가적으로 저장소를 추가해줘야 합니다.
이를 PPA(Personal Package Archives) 라고 부릅니다.
PPA 에서 tomcat8을 가진 저장소를 찾아 저장소를 ubuntu 저장소에 추가한 후, apt update를 하면 메뉴판에 tomcat 8이 추가되어 설치할 수 있게 됩니다.
우분투는 버전마다 코드명이 있는데, 현재 버전은 20.04 입니다.
lsb_release -a
위 명령어를 통해 Codename: focal 이라는 것을 알았습니다. PPA에서 focal 용 tomcat8 버전 설치하는 법을 검색해서 찾아옵니다.
PPA(Personal Package Archives) 추가하기
sudo add-apt-repository ppa:ttyrnpuu/tomcat
이후 apt update 를 통해 우분투 repository 의 목록을 갱신해준 후, tomcat8 을 설치해줍니다.
sudo apt update
sudo apt install tomcat8
netstat -nlpt
8080 포트가 돌아가고 있습니다.
현재는 8080 포트가 EC2 서버의 방화벽에 막혀있기 때문에, AWS 에서 인바운드 규칙을 통해 추가해줍니다.
그 후, 접속한 모습입니다.
여기까지, EC2에 Tomcat 8을 설치해 주었습니다.
실행중인 톰캣을 끄려면 sudo systemctl stop tomcat8 명령어를 입력해줍니다.
다시 시작하려면 sudo systemctl restart tomcat8 을 입력합니다.
사실상 저희는 스프링부트 프로젝트를 clone 해서 실행해줄 것이기 때문에, 내장된 톰캣을 사용할 것입니다.
그래도 톰캣을 어떻게 설치하고 작동시키는지 알면 좋을 것 같아 적어보았습니다.
2. GitHub에서 프로젝트를 다운로드합니다.
- git --version 으로 git이 깔려있는지 확인
- git clone <프로젝트 URL>
프로젝트 다운로드 후, 폴더가 하나 생성되었습니다.
내부 구조는 아래와 같습니다.
프로젝트를 실행파일로 변경해야 하는데, 자바의 실행파일은 jar 파일입니다.
테스트와 빌드를 통해 jar 파일로 변경한 후 만들어진 jar 파일로 프로젝트를 실행할 수 있습니다.
- gradlew를 통해 프로젝트를 빌드할 것입니다. (맥, 리눅스 용 스크립트)
- 이 스크립트는 내장 gradle을 이용해 빌드를 실행합니다.
chmod u+x gradlew
소유주에 실행(x) 권한을 추가로 부여합니다.
3. 파일 실행, 로그 redirection
sudo apt update
sudo apt-cache search jdk | grep open-jdk-11
JDK 로 프로젝트를 컴파일해주어야 하기 때문에, openjdk-11-jdk를 설치해줍시다.
sudo apt install openjdk-11-jdk
java --version
jdk 설치 후 java 버전이 나오면 성공!
이제 gradlew 를 사용해 실행 파일로 변경해줍니다.
./gradlew build
빌드가 모두 끝난 후 build 폴더가 생성되고, build/libs 폴더 내부에 jar 파일이 만들어져 있습니다.
java -jar plac-0.0.1-SNAPSHOT.jar 명령어를 통해 실행하면 됩니다.
하지만 제 프로젝트는 application.yml 파일에 여러 환경 변수들이 있어서, 이를 실행하기 위한 쉡 스크립트 파일을 작성해주었습니다.
sh 파일 작성 후, 실행해주면 백그라운드로 서버 실행 완료입니다.
start.sh 파일
#!/bin/bash
# 데이터베이스 설정
export DB_HOST="{db_host 값}"
export DB_USERNAME="{db_username}"
export DB_PASSWORD="{db_password}"
# Google OAuth 설정
export GOOGLE_LOGIN_CLIENT_ID="{google_client_id}"
export GOOGLE_LOGIN_CLIENT_SECRET="{google_client_secret}"
/**
생략
*/
# JWT 시크릿 설정
export JWT_ACCESS_SECRET="{access_token_secret}"
export JWT_REFRESH_SECRET="{refersh_token_secret}"
# 애플리케이션 백그라운드로 실행
nohup java -jar plac-0.0.1-SNAPSHOT.jar > mylog.out &
plac-0.0.1-snapshot jar 파일이 3631 PID 로 실행중입니다.
nohup 명령어로 인해 프로그램을 백그라운드로 실행하면서 로그를 nohup.out 에 남던 로그를 mylog.out 파일에 옮겼습니다.
mylog.out 파일이 생성되었고 이 파일을 tail 로 실시간으로 모니터링 할 수 있습니다.
tail -f mylog.out
4. 정상 로그와 에러 로그 분리
nohup java -jar plac-0.0.1-SNAPSHOT.jar > log.out &
현재는 에러 로그 뿐만 아니라 정상 로그도 log.out 파일에서 볼 수 있습니다. 에러 출력과 표준 출력을 리해보겠습니다.
nohup java -jar plac-0.0.1-SNAPSHOT.jar 1>log.out 2>err.out &
표준 출력은 log.out, 에러 출력은 err.out 파일에 리다이렉션 해줍니다.
이후에 배포를 통해 작성했던 모든 명령어들을 스크립트로 작성해 자동화시킬 때, 실행이 잘 안된 경우 에러 로그만 확인하고, 잘 된다면 정상 로그만 확인하는 게 편리하기 때문에 나누었습니다.
타임존 변경
현재 UTC(미국)으로 설정되어 있는 타임존을 우리나라 서울 시간으로 바꿔줍시다.
sudo timedatectl set-timezone Asia/Seoul
타임존이 서울로 바뀌었습니다. 시간 세팅을 해준 후, 서버를 재시작해서 설정을 적용해주어야 합니다.
종료 스크립트 작성하기
pgrep -f *.jar
다음과 같은 stop.sh 스크립트 파일을 작성해줍니다.
echo "Plac-server stop..."
Spring_PID=$(pgrep -f .jar)
echo $Spring_PID
kill -9 $Spring_PID
서버를 재시작해준 후, 타임존이 서울로 잘 설정되어 있는 것을 확인했습니다.
5. Cron 자동화
cron 은 시간기반 job 스케쥴러입니다. 작업을 고정된 시간, 날짜에 맞춰 주기적으로 실행할 수 있도록 스케줄링해줍니다.
필요성
- 프로젝트 배포 후, 실행 도중에 에러가 발생해 서버가 다운될 수 있습니다.
- err.log 파일에서 서버가 종료되었다는 로그는 저희가 모니터링 할 수 있지만, 서버가 자동적으로 재시작되지는 않습니다. 따라서 일일이 서버에 접속해 재시작 하는건 너무 번거로우므로, 자동 재시작하는 스크립트를 작성해보았습니다.
스프링 서버가 종료되었을 때, 자동으로 재시작하는 cron 을 설정할 것입니다.
스프링 서버를 종료시키는 스크립트 : spring-stop.sh
echo "SPRING BOOT STOP..."
SPRING_PID=$(pgrep -f plac-0.0.1-SNAPSHOT.jar)
kill -9 $SPRING_PID
작동 방식
- PID를 찾는다.
- 찾은 PID로 프로세스 Kill
실행 후 8080 포트가 더 이상 돌지 않는다는 걸 확인했습니다.
이제는 서버가 종료된 후, 서버를 재실행하는 스크립트를 작성해봅시다.
spring-restart.sh
# 데이터베이스 설정
export DB_HOST="{db_host}"
export DB_USERNAME="{db_username}"
export DB_PASSWORD="{db_password}"
# Google OAuth 설정
export GOOGLE_LOGIN_CLIENT_ID="{google_client_id}"
export GOOGLE_LOGIN_CLIENT_SECRET="{google_client_secret}"
/**
생략
*/
SPRING_PID=$(pgrep -f plac-0.0.1-SNAPSHOT.jar)
SPRING_PATH="/home/ubuntu/plac-server/build/libs/plac-0.0.1-SNAPSHOT.jar"
echo $SPRING_PID
echo $SPRING_PATH
# 서버가 종료되었는지 확인.
# $SPRING_PID는 문자열이 아니므로 쌍따옴표로 감싸준다.
if [ -z "$SPRING_PID" ]; then
echo "plac 서버가 종료된 상태..."
echo "plac 서버를 재시작합니다 - $(date)" 1>>/home/ubuntu/cron-restart/spring-restart.log
nohup java -jar $SPRING_PATH 1>log.out 2>err.out &
else
echo "plac 서버가 이미 실행중입니다..."
fi
재시작 스크립트 파일을 실행하면 서버가 재시작되고, spring-restart.log 파일이 생성됩니다.
tail -f 로 해당 로그파일을 모니터링 하면, 다음과 같습니다.
서버를 종료시키고 spring-restart.sh 실행 후, netstat -nltp 를 통해 8080 포트가 돌고 있는 것을 확인했습니다. -> 성공!
spring-restart.sh 을 직접 실행하여 서버를 재시작하는 부분까지 완료했고, 이를 cron 에 등록하는 스크립트를 짜봅시다.
vim deploy.sh
# 스프링 서버 종료 시, 재시작하는 스크립트
echo "crontab 등록 - spring restart..."
crontab -l > crontab_new
echo "* * * * * /home/ubuntu/cron-restart/spring-restart.sh" 1>>crontab_new
crontab crontab_new
rm crontab_new
chmod u+x deploy.sh
crontab -e 를 통해 cron 에 잘 등록되었는지 확인합니다.
잘 등록되었습니다. (맨 밑)
spring-restart.sh 파일이 cron 에 잘 등록되어 있으므로, 서버가 종료되어도 자동 재시작됩니다.
서버를 stop 시키고, 1분 후에 다시 보면 8080 포트가 동작중인 것을 볼 수 있습니다.
정리
여기까지 배포를 완료했습니다.
EC2 로컬에서 GitHub 프로젝트를 다운받았으며 프로젝트를 빌드하는 스크립트를 작성하고, 자동 재실행을 위해 cron 을 등록해 주었습니다. 또한 에러 로그를 리다이렉션해 로그 파일을 만들었습니다.
다음 포스팅에서는 배포와 재배포를 자동화하는 실제 과정 작성하겠습니다.
'프로젝트' 카테고리의 다른 글
[쿠폰] Redis 기반 비동기 시스템 구현 (0) | 2024.04.21 |
---|---|
[쿠폰] 트러블 슈팅 - 동시성 처리 (0) | 2024.04.15 |
Docker, Github Actions 로 CI/CD 구축하기 (0) | 2024.03.11 |
[JWT] Access Token 과 Refresh Token 저장 및 관리에 대한 고민 (2) | 2024.02.02 |
Spring Security를 이용한 인증/인가 (0) | 2024.02.01 |