[Server/AWS] AWS를 이용한 Spring Boot 서버 배포 - GitHub Actions 설정

HAEN·2023년 3월 16일
0

이번 포스팅에는 특정 브랜치에 commit이 push 되면 서버가 자동으로 재배포 되는 GitHub Actions를 설정해보겠다


1. GitHub Workflow 생성

GitHub에서 배포하고자 하는 서버의 레포지토리에 들어가서
Actions -> new workflow -> set up a workflow yourself

원하는 이름으로 yml 파일을 생성할 수 있다
아래는 전체 workflow이다

name: Build and Deploy for WOWMATE server to AWS EC2

on:
  push:
    branches: [ deploy ]

env:
  # 버킷에 저장할 폴더 이름
  PROJECT_NAME: WOWMATE_Server
  # S3 버킷 이름
  BUCKET_NAME: wowmate-server-github-action-s3-bucket
  # CodeDeploy의 애플리케이션 이름
  CODE_DEPLOY_APP_NAME: wowmate-app
  # CodeDeploy의 배포그룹 이름
  DEPLOYMENT_GROUP_NAME: wowmate-app-group
  

jobs:
  build:
    # 실행 환경 설정
    runs-on: ubuntu-latest

    # 차례대로 실행
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up JDK 11
      uses: actions/setup-java@v1
      with:
        java-version: 11
    
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    # Gradle build (Test 제외)
    - name: Build with Gradle
      run: ./gradlew clean build -x test
      
    # 압축 파일 만들기
    - name: Make Zip File
      run: zip -qq -r ./$GITHUB_SHA.zip .
      shell: bash
      
    # AWS 인증
    - 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: ap-northeast-2
      
    # S3 버킷으로 파일을 업로드
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

    # S3 버킷에 업로드 된 파일을 대상으로 CodeDeploy에서 배포 요청
    - 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=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

위에서부터 차례로 살펴보겠다

name: Build and Deploy for WOWMATE server to AWS EC2

# Event Trigger
on:
  push:
    branches: [ deploy ]
#  pull_request:
#    branches: [ deploy ]

name 부분은 workflow의 이름이다
on 은 해당 이벤트가 발생하면 workflow가 실행된다는 것을 알려준다
위의 예시에서는 deploy 브랜치에 commit이 push되면 workflow가 실행된다

env:
  # 버킷에 저장할 폴더 이름
  PROJECT_NAME: WOWMATE_Server
  # S3 버킷 이름
  BUCKET_NAME: wowmate-server-github-action-s3-bucket
  # CodeDeploy의 애플리케이션 이름
  CODE_DEPLOY_APP_NAME: wowmate-app
  # CodeDeploy의 배포그룹 이름
  DEPLOYMENT_GROUP_NAME: wowmate-app-group

env 부분에서는 해당 workflow에서 사용될 변수를 설정한다

jobs:
  build:
    # 실행 환경 설정
    runs-on: ubuntu-latest

    # 차례대로 실행
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up JDK 11
      uses: actions/setup-java@v1
      with:
        java-version: 11
    
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    # Gradle build (Test 제외)
    - name: Build with Gradle
      run: ./gradlew clean build -x test
      
    # 압축 파일 만들기
    - name: Make Zip File
      run: zip -qq -r ./$GITHUB_SHA.zip .
      shell: bash
      
    # AWS 인증
    - 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: ap-northeast-2
      
    # S3 버킷으로 파일을 업로드
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

    # S3 버킷에 업로드 된 파일을 대상으로 CodeDeploy에서 배포 요청
    - 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=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

위에서 지정한 Event가 발생하면 jobs를 따라 자동 배포가 진행된다


2. GitHub Secrets 값 설정

AWS에 접근하기 위해 AWS IAM에서 사용자 액세스 키를 발급받은 후 GitHub Secrets에 설정해주어야한다

레포지토리 Settings -> Secrets and variables -> Actions -> New repository secret
IAM 사용자의 액세스키와 시크릿키를 설정해준다


3. AppSpec 파일 및 배포 쉘 스크립트 작성

(1) AppSpec 파일 작성

배포를 할 때 사용할 CodeDeploy 애플리케이션 사양 이하 AppSpec 파일을 작성해야 한다 참고

AppSpec 파일은 yaml 형식이고 다음과 같은 역할을 한다

  • 애플리케이션 개정의 소스 파일을 인스턴스의 대상으로 매핑합니다.

  • 배포된 파일에 대한 사용자 지정 권한을 지정합니다.

  • 배포 프로세스의 다양한 단계에서 각 인스턴스에 실행할 스크립트를 지정합니다.

AppSpec 파일은 반드시 소스코드의 루트 디렉토리에 위치시켜야한다

version: 0.0 # version은 반드시 0.0이어야 함
os: linux

files:
  - source: /
    destination: /home/ec2-user/deploy
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ec2-user

작성 후 다음과 같이 위치시킨다

(2) 배포 쉘 스크립트 작성

# stop.sh

PROJECT_ROOT="/home/ec2-user/app"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"

DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)

# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
  echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
  echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
  kill -15 $CURRENT_PID
fi
# start.sh

PROJECT_ROOT="/home/ec2-user/deploy"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"

APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
source ~/.bashrc
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG

4. 배포 확인

이후 deploy 브랜치에 push가 되면 Actions에서 workflow가 실행되는 것을 볼 수 있다

성공적으로 build가 되었으면 S3 버킷에 빌드 파일이 압축되어 올라가고 CodeDeploy를 통해 서버가 배포되는 것을 확인할 수 있다

쉘 스크립트를 통해 로그파일들을 생성했으므로 배포시 에러가 생기면 error.log를 확인하면 된다



지금까지 GitHub Actions를 통한 자동배포에 대한 레퍼런스를 알아보았다 여기까지 진행하면서 수많은 시행착오를 겪었구...^^ 역시 AWS만으로 배포하는 것은 넘 어려웠기에 Docker의 필요성을 느꼈다 흑
다음에는 Docker를 이용한 배포와 https 인증에 대한 글을 써보겠다! 아됴스

profile
핸수

0개의 댓글