무중단 배포를 구축해 보자 - Front End 구성 편

Server

Language :

안녕하세요 Lovefield입니다.

이전 글 “무중단 배포를 구축해 보자 - 환경 편”에 이어서 이번 글에서는 프론트 엔드 서버를 무중단 배포하기 위한 설정을 서술하려 합니다. 프론트 엔드 프레임워크로는 Nuxt.js를 사용했습니다. 구동 환경은 Bun.js를 사용했습니다. 우선적으로 빌드를 해야했기에 Git Action을 이용해 빌드와 업로드 기능을 작성해 주겠습니다.

Git Action을 작성하기 이전에 secrets 값을 지정해 줘야 합니다.

  • ENV : 프론트 엔드 에서 사용하는 환경변수 값입니다.
  • HOST_DIR : 서버에서 사용할 기본 디렉토리 위치입니다.
  • HOST_IP : 서버 주소입니다.
  • HOST_RUN_DIR : 서버에서 스크립트를 실행하는 디렉토리 위치입니다.
  • HOST_USER : 서버 유저 이름입니다.
  • PEM_VALUE : 서버에 접근하기위한 PEM키의 값입니다.

docker-compose.yml

YAML

name: Deploy

on:
   push: # 브런치에 PUSH가 될 경우 실행
       branches:
           - main
   workflow_dispatch: # GitHub action 페이지에서 수동으로 실행
       name:
           description: "print name"

jobs:
   buildAndDeploy:
       runs-on: ubuntu-latest
       permissions:
           contents: read
           packages: write
       steps:
           - uses: actions/checkout@v3
           - uses: oven-sh/setup-bun@v2 # bun.js 사용

           - name: Module Install
             run: bun install --frozen-lockfile

           - name: Create env
             run: echo "$ENV" >> .env
             env:
                 ENV: ${{ secrets.ENV }}

           - name: Blue
             run: bun run build

           - name: Create ZIP
             run: zip -qq -r ./.output.zip ./.output

           - name: Upload ZIP file
             uses: appleboy/scp-action@v0.1.7
             with:
                 host: ${{ secrets.HOST_IP }}
                 username: ${{ secrets.HOST_USER }}
                 key: ${{ secrets.PEM_VALUE }}
                 port: 22
                 source: "./.output.zip"
                 target: ${{ secrets.HOST_DIR }}/

           - name: Run Deploy Script
             uses: appleboy/ssh-action@v1.1.0
             env:
                 HOST_DIR: ${{ secrets.HOST_DIR }}
                 HOST_RUN_DIR: ${{ secrets.HOST_RUN_DIR }}
             with:
                 host: ${{ secrets.HOST_IP }}
                 username: ${{ secrets.HOST_USER }}
                 key: ${{ secrets.PEM_VALUE }}
                 port: 22
                 envs: HOST_DIR,HOST_RUN_DIR
                 script: |
                     sudo cp -vf $HOST_DIR/.output.zip $HOST_RUN_DIR/front/blue/.output.zip
                     sudo cp -vf $HOST_DIR/.output.zip $HOST_RUN_DIR/front/green/.output.zip
                     cd $HOST_RUN_DIR
                     sudo sh deploy-frontend.sh

GitHub Action을 이용해 빌드 및 업로드를 진행한 후, 서버에 있는 deploy-frontend.sh 를 실행하도록 구성했는데요. 이 deploy-frontend.sh를 통해서 Blue, Green 컨테이너를 업데이트 해줍니다.

deploy-frontend.sh

Bash

#!/bin/bash

# 실행중인 blue가 있는지
EXIST_BLUE=$(sudo docker compose ps -a | grep "frontend-blue")
target="blue";
target_port="8002"
TIMESTAMP=`date +%Y%m`
LOGFILE="./logs/frontend-$TIMESTAMP.log"

func_reload() # 재실행 함수
{
   echo "[$(date +%Y-%m-%d\ %H\:%M\:%S)] $1 Container down" >> $LOGFILE

   sudo docker compose down frontend-$1 # 컨테이너 다운

   rm -rf ./front/$1/.output # 기존 파일 삭제

   sudo unzip -o ./front/$1/.output.zip -d ./front/$1 # 압축 해제

   rm ./front/$1/.output.zip # 압축파일 삭제

   echo "[$(date +%Y-%m-%d\ %H\:%M\:%S)] $1 Container up" >> $LOGFILE

   sudo docker compose up frontend-$1 -d # 컨테이너 업

   sleep 1.5

   while true; do # 2초마다 헬스 체크
       RESPONSE=$(curl -I http://localhost:$2/health-check | grep "200" | awk '{print $2}')

       echo "[$(date +%Y-%m-%d\ %H\:%M\:%S)] $1 Container Health Check" >> $LOGFILE

       if [ "$RESPONSE" -eq "200" ]; then
           break;
       fi
      
       sleep 2
   done
}

touch $LOGFILE

echo "[$(date +%Y-%m-%d\ %H\:%M\:%S)] >>> 프론트 배포 스크립트 시작 <<<" >> $LOGFILE

# Blue가 실행중이라면
if [ "$EXIST_BLUE" ]; then
   target="green";
   target_port="8001"
else
   target="blue";
   target_port="8002"
fi

func_reload $target $target_port

if [ "$target" -eq "blue" ]; then
   func_reload "green" "8001"
else
   func_reload "blue" "8002"
fi

echo "[$(date +%Y-%m-%d\ %H\:%M\:%S)] >>> 프론트 배포 스크립트 종료 <<<" >> $LOGFILE

위와 같이 작성 후 Git Push를 통해서나 직접 Action을 생성해서든 실행이 된다면 다음과 같은 순서대로 진행이 됩니다.
Git Action에서 main 브런치를 기준으로 빌드합니다.
Git Action에서 빌드된 파일을 압축하여 서버에 전송합니다.
Git Action에서 서버에 있는 배포 스크립트를 실행합니다.
배포 스크립트에서 전달받은 압축파일을 풀고 Blue, Green 컨테이너를 각각 업데이트 합니다.

전부 진행이 되었다면 logs 폴더에 다음과 같은 log 파일이 생성됩니다.

Plain Text

[2024-12-22 23:28:50] >>> 프론트 배포 스크립트 시작 <<<
[2024-12-22 23:28:50] green Container down
[2024-12-22 23:29:03] green Container up
[2024-12-22 23:29:11] green Container Health Check
[2024-12-22 23:29:11] blue Container down
[2024-12-22 23:29:22] blue Container up
[2024-12-22 23:29:28] blue Container Health Check
[2024-12-22 23:29:28] >>> 프론트 배포 스크립트 종료 <<<

이렇게 해서 프론트 배포 구성이 완료되었습니다.

Lovefield

Web Front-End developer

하고싶은게 많고, 나만의 서비스를 만들고 싶은 변태스러운 개발자입니다.