Skip to content

Commit

Permalink
feat: scripts 파일 작성 및 port switch를 위한 controller 생성
Browse files Browse the repository at this point in the history
- health, start, stop, profile, switch 스크립트 파일 생성
- 포트 번호별 스프링 부트 switch을 위한 controller 생성
  • Loading branch information
kimdozzi committed Apr 17, 2024
1 parent 357cce4 commit 58fdefe
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 32 deletions.
27 changes: 19 additions & 8 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: Build and Deploy to EC2
on:
push:
branches: [ "production" ] ## 나중에 production으로 변경하기
pull_request:
branches: [ "production" ]
# pull_request:
# branches: [ "production" ]

env:
AWS_REGION: ap-northeast-2
Expand All @@ -19,14 +19,17 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
# Actions
- name: Checkout
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

# 프로젝트 내 yml 파일 실행
- name: make application.yml
run: |
mkdir -p ./src/main/resources
Expand All @@ -47,18 +50,22 @@ jobs:
echo "${{ secrets.APPLICATION_TEST }}" > ./application.yml
echo "${{ secrets.TEST }}" > ./application-test.yml
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash

- name: Build and Test
run: ./gradlew build -x test #./gradlew build test

- name: Build with Gradle # and Test
run: ./gradlew clean build -x test #./gradlew build test


- name: Make zip file
run: zip -r ./$GITHUB_SHA.zip .
shell: bash

- name: AWS credential 설정

- name: Deliver to AWS S3 (AWS credential 설정)
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
Expand All @@ -69,8 +76,12 @@ jobs:
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip

- name: EC2에 배포
run: aws deploy create-deployment --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} --s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip

- name: Code Deploy (EC2에 배포)
run: aws deploy create-deployment \
--application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} \
--s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip


40 changes: 40 additions & 0 deletions scripts/health.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# Nginx와 연결되지 않은 포트로 스프링 부트가 잘 수행되었는지 체크
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://localhost:$IDLE_PORT/profile "
sleep 10

for RETRY_COUNT in {1..10}
do
RESPONSE=$(curl -s http://localhost:${IDLE_PORT}/profile)
UP_COUNT=$(echo ${RESPONSE} | grep 'real' | wc -l)

if [ ${UP_COUNT} -ge 1 ]
then # $up_count >= 1 ("real" 문자열이 있는지 검증)
echo "> Health check 성공"
switch_proxy # 잘 떳다면, switch.sh의 switch_proxy로 Nginx 프록시 설정을 변경
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
37 changes: 37 additions & 0 deletions scripts/profile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash

# 쉬고 있는 profile 찾기: deploy01이 사용중이면 deploy02가 쉬고 있고, 반대면 deploy01이 쉬고 있음
function find_idle_profile()
{ # 현재 엔진엑스가 바라보고 있는 스프링부트가 정상적으로 수행 중인지 확인.
RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/profile)

if [ ${RESPONSE_CODE} -ge 400 ] # 400 보다 크면 (즉, 40x/50x 에러 모두 포함)
then # 오류가 발생하면 deploy02를 현재 profile로 사용
CURRENT_PROFILE=deploy02
else
CURRENT_PROFILE=$(curl -s http://localhost/profile)
fi

if [ ${CURRENT_PROFILE} == deploy01 ]
then # IDLE_PROFILE 은 엔진엑스와 연결되지 않은 프로필 , 스프링 부트 프로젝트를 이 프로필로 연결
IDLE_PROFILE=deploy02
else
IDLE_PROFILE=deploy01
fi

# bash는 return value가 안되니 *제일 마지막줄에 echo로 해서 결과 출력*후, 클라이언트에서 값을 사용한다
echo "${IDLE_PROFILE}"
}

# 쉬고 있는 profile의 port 찾기
function find_idle_port()
{
IDLE_PROFILE=$(find_idle_profile)

if [ ${IDLE_PROFILE} == deploy01 ]
then
echo "8080"
else
echo "8081"
fi
}
47 changes: 33 additions & 14 deletions scripts/start.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/GitGetApplication.jar"
# Nginx와 연결되지 않은 포트로 스프링 부트가 잘 수행되었는지 체크
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
source ${ABSDIR}/profile.sh
source ${ABSDIR}/switch.sh

APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
IDLE_PORT=$(find_idle_port)

TIME_NOW=$(date +%c)
echo "> Health Check Start!"
echo "> IDLE_PORT: $IDLE_PORT"
echo "> curl -s http://localhost:$IDLE_PORT/profile "
sleep 10

# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE
for RETRY_COUNT in {1..10}
do
RESPONSE=$(curl -s http://localhost:${IDLE_PORT}/profile)
UP_COUNT=$(echo ${RESPONSE} | grep 'real' | wc -l)

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
if [ ${UP_COUNT} -ge 1 ]
then # $up_count >= 1 ("real" 문자열이 있는지 검증)
echo "> Health check 성공"
switch_proxy # 잘 떴다면, switch.sh의 switch_proxy로 Nginx 프록시 설정을 변경
break
else
echo "> Health check의 응답을 알 수 없거나 혹은 실행 상태가 아닙니다."
echo "> Health check: ${RESPONSE}"
fi

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
if [ ${RETRY_COUNT} -eq 10 ]
then
echo "> Health check 실패. "
echo "> Nginx에 연결하지 않고 배포를 종료합니다."
exit 1
fi

echo "> Health check 연결 실패. 재시도..."
sleep 10
done
25 changes: 15 additions & 10 deletions scripts/stop.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#!/bin/bash
#!/usr/bin/env bash

ROOT_PATH="/home/ubuntu/build"
JAR="$ROOT_PATH/GitGetApplication.jar"
STOP_LOG="$ROOT_PATH/stop.log"
SERVICE_PID=$(pgrep -f $JAR) # 실행중인 Spring 서버의 PID
ABSPATH=$(readlink -f $0) # 절대경로
ABSDIR=$(dirname $ABSPATH ) # 현재 stop.sh가 속해있는 경로를 찾는다.
source ${ABSDIR}/profile.sh # 자바로 보면 일종의 import 구문, stop.sh에서도 profile.sh의 여러 function을 사용 가능

if [ -z "$SERVICE_PID" ]; then
echo "서비스 NotFound" >> $STOP_LOG
IDLE_PORT=$(find_idle_port)

echo "> $IDLE_PORT 에서 구동중인 애플리케이션 pid 확인"
IDLE_PID=$(lsof -ti tcp:${IDLE_PORT})

if [ -z ${IDLE_PID} ]
then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "서비스 종료 " >> $STOP_LOG
# kill "$SERVICE_PID"
kill -9 "$SERVICE_PID" # 강제 종료를 하고 싶다면 이 명령어 사용
echo "> kill -15 $IDLE_PID"
kill -15 ${IDLE_PID}
sleep 5
fi
19 changes: 19 additions & 0 deletions scripts/switch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/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를 사용. tee 는 앞의 문장을 읽어 해당 경로의 파일에 저장.
echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc

echo "> 엔진엑스 Reload"
# restart와 달리 끊김 없이 다시 불러온다. (중요한 설정을 반영해야한다면 restart 사용)
# 여기선 외부의 설정 파일인 service-url을 다시 불러오기 때문에 reload로 가능
sudo service nginx reload
}
26 changes: 26 additions & 0 deletions src/main/java/com/genius/gitget/deploy/DeployController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.genius.gitget.deploy;

import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class DeployController {
private final Environment env;

@GetMapping("/profile")
public String profile() {
List<String> profiles = Arrays.asList(env.getActiveProfiles());
List<String> realProfiles = Arrays.asList("deploy01", "deploy02");
String defaultProfile = profiles.isEmpty() ? "default" : profiles.get(0);

return profiles.stream()
.filter(realProfiles::contains)
.findAny()
.orElse(defaultProfile);
}
}

0 comments on commit 58fdefe

Please sign in to comment.