이전 포스트에서 GitHub Actions와 AWS CodeDeploy를 통해 배포를 자동화하기 위해 여러 설정들을 하는 과정을 거쳤다.
이번 포스트에서는 Workflow를 생성하여 실제 배포 자동화가 작동하기까지의 과정을 진행해 볼 것이다.
앞서 만들었던 IAM 사용자의 액세스 키 ID와 비밀 액세스 키는 public으로 노출되면 안 된다. 하지만 GitHub Actions를 이용하기 위한 Workflow는 레포지토리에 올라가게 된다면 public이 되기 때문에, Secrets로 따로 입력하는 방법을 이용해야 한다.
레포지토리의 Settings -> Secrets -> Actions로 들어가 New repository secret으로 들어간다.
각각 대응하는 secrets값을 만들어 준다.
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
위에서 작성한 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
build.gradle
파일 수정아래 내용을 추가한다. 이유는 링크 참조.
jar {
enabled = false
}
첫번째 포스트와 마찬가지로 .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 \
Push 후 레포지토리의 actions를 확인해 보면 다음과 같이 workflow가 진행되어 성공한 것을 볼 수 있다.
레포지토리 메인 브랜치의 커밋 왼쪽에 초록색 체크 표시로 workflow가 성공했다는 것을 알려주고 있다.
주의할 점은 GitHub 레포지토리의 actions만으로 배포가 성공적으로 끝났다는 것은 아니다. 필자가 실제로 경험한 것인데, 현재 작성한 workflow 상으로는 CodeDeploy에 배포 추가가 성공적으로 이뤄졌는지만 확인할 수 있지, CodeDeploy를 통해 프로젝트가 EC2 인스턴스 위에서 실제로 실행되어 배포되는지는 알 수 없기 때문이다. 따라서 직접 AWS CodeDeploy 대시보드와 인스턴스를 통해 실제 배포를 확인하거나, 로직을 추가적으로 보완해 이 또한 actions에서 알 수 있는지 확인할 수 있게 해야 한다.
아래와 같이 빌드한 프로젝트 파일이 압축되어 버킷에 성공적으로 업로드된 것을 확인할 수 있다.
CodeDeploy의 대시보드에서 어플리케이션의 배포 내역을 확인할 수 있다. 만약 실패했다면 어떤 단계에서 어떤 이유로 실패했는지 확인할 수 있다.
프로젝트가 위치한 디렉토리를 보면 아래와 같이 프로젝트 디렉토리와 파일들이 잘 있는 것을 확인할 수 있다.
start.sh를 통해 어플리케이션에서 생성하는 로그를 확인해 보면 성공적으로 실행되어 배포 중인 것을 확인할 수 있다.
서버에 요청을 해 보면 정상적으로 응답을 하는 것을 확인할 수 있다.