본문 바로가기
BackEnd/Project

[ParmNav] CI/CD 구축

by 개발 Blog 2024. 9. 26.

효율적인 애플리케이션 개발과 운영을 위해 자동화된 CI/CD 파이프라인 구축은 필수적이다. 이를 통해 코드 변경 사항이 신속하고 안전하게 배포될 수 있으며, 개발자는 더 빠르게 기능을 릴리즈하고 버그를 수정할 수 있다. 이번 글에서는 ParmNav 프로젝트에 CI/CD 파이프라인을 구축하는 과정과 이를 통해 얻을 수 있는 이점을 소개하고자 한다.

 

AWS CodeDeploy 에이전트 설치

AWS 가이드라인에 따라 필요한 패키지를 설치하고 CodeDeploy 에이전트를 설치한다. 다음 명령어를 실행하여 에이전트를 설치하고 로그 파일을 생성한다.

https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html

sudo apt install ruby-full
sudo apt install wget
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto > /tmp/logfileCopy

 

설치 후에는 다음 명령어로 에이전트의 실행 상태를 확인한다.

systemctl status codedeploy-agent

 

IAM 설정 사용

이전에 생성한 IAM 설정을 사용한다. 자세한 설정은 이전 포스트를 참고한다.

https://eunchaan.tistory.com/170

 

약국 인스턴스에 IAM 롤을 연결해서 인스턴스가 AWS 리소스에 접근할 수 있게 해 준다.

 

S3 버킷 생성

프로젝트의 빌드 파일을 저장할 S3 버킷을 생성한다. 이 버킷은 프로젝트의 빌드 파일을 EC2 인스턴스로 전송하는 데 사용된다.

 

CodeDeploy 설정

CodeDeploy 애플리케이션을 생성하고, EC2 인스턴스를 배포 그룹에 추가한다. 배포 그룹 설정은 애플리케이션을 EC2 인스턴스에 배포할 때 사용된다.

 

GitHub Secrets 설정

프로젝트 리포지토리의 GitHub Actions에서 사용할 AWS 자격증명을 설정한다.

 

 

배포 스크립트 설정

EC2 인스턴스에 배포를 위한 스크립트를 작성하고 실행 권한을 부여한다. 이 스크립트는 현재 실행 중인 애플리케이션의 프로세스 ID를 확인하여, 실행 중인 애플리케이션이 있을 경우 이를 종료시키고, 없을 경우 종료하지 않고 넘어간다. 이후 빌드 파일을 복사하고 Docker Compose를 재시작하여 새 애플리케이션을 배포한다.

 

scripts/deploy.sh

#!/bin/bash

REPOSITORY=/home/ec2-user/Pharmacy-Recommendation
PROJECT_NAME=Pharmacy-Recommendation

echo "> 현재 구동 중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}.*.jar)

if [ -z "$CURRENT_PID" ]; then
    echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
    echo "> kill -15 $CURRENT_PID"
    kill -15 $CURRENT_PID
    sleep 5
fi

echo "> 새 어플리케이션 배포"

