GitHub Actions - 3. CD를 위한 Workflow 생성

Kim, Beomgoo·2022년 10월 7일
0

CI/CD

목록 보기
4/5

이전 포스트에서 GitHub ActionsAWS CodeDeploy를 통해 배포를 자동화하기 위해 여러 설정들을 하는 과정을 거쳤다.
이번 포스트에서는 Workflow를 생성하여 실제 배포 자동화가 작동하기까지의 과정을 진행해 볼 것이다.

1. GitHub Repository Secrets 생성

앞서 만들었던 IAM 사용자액세스 키 ID비밀 액세스 키는 public으로 노출되면 안 된다. 하지만 GitHub Actions를 이용하기 위한 Workflow는 레포지토리에 올라가게 된다면 public이 되기 때문에, Secrets로 따로 입력하는 방법을 이용해야 한다.
레포지토리의 Settings -> Secrets -> Actions로 들어가 New repository secret으로 들어간다.

각각 대응하는 secrets값을 만들어 준다.

2. CodeDeploy 관련 파일 작성

2.1. AppSpec 파일 작성

CodeDeploy에서 EC2 인스턴스를 통해 배포를 진행할 때 참조하는 파일이 바로 AppSpec 파일이다. AppSpec 파일은 appspec.yml프로젝트의 최상단 디렉토리 아래에 위치해야 한다.

version: 0.0
os: linux

files:
  - source: /
    destination: /home/ubuntu/app/deploy
file_exists_behavior: OVERWRITE

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

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

2.2. Script 작성

위에서 작성한 AppSpec 파일에 따라, CodeDeploy의 라이프사이클 중 AfterInstall 시에 stop.sh 파일이, ApplicationStart 시에 start.sh 파일이 실행된다. 프로젝트의 최상단 디렉토리 아래에 scripts 디렉토리를 생성하고, 그 아래에 stop.sh 파일과 start.sh 파일을 작성하자.

  • stop.sh
    stop.sh는 새로운 배포가 진행되기 전, 기존에 실행 중인 빌드를 종료하는 역할을 한다.
PROJECT_ROOT="/home/ubuntu/app/deploy"		# 여기서는 배포할 프로젝트가 위치할 디렉토리
JAR_FILE="$PROJECT_ROOT/spring-project.jar"	# 배포할 프로젝트가 빌드된 jar 파일

DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

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/ubuntu/app/deploy"
JAR_FILE="$PROJECT_ROOT/spring-project.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
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &

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

2.3. build.gradle 파일 수정

아래 내용을 추가한다. 이유는 링크 참조.

jar {
    enabled = false
}

3. GitHub Actions Workflow 작성

첫번째 포스트와 마찬가지로 .github/workflows/ 아래에 deploy.yml 파일을 생성한다.

name: Deploy

on:
  push:
    branches: [ main ]    # main 브랜치에 push 시 실행

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: bamboo-action-prac					# 생성한 S3 버킷 이름
  CODE_DEPLOY_APPLICATION_NAME: github-action-prac		# CodeDeploy 어플리케이션 이름
  CODE_DEPLOY_GROUP_NAME: github-action-prac-group		# 배포 그룹 이름

jobs:
  build_deploy:
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v3

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

        # Gradle Wrapper 권한 부여
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

        # Gradle을 통해 프로젝트를 빌드한다
      - name: Build Project
        run: ./gradlew clean build -x test

        # 하위 디렉토리 생성
      - name: Make Directory
        run: mkdir deploy

        # JAR 파일 복사
      - name: Copy Jar File
        run: cp ./build/libs/*.jar ./deploy/

        # JAR 디렉토리 -> ZIP
      - name: Zip Directory
        run: zip -r -qq -j ./spring-project.zip ./deploy

        # AWS Credentials
      - 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: ${{ env.AWS_REGION }}

        # S3 Bucket으로 업로드
      - name: Upload Zip File to S3 Bucket
        run: |
          aws deploy push \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --ignore-hidden-files \
          --s3-location s3://${{ env.S3_BUCKET_NAME }}/spring-project.zip \
          --source .
          

        # Deploy
      - name: Deploy
        run: |
          aws deploy create-deployment \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --deployment-group-name ${{ env.CODE_DEPLOY_GROUP_NAME }} \
          --file-exists-behavior OVERWRITE \
          --s3-location bucket=${{ env.S3_BUCKET_NAME }},bundleType=zip,key=spring-project.zip \

4. Push 후 자동 배포 확인

4.1. Deploy Workflow 확인

Push 후 레포지토리의 actions를 확인해 보면 다음과 같이 workflow가 진행되어 성공한 것을 볼 수 있다.

레포지토리 메인 브랜치의 커밋 왼쪽에 초록색 체크 표시로 workflow가 성공했다는 것을 알려주고 있다.

주의할 점은 GitHub 레포지토리의 actions만으로 배포가 성공적으로 끝났다는 것은 아니다. 필자가 실제로 경험한 것인데, 현재 작성한 workflow 상으로는 CodeDeploy에 배포 추가가 성공적으로 이뤄졌는지만 확인할 수 있지, CodeDeploy를 통해 프로젝트가 EC2 인스턴스 위에서 실제로 실행되어 배포되는지는 알 수 없기 때문이다. 따라서 직접 AWS CodeDeploy 대시보드와 인스턴스를 통해 실제 배포를 확인하거나, 로직을 추가적으로 보완해 이 또한 actions에서 알 수 있는지 확인할 수 있게 해야 한다.

4.2. S3 버킷 업로드 확인

아래와 같이 빌드한 프로젝트 파일이 압축되어 버킷에 성공적으로 업로드된 것을 확인할 수 있다.

4.3. CodeDeploy 배포 확인

CodeDeploy의 대시보드에서 어플리케이션의 배포 내역을 확인할 수 있다. 만약 실패했다면 어떤 단계에서 어떤 이유로 실패했는지 확인할 수 있다.

4.4. 인스턴스 확인

프로젝트가 위치한 디렉토리를 보면 아래와 같이 프로젝트 디렉토리와 파일들이 잘 있는 것을 확인할 수 있다.

start.sh를 통해 어플리케이션에서 생성하는 로그를 확인해 보면 성공적으로 실행되어 배포 중인 것을 확인할 수 있다.

4.5. 서비스 확인

서버에 요청을 해 보면 정상적으로 응답을 하는 것을 확인할 수 있다.

참고 자료

profile
하나에 하나를 보탠다

0개의 댓글