Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .deploy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
16 changes: 16 additions & 0 deletions .deploy/blue-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3'

services:

web:
container_name: neighbors-blue
image: ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}
expose:
- "8080"
ports:
- "8080:8080"
environment:
- TZ=Asia/Seoul
- DB_URL=${DATASOURCE_URL_LOCAL}
- DB_USERNAME=${DATASOURCE_USERNAME}
- DB_PASSWORD=${DATASOURCE_PASSWORD}
16 changes: 16 additions & 0 deletions .deploy/green-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3'

services:

web:
container_name: neighbors-green
image: ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}
expose:
- "8081"
ports:
- "8081:8081"
environment:
- TZ=Asia/Seoul
- DB_URL=${DATASOURCE_URL_LOCAL}
- DB_USERNAME=${DATASOURCE_USERNAME}
- DB_PASSWORD=${DATASOURCE_PASSWORD}
86 changes: 86 additions & 0 deletions .github/workflows/CD.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Blue-Green deployment

on:
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:

# 레포지토리의 특정 브랜치, 커밋을 가져오는 설정
# Github Action 라이브러리인 actions/checkout@v3 액션을 사용
- uses: actions/checkout@v3

# JDK 셋업
# Github Action 라이브러리인 actions/setup-java@v3 액션을 사용
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

# Gradle 빌드에 필요한 데이터를 캐싱하여 빌드 속도를 향상시키는 설정
# Github Action 라이브러리인 actions/cache 액션을 사용
# Gradle 캐시에 의존성, 래퍼 등을 빌드할 때 저장해두었다가 나중에 재빌드할 때 재사용해서 속도를 향상
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: ${{ runner.os }}-gradle-

# gradle 파일에 접근할 권한을 부여
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew

# build 작업 수행
- name: Build with Gradle Wrapper
run: ./gradlew build

# docker image를 build 하고 docker hub에 push
- name: Docker Build and Push
run: |
sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
sudo docker build -f ./.deploy/Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }} .
sudo docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}

deploy:
needs: build
runs-on: ubuntu-latest

steps:
# DockerHub에 로그인
# GitHub Action 라이브러리 사용
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

# .env 파일에 환경 변수 값들 집어넣기 (Github Secret 에 저장한 정보를 .env 파일로 echo)
# 그리고 Blue-Green 배포 스크립트인 deploy.sh 실행
- name: Run a New Version of the the application on EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_KEY }}
script: |
rm -rf ./.env
touch ./.env
echo "DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}" >> ./.env
echo "DOCKER_REPOSITORY=${{ secrets.DOCKER_REPOSITORY }}" >> ./.env
echo "DATASOURCE_URL_LOCAL=${{ secrets.DATASOURCE_URL_LOCAL }}" >> ./.env
echo "DATASOURCE_USERNAME=${{ secrets.DATASOURCE_USERNAME }}" >> ./.env
echo "DATASOURCE_PASSWORD=${{ secrets.DATASOURCE_PASSWORD }}" >> ./.env
cd ~/app/Backend
chmod +x deploy.sh
source deploy.sh


2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ out/

### VS Code ###
.vscode/

.DS_Store
67 changes: 67 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash

set -e

ERR_MSG=''

trap 'echo "Error occured: $ERR_MSG. Exiting deploy script."; exit 1' ERR

if sudo docker ps --filter "name=blue" --format '{{.ID}}' | grep -E .; then
RUN_TARGET="green"
STOP_TARGET="blue"
WAS_RUN_PORT=8081
WAS_STOP_PORT=8080
else
RUN_TARGET="blue"
STOP_TARGET="green"
WAS_RUN_PORT=8080
WAS_STOP_PORT=8081
fi

echo "The $STOP_TARGET version is currently running on the server. Starting the $RUN_TARGET version."

DOCKER_COMPOSE_FILE="$RUN_TARGET-deploy.yml"
sudo docker-compose -f "$DOCKER_COMPOSE_FILE" pull || { ERR_MSG='Failed to pull docker image'; exit 1; }
sudo docker-compose -f "$DOCKER_COMPOSE_FILE" up -d || { ERR_MSG='Failed to start docker image'; exit 1; }
sleep 50

echo "Starting health check for the new version of the application."

HEALTH_CHECK_PASSED=true
RUN_CONTAINER_IDS=$(sudo docker ps --filter "name=$RUN_TARGET" --quiet --all)

for CONTAINER_ID in $RUN_CONTAINER_IDS; do
HEALTH_STATUS=$(sudo docker inspect --format "{{.State.Health.Status}}" $CONTAINER_ID)
if [ "$HEALTH_STATUS" != "healthy" ]; then
HEALTH_CHECK_PASSED=false
break
fi
done

if [ "$HEALTH_CHECK_PASSED" = false ]; then
sudo docker image prune -af
ERR_MSG="Health check failed."
exit 1
fi

echo "Health check passed. Reloading nginx to transfer traffic from $STOP_TARGET to $RUN_TARGET."

NGINX_ID=$(sudo docker ps --filter "name=nginx" --quiet)
NGINX_CONFIG="/etc/nginx/conf.d/default.conf"

sudo docker exec $NGINX_ID /bin/bash -c "sed -i 's/neighbors-$STOP_TARGET:$WAS_STOP_PORT/neighbors-$RUN_TARGET:$WAS_RUN_PORT/' $NGINX_CONFIG"
sudo docker exec $NGINX_ID /bin/bash -c "nginx -s reload" || { ERR_MSG='Failed to reload nginx'; exit 1; }

echo "Terminating the $STOP_TARGET applications."

STOP_CONTAINER_ID=$(sudo docker ps --filter "name=$STOP_TARGET" --quiet)
if [ -n "$STOP_CONTAINER_ID" ]; then
sudo docker stop $STOP_CONTAINER_ID
sudo docker rm $STOP_CONTAINER_ID
sudo docker image prune -af
fi

rm .env

echo "Deployment success."
exit 0