From c5f2e8698496429408ffe1d9d1d1d5772e7ddb96 Mon Sep 17 00:00:00 2001 From: "Lee, yeeun" Date: Thu, 31 Oct 2024 16:46:43 +0900 Subject: [PATCH 1/2] =?UTF-8?q?:sparkles:Feat:=20build.gradle=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 5358dcc..8c73de6 100644 --- a/build.gradle +++ b/build.gradle @@ -56,3 +56,7 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +jar{ + enabled = false +} \ No newline at end of file From 7ac84fb4aaf89990c0bc26d30a9f51755557dedf Mon Sep 17 00:00:00 2001 From: "Lee, yeeun" Date: Thu, 31 Oct 2024 16:49:08 +0900 Subject: [PATCH 2/2] =?UTF-8?q?:sparkles:Feat:=20CI/CD=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appspec.yml | 26 ++++++++++++++++ scripts/health.sh | 39 ++++++++++++++++++++++++ scripts/profile.sh | 36 ++++++++++++++++++++++ scripts/start.sh | 32 +++++++++++++++++++ scripts/stop.sh | 20 ++++++++++++ scripts/switch.sh | 16 ++++++++++ src/main/resources/application-real1.yml | 2 ++ src/main/resources/application-real2.yml | 2 ++ 8 files changed, 173 insertions(+) create mode 100644 appspec.yml create mode 100644 scripts/health.sh create mode 100644 scripts/profile.sh create mode 100644 scripts/start.sh create mode 100644 scripts/stop.sh create mode 100644 scripts/switch.sh create mode 100644 src/main/resources/application-real1.yml create mode 100644 src/main/resources/application-real2.yml diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..068b167 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,26 @@ +version: 0.0 #CodeDeploy 버전을(무조건 0.0으로 고정) +os: linux +files: + - source: / #destination으로 이동시킬 파일. 여기서는 전체 파일을 의미. + destination: /home/ec2-user/app/zip/ #source에서 지정된 파일을 받는 위치 + overwrite: yes #기존 파일들을 덮어쓸지 여부 + +permissions: #CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 함 + - object: / + pattern: "**" + owner: ec2-user + group: ec2-user + +hooks: + AfterInstall: + - location: stop.sh #엔진엑스와 연결되어 있지 않은 스프링 부트를 종료 + timeout: 60 + runas: ec2-user #stop.sh를 ec2-user 권한으로 실행 + ApplicationStart: + - location: start.sh #엔진엑스와 연결되어 있지 않은 Port로 새 버전의 스프링 부트를 시작 + timeout: 60 + runas: ec2-user + ValidateService: + - location: health.sh #새 스프링 부트가 정상적으로 실행됐는지 확인 + timeout: 60 + runas: ec2-user \ No newline at end of file diff --git a/scripts/health.sh b/scripts/health.sh new file mode 100644 index 0000000..e0c9830 --- /dev/null +++ b/scripts/health.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh +source ${ABSDIR}/switch.sh + +IDLE_PORT=$(find_idle_port) + +echo "> Health Check Start!" +echo "> IDLE_PORT: $IDLE_PORT" +echo "> curl -s http://127.0.0.1:$IDLE_PORT/profile" +sleep 10 + +for RETRY_COUNT in {1..10} +do + RESPONSE=$(curl -s http://127.0.0.1:${IDLE_PORT}/profile) + UP_COUNT=$(echo ${RESPONSE} | grep 'real' | wc -l) + + if [ ${UP_COUNT} -ge 1 ] # Nginx와 연결되지 않은 포트로 스프링 부트가 잘 실행되었는지 체크 + then # $up_count >= 1 ("real" 문자열이 있는지 검증) + echo "> Health Check 성공" + switch_proxy # 잘 실행되어 있다면 프록시 설정을 변경 + break + else + echo "> Health Check의 응답을 알 수 없거나 혹은 실행 상태가 아닙니다." + echo "> Health Check: ${RESPONSE}" + fi + + if [ ${RETRY_COUNT} -eq 10 ] + then + echo "> Health check 실패. " + echo "> 엔진엑스에 연결하지 않고 배포를 종료합니다." + exit 1 + fi + + echo "> Health check 연결 실패. 재시도..." + sleep 10 +done \ No newline at end of file diff --git a/scripts/profile.sh b/scripts/profile.sh new file mode 100644 index 0000000..462762b --- /dev/null +++ b/scripts/profile.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# 쉬고 있는 profile 찾기 +# real1이 사용 중이면 real2가 쉬고 있고 반대면 real1이 쉬고 있음 + +function find_idle_profile() { + RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://newteamsgoody.shop/profile) # 현재 Nginx가 바라보고 있는 스프링 부트가 정상적으로 수행 중인지 확인하고 응답값으로 상태코드를 전달받음 + + if [ ${RESPONSE_CODE} -ge 400 ] # 400번대 이상의 오류일 경우 real2를 사용 + then + CURRENT_PROFILE=real2 + else + CURRENT_PROFILE=$(curl -s https://newteamsgoody.shop/profile) + fi + + if [ ${CURRENT_PROFILE} == real1 ] + then + IDLE_PROFILE=real2 + else + IDLE_PROFILE=real1 + fi + + echo "${IDLE_PROFILE}" # bash 스크립트는 반환 기능이 없기 때문에 echo로 값을 출력하고 클라이언트에서 그 값을 잡아서 사용 +} + +# 쉬고 있는 profile의 port 찾기 +function find_idle_port() { + IDLE_PROFILE=$(find_idle_profile) + + if [ ${IDLE_PROFILE} == real1 ] + then + echo "8081" + else + echo "8082" + fi +} \ No newline at end of file diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100644 index 0000000..0ff9da2 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh + +REPOSITORY=/home/ec2-user/app + +echo "> Build 파일을 복사합니다." + +cp $REPOSITORY/zip/*.jar $REPOSITORY/ + +echo "> 새 애플리케이션 배포" +JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) + +echo "> JAR NAME: $JAR_NAME" + +echo "> $JAR_NAME 에 실행 권한을 부여합니다." + +chmod +x $JAR_NAME + +IDLE_PROFILE=$(find_idle_profile) + +echo "> 새 애플리케이션을 $IDLE_PROFILE 로 실행합니다." + +# 설정 파일의 위치를 지정하고 active profile을 통해 구동될 포트를 지정 +nohup java -jar \ +-Dspring.config.location=$REPOSITORY/config/application.yml,\ +$REPOSITORY/config/application-prod.yml,\ +$REPOSITORY/config/application-$IDLE_PROFILE.yml \ +-Dspring.profiles.active=$IDLE_PROFILE,prod \ +$JAR_NAME > $REPOSITORY/nohup.out 2>&1 & \ No newline at end of file diff --git a/scripts/stop.sh b/scripts/stop.sh new file mode 100644 index 0000000..c082b70 --- /dev/null +++ b/scripts/stop.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) # 현재 stop.sh가 속해 있는 경로를 찾음 + +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh # 일종의 import 구문으로 stop.sh에서도 profile.sh의 function을 사용할 수 있게 함 + +IDLE_PORT=$(find_idle_port) + +echo "> $IDLE_PORT 에서 구동 중인 애플리케이션 pid 확인" +IDLE_PID=$(lsof -ti tcp:${IDLE_PORT}) + +if [ -z ${IDLE_PID} ] +then + echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다." +else + echo "> kill -9 $IDLE_PID" + kill -9 ${IDLE_PID} + sleep 5 +fi \ No newline at end of file diff --git a/scripts/switch.sh b/scripts/switch.sh new file mode 100644 index 0000000..6eb49bc --- /dev/null +++ b/scripts/switch.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source $ABSDIR/profile.sh + +function switch_proxy() { + IDLE_PORT=$(find_idle_port) + + echo "> 전환할 port: $IDLE_PORT" + echo "> Port 전환" + echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc # 엔진엑스가 변경할 프록시 주소를 생성하여 service-url.inc로 덮어 씀 + + echo "> 엔진엑스 Reload" + sudo systemctl reload nginx +} \ No newline at end of file diff --git a/src/main/resources/application-real1.yml b/src/main/resources/application-real1.yml new file mode 100644 index 0000000..54b155f --- /dev/null +++ b/src/main/resources/application-real1.yml @@ -0,0 +1,2 @@ +server: + port: 8081 \ No newline at end of file diff --git a/src/main/resources/application-real2.yml b/src/main/resources/application-real2.yml new file mode 100644 index 0000000..0884131 --- /dev/null +++ b/src/main/resources/application-real2.yml @@ -0,0 +1,2 @@ +server: + port: 8082 \ No newline at end of file