이번 포스팅에는 특정 브랜치에 commit이 push 되면 서버가 자동으로 재배포 되는 GitHub Actions를 설정해보겠다
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를 따라 자동 배포가 진행된다
AWS에 접근하기 위해 AWS IAM에서 사용자 액세스 키를 발급받은 후 GitHub Secrets에 설정해주어야한다
레포지토리 Settings -> Secrets and variables -> Actions -> New repository secret
IAM 사용자의 액세스키와 시크릿키를 설정해준다
배포를 할 때 사용할 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
작성 후 다음과 같이 위치시킨다
# 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
이후 deploy 브랜치에 push가 되면 Actions에서 workflow가 실행되는 것을 볼 수 있다
성공적으로 build가 되었으면 S3 버킷에 빌드 파일이 압축되어 올라가고 CodeDeploy를 통해 서버가 배포되는 것을 확인할 수 있다
쉘 스크립트를 통해 로그파일들을 생성했으므로 배포시 에러가 생기면 error.log를 확인하면 된다
지금까지 GitHub Actions를 통한 자동배포에 대한 레퍼런스를 알아보았다 여기까지 진행하면서 수많은 시행착오를 겪었구...^^ 역시 AWS만으로 배포하는 것은 넘 어려웠기에 Docker의 필요성을 느꼈다 흑
다음에는 Docker를 이용한 배포와 https 인증에 대한 글을 써보겠다! 아됴스