- #Project
- #Burgerput
채팅 서버 배포 파이프라인 구성하기
Prolip
2024-08-21
Next.js로 만든 프로젝트 배포 파이프라인 구성하기..
시작..
이번 포스팅에선 제가 채팅 서버를 EC2 환경에 배포할 때 설정한 파일들을 기록해보려고 합니다..
CI/CD 파이프라인은 흐름은 다음과 같습니다.
- 타켓 브랜치(main)에 push 혹은 merge하면 Github-Actions에 의해 프로젝트를 빌드한 뒤 압축해 S3에 업로드합니다.
- 미리 설정해둔 appspect.yml 설정에 맞게 CodeDeploy가 S3에 업로드 되어있는 빌드 파일을 EC2 인스턴스로 가져와 압축을 해제합니다.
- 이후 작성한 스크립트를 통해 pm2로 프로젝트를 배포합니다.
사실 S3 버킷 생성하는거나 EC2 인스턴스 생성하는건 어렵지 않으니 굳이 다루고 가진 않으려 합니다.
main.yml
name: Burgerput-chat-server CI/CD # 파이프라인 트리거로 main 브랜치에 변경 사항이 생길 때 트리거 됩니다. on: push: branches: - main # 파이프라인에서 사용할 환경 변수를 설정하는데 github secrets 값을 사용합니다. env: PROJECT_NAME: Burgerput_Chat_Server S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }} CODE_DEPLOY_APP_NAME: ${{ secrets.CODE_DEPLOY_APP_NAME }} DEPLOYMENT_GROUP_NAME: ${{ secrets.DEPLOYMENT_GROUP_NAME }} NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }} NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }} NEXT_PUBLIC_URL: ${{ secrets.NEXT_PUBLIC_URL }} ADMIN_ID: ${{ secrets.ADMIN_ID }} ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }} NAVER_EMAIL: ${{ secrets.NAVER_EMAIL }} NAVER_PASS: ${{ secrets.NAVER_PASS }} GMAIL_ID: ${{ secrets.GMAIL_ID }} BURGERPUT_SITE_1: ${{ secrets.BURGERPUT_SITE_1 }} BURGERPUT_SITE_2: ${{ secrets.BURGERPUT_SITE_2 }} jobs: build: runs-on: ubuntu-latest # 이 작업은 최신 우분투 환경에서 실행됩니다. steps: - name: checkout # 빌드할 코드 베이스를 준비합니다. uses: actions/checkout@v4 - name: Install pnpm # 패키지 매니저 설치 run: npm install -g pnpm - name: Install dependencies # 의존성 설치 run: pnpm install # .env 파일을 생성해 Github Secrets에서 가져온 환경 변수들을 .env 파일에 기록합니다. # 이 과정을 통해 배포 후 환경 변수들이 작동하게 됩니다. - name: Set Environment Variables run: | echo "NEXTAUTH_SECRET=${NEXTAUTH_SECRET}" >> .env echo "NEXTAUTH_URL=${NEXTAUTH_URL}" >> .env echo "NEXT_PUBLIC_URL=${NEXT_PUBLIC_URL}" >> .env echo "ADMIN_ID=${ADMIN_ID}" >> .env echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" >> .env echo "NAVER_EMAIL=${NAVER_EMAIL}" >> .env echo "NAVER_PASS=${NAVER_PASS}" >> .env echo "GMAIL_ID=${GMAIL_ID}" >> .env echo "BURGERPUT_SITE_1=${BURGERPUT_SITE_1}" >> .env echo "BURGERPUT_SITE_2=${BURGERPUT_SITE_2}" >> .env - name: Build with pnpm # 빌드 run: pnpm run build # $GITHUB_SHA.zip은 git 커밋 해시를 기반으로 한 파일 이름으로 커밋마다 고유한 파일이 생성됩니다. # node_modules 폴더는 배포에 불필요해 제외합니다. - name: Zip create run: zip -qq -r ./$GITHUB_SHA.zip . -x "node_modules/*" shell: bash - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-2 # 압축한 파일을 AWS S3 버킷에 업로드합니다. 업로드된 파일은 /$PROJECT_NAME/$GITHUB_SHA.zip 경로로 저장되며, GITHUB_SHA는 해당 커밋의 고유 해시로 파일 이름이 결정됩니다. - name: Upload to S3 run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip - name: Code Deploy run: | aws deploy create-deployment \ --application-name $CODE_DEPLOY_APP_NAME \ --deployment-config-name CodeDeployDefault.OneAtATime \ --deployment-group-name $DEPLOYMENT_GROUP_NAME \ --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
추가적으로 Code Deploy 부분을 보자면
- application-name: 코드 디플로이 어플리케이션 이름입니다.
- deployment-config-name: 배포 구성 방식으로 한번에 하나의 인스턴스에 배포하도록 OneAtTime으로 설정했습니다.
- deployment-group-name: 배포 그룹 이름입니다.
- s3-location: S3에서 배포할 파일의 경로와 유형을 지정합니다.
appspec.yml
version: 0.0 os: linux files: - source: / destination: "/home/ubuntu/deploy" # 해당 경로에 프로젝트를 저장합니다. overwrite: yes permissions: # EC2 인스턴스에 프로젝트를 저장하기 위한 권한 설정 - object: /home/ubuntu/deploy owner: ubuntu group: ubuntu mode: 755 hooks: AfterInstall: # 배포가 끝난 후 실행할 동작 - location: scripts/deploy.sh # scripts 폴더의 deploy.sh 실행 timeout: 240 runas: ubuntu
code-deploy가 실행할 스크립트로 S3 버킷에 업로드 된 빌드 파일을 EC2 인스턴스의 지정된 경로로 가져와 지정한 스크립트 파일을 실행하게 됩니다.
deploy.sh
#!/bin/bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" sudo chown -R ubuntu:ubuntu /home/ubuntu/deploy PROJECT_ROOT="/home/ubuntu/deploy" PROJECT_NAME="Burgerput_Chat_Server" current_time=$(date "+%Y-%m-%d_%H-%M-%S") DeployLogFile="/home/ubuntu/log/DeployLog_$current_time.log" cd $PROJECT_ROOT echo "Burgerput Chat Server Deploy : $current_time" >> $DeployLogFile echo "Install Dependencies : $current_time" >> $DeployLogFile pnpm install >> $DeployLogFile 2>&1 echo "" && echo "" >> $DeployLogFile 2>&1 echo "Shut down an existing server : $current_time" >> $DeployLogFile pm2 delete $PROJECT_NAME >> $DeployLogFile 2>&1 echo "Run the server : $current_time" >> $DeployLogFile pm2 start "pnpm start" --name $PROJECT_NAME echo "" && echo "" >> $DeployLogFile 2>&1 pm2 ps && pm2 ps >> $DeployLogFile 2>&1 echo "Successful deployment and server execution : $current_time" >> $DeployLogFile 2>&1
배포가 끝난 뒤 실행되는 스크립트 파일로 의존성 설치 후 기존 pm2에서 실행 중인 프로젝트를 제거한 뒤 새로 시작하게 됩니다.
nginx 설정
server { server_name burgerput-chat.site; location / { proxy_pass EC2 인스턴스 주소; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } listen [::]:443 ssl ipv6only=on; listen 443 ssl; ssl_certificate /etc/letsencrypt/live/burgerput-chat.site/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/burgerput-chat.site/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { if ($host = burgerput-chat.site) { return 301 https://$host$request_uri; } listen 80 default_server; listen [::]:80 default_server; server_name burgerput-chat.site; return 404;
메모리 스왑
버거풋 서버에서 셀레니움 돌릴 때 프리티어를 사용하다보니 시스템이 계속 멈췄던 악몽이 생각나서 메모리 스왑은 꼭 해두는 편입니다..
2gb 스토리지 용량을 메모리처럼 사용할 수 있는데 이게 실제 메모리처럼 빠르진 않지만 그래도 없는 것 보단 좋습니다.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16 sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile swapon -s sudo nano /etc/fstab /swapfile swap swap defaults 0 0 free
마치며..
정적인 웹 사이트를 S3에 올리는건 자주 해봤는데 이렇게 EC2에 올리기 위한 저장소로 사용한건 이번이 처음이었습니다..
이렇게 작성해놓고 보면 별로 어렵지 않았던 거 같은데 막상 github actions 들어가보면 실패한 actions 많습니다.. ^^ 눈물을 흘렸습니다..