echo "> Build 파일 복사"
cp $REPOSITORY/*.jar $REPOSITORY/

JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1)

echo "> JAR Name: $JAR_NAME"

echo "> Docker Compose 재시작"
cd $REPOSITORY
docker-compose down
docker-compose up -d

echo "> 새 어플리케이션 배포 완료"
  • 현재 실행 중인 애플리케이션의 프로세스 ID 확인
  • 실행 중인 애플리케이션이 있다면 종료
  • 빌드 파일을 복사하여 새 애플리케이션으로 준비
  • Docker Compose를 사용하여 컨테이너를 재시작하고 새 애플리케이션을 배포

인스턴스 서버에서 아래 명령어로 실행 권한을 부여한다.

chmod +x deploy.sh

 

appspec.yml 생성

AWS CodeDeploy에 사용될 appspec.yml 파일을 설정한다. 이 파일은 배포 과정에서 필요한 파일 위치, 실행 권한, 환경 변수 설정 등을 정의한다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/Pharmacy-Recommendation
    overwrite: yes
file_exists_behavior: OVERWRITE
hooks:
  ApplicationStart:
    - location: scripts/deploy.sh
      timeout: 600
      runas: ec2-user
environment:
  variables:
    PATH: /usr/local/bin:/usr/bin:/bin
  • 소스 경로, 대상 경로 및 파일 덮어쓰기 옵션을 설정한다.
  • 배포 후 실행될 스크립트와 해당 스크립트의 타임아웃, 실행 사용자를 지정한다.

.github/workflows/deploy.yaml에 스크립트를 작성

deploy.yaml 파일은 GitHub Actions를 사용하여 자동화된 CI/CD 파이프라인을 구축하는 데 사용된다. 이 파일은 push 이벤트를 기반으로 코드가 푸시될 때마다 빌드 및 배포 과정을 자동으로 실행한다.

name: CI-CD

on:
  push:
    branches:
      - main

env:
  PROJECT_NAME: Pharmacy-Recommendation
  S3_BUCKET_NAME: s3-eunchan
  CODE_DEPLOY_APPLICATION_NAME: CODE-DEPLOY
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: CODE-DEPLOY-GROUP

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

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

      - name: Cache Gradle packages
        uses: actions/cache@v3
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
          restore-keys: ${{ runner.os }}-gradle

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew

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

      - name: Grant execute permission for deploy.sh
        run: chmod +x ./scripts/deploy.sh

      - name: Make zip file
        run: |
          zip -r ./$GITHUB_SHA.zip . -x "*.git*"
          echo "Zip file contents:"
          unzip -l ./$GITHUB_SHA.zip
        shell: bash

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Upload to S3
        run: aws s3 cp --region ${{ secrets.AWS_REGION }} ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      - name: Code Deploy
        run: |
          aws deploy create-deployment \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --deployment-config-name CodeDeployDefault.AllAtOnce \
          --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
          --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
  • on: push: main 브랜치로 푸시가 발생할 때만 파이프라인이 작동하도록 설정한다.
  • env: 프로젝트 이름, S3 버킷 이름, AWS CodeDeploy 애플리케이션 및 배포 그룹과 같은 중요한 환경 변수를 설정한다.
  • jobs: build: 빌드 및 배포 작업을 정의한다. 이 작업은 GitHub Actions에서 최신 Ubuntu 환경을 사용하여 실행된다.
  1. Checkout: 코드를 체크아웃하여 GitHub Actions 환경으로 가져온다.
  2. Set up JDK 17: 프로젝트에 필요한 Java 17 버전을 설정한다.
  3. Cache Gradle packages: 빌드 시간을 줄이기 위해 Gradle 패키지를 캐시한다.
  4. Grant execute permission for gradlew: Gradle 실행 파일의 권한을 설정한다.
  5. Build with Gradle: 테스트를 제외하고 프로젝트를 빌드한다.
  6. Grant execute permission for deploy.sh: 배포 스크립트 파일에 실행 권한을 부여한다.
  7. Make zip file: 프로젝트를 zip 파일로 압축하여 S3로 업로드할 준비를 한다.
  8. Configure AWS credentials: AWS 자격 증명을 설정하여 S3와 CodeDeploy에 접근할 수 있도록 한다.
  9. Upload to S3: 생성된 zip 파일을 AWS S3에 업로드한다.
  10. Code Deploy: AWS CodeDeploy를 통해 업로드된 파일을 배포한다.

Actions에서 빌드 확인

GitHub Actions에서 빌드가 성공적으로 완료되었는지 확인한다.

 

AWS CodeDeploy 배포 확인

AWS의 CodeDeploy에서 배포가 성공적으로 이루어졌는지 확인한다.

 

서버 접속 후 Docker 실행 확인

서버에 접속하여 Docker가 정상적으로 실행 중인지 확인한다.

 

이렇게 CI/CD 파이프라인 구축을 완료했다. 이제 코드 수정 후 푸시하면 자동으로 서버에 배포되며, 이를 통해 더 효율적이고 안정적인 배포 프로세스를 유지할 수 있다.