From cc7a86905a446166f57143e27d8c905b26bb5b8d Mon Sep 17 00:00:00 2001 From: PgmJun Date: Wed, 6 Dec 2023 22:18:46 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8:=20feat=20CD=20=ED=8C=8C=EC=9D=B4?= =?UTF-8?q?=ED=94=84=EB=9D=BC=EC=9D=B8=20=EA=B5=AC=EC=B6=95=20#49?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd-dev.yml | 86 ++++++++++++++++++++++++++++++++++++ scripts/appspec.yml | 26 +++++++++++ scripts/health_check.sh | 31 +++++++++++++ scripts/run_new_was.sh | 32 ++++++++++++++ scripts/switch.sh | 25 +++++++++++ 5 files changed, 200 insertions(+) create mode 100644 .github/workflows/cd-dev.yml create mode 100644 scripts/appspec.yml create mode 100644 scripts/health_check.sh create mode 100644 scripts/run_new_was.sh create mode 100644 scripts/switch.sh diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml new file mode 100644 index 0000000..b3ad83a --- /dev/null +++ b/.github/workflows/cd-dev.yml @@ -0,0 +1,86 @@ +name: API Server Java CD with Gradle on DEV + +# develop 브랜치에 push 시에 동작 +on: + push: + branches: [ "develop" ] + +env: + S3_BUCKET_NAME: codere-s3 + +jobs: + build: + name: Code deployment + + # 실행 환경 + runs-on: ubuntu-latest + + steps: + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'corretto' + + # 3) application.yml 세팅 + - name: setting application.yml + run: | + cd ./src/main/resources # resources 폴더로 이동 + echo "${{ secrets.APPLICATION_YML }}" > ./application.yml + echo "${{ secrets.APPLICATION_DEV_YML }}" > ./application-dev.yml + shell: bash + + # 4) build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 테스트는 제외) + run: ./gradlew clean build -x test + + # 5) 배포 파일을 담을 디렉토리 생성 + - name: Make Directory + run: mkdir -p deploy + + # 6) Jar 파일 복사 + - name: Copy Jar + run: cp ./build/libs/*.jar ./deploy + + # 7) appspec.yml, script files 복사 + - name: Copy files + run: cp ./scripts/* ./deploy + + # 8) 배포 압축 파일 생성 + - name: Make zip file + run: zip -r ./core.zip ./deploy + shell: bash + + # 9) S3에 배포 압축 파일 업로드 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_DEV }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY_DEV }} + aws-region: ap-northeast-2 + + - name: Upload to S3 + run: aws s3 cp --region ap-northeast-2 ./core.zip s3://$S3_BUCKET_NAME/ + + # Deploy + - name: Deploy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_DEV }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY_DEV }} + run: + aws deploy create-deployment + --application-name core-codeDeploy + --deployment-group-name API_SERVER + --file-exists-behavior OVERWRITE + --s3-location bucket=codere-s3,bundleType=zip,key=core.zip + --region ap-northeast-2 + + diff --git a/scripts/appspec.yml b/scripts/appspec.yml new file mode 100644 index 0000000..926f8bb --- /dev/null +++ b/scripts/appspec.yml @@ -0,0 +1,26 @@ +version: 0.0 +os: linux + +# source 경로에 있는 파일을 EC2 인스턴스의 destination에 배포, 만약 해당 지점에 이미 파일들이 존재하면 overwrite +files: + - source: / + destination: /home/ubuntu/api-server + overwrite: yes + +permissions: + - object: / + pattern: "**" + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: run_new_was.sh + timeout: 180 + runas: ubuntu + - location: health_check.sh + timeout: 180 + runas: ubuntu + - location: switch.sh + timeout: 180 + runas: ubuntu diff --git a/scripts/health_check.sh b/scripts/health_check.sh new file mode 100644 index 0000000..143d7c6 --- /dev/null +++ b/scripts/health_check.sh @@ -0,0 +1,31 @@ +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +CURRENT_PORT=$(cat /etc/nginx/conf.d/service-url.inc | grep -Po '[0-9]+' | tail -1) +TARGET_PORT=0 + +# Toggle port Number +if [ ${CURRENT_PORT} -eq 8081 ]; then + TARGET_PORT=8082 +elif [ ${CURRENT_PORT} -eq 8082 ]; then + TARGET_PORT=8081 +else + echo "[$NOW_TIME] No WAS is connected to nginx" >> /home/ubuntu/api-server/deploy_err.log + exit 1 +fi + +echo "[$NOW_TIME] Start health check of WAS at 'http://127.0.0.1:${TARGET_PORT}' ..." >> /home/ubuntu/api-server/deploy.log + +for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10 +do + echo "[$NOW_TIME] #${RETRY_COUNT} trying..." >> /home/ubuntu/api-server/deploy.log + RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${TARGET_PORT}/actuator/health) + + if [ ${RESPONSE_CODE} -eq 200 ]; then + echo "[$NOW_TIME] New WAS successfully running" >> /home/ubuntu/api-server/deploy.log + exit 0 + elif [ ${RETRY_COUNT} -eq 10 ]; then + echo "[$NOW_TIME] Health check failed." >> /home/ubuntu/api-server/deploy_err.log + exit 1 + fi + sleep 10 +done \ No newline at end of file diff --git a/scripts/run_new_was.sh b/scripts/run_new_was.sh new file mode 100644 index 0000000..e84286d --- /dev/null +++ b/scripts/run_new_was.sh @@ -0,0 +1,32 @@ +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +HOST_NAME=$(cat /etc/hostname) +CURRENT_PORT=$(cat /etc/nginx/conf.d/service-url.inc | grep -Po '[0-9]+' | tail -1) +TARGET_PORT=0 + +echo "[$NOW_TIME] Current port of running WAS is ${CURRENT_PORT}." >> /home/ubuntu/api-server/deploy.log + +if [ ${CURRENT_PORT} -eq 8081 ]; then + TARGET_PORT=8082 +elif [ ${CURRENT_PORT} -eq 8082 ]; then + TARGET_PORT=8081 +else + echo "[$NOW_TIME] No WAS is connected to nginx" >> /home/ubuntu/api-server/deploy.log +fi + +TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+') + +if [ ! -z ${TARGET_PID} ]; then + echo "[$NOW_TIME] Kill WAS running at ${TARGET_PORT}." >> /home/ubuntu/api-server/deploy.log + sudo kill ${TARGET_PID} +fi + +if [ ${HOST_NAME} == "core-prod-server" ]; then + nohup java -jar -Dserver.port=${TARGET_PORT} -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod /home/ubuntu/api-server/*.jar >> /home/ubuntu/api-server/deploy.log 2>/home/ubuntu/api-server/deploy_err.log & + echo "[$NOW_TIME] Now new WAS runs at ${TARGET_PORT}." >> /home/ubuntu/api-server/deploy.log + exit 0 +else + nohup java -jar -Dserver.port=${TARGET_PORT} -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev /home/ubuntu/api-server/*.jar >> /home/ubuntu/api-server/deploy.log 2>/home/ubuntu/api-server/deploy_err.log & + echo "[$NOW_TIME] Now new WAS runs at ${TARGET_PORT}." >> /home/ubuntu/api-server/deploy.log + exit 0 +fi diff --git a/scripts/switch.sh b/scripts/switch.sh new file mode 100644 index 0000000..4c90c36 --- /dev/null +++ b/scripts/switch.sh @@ -0,0 +1,25 @@ +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +CURRENT_PORT=$(cat /etc/nginx/conf.d/service-url.inc | grep -Po '[0-9]+' | tail -1) +TARGET_PORT=0 + +echo "[$NOW_TIME] Nginx currently proxies to ${CURRENT_PORT}." >> /home/ubuntu/api-server/deploy.log + +# Toggle port number +if [ ${CURRENT_PORT} -eq 8081 ]; then + TARGET_PORT=8082 +elif [ ${CURRENT_PORT} -eq 8082 ]; then + TARGET_PORT=8081 +else + echo "[$NOW_TIME] No WAS is connected to nginx" >> /home/ubuntu/api-server/deploy.log + exit 1 +fi + +# Change proxying port into target port +echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc + +echo "[$NOW_TIME] Now Nginx proxies to ${TARGET_PORT}." >> /home/ubuntu/api-server/deploy.log +# Reload nginx +sudo service nginx reload + +echo "[$NOW_TIME] Nginx reloaded." >> /home/ubuntu/api-server/deploy.log