Github에서 특정 브랜치에 commit이 되면 빌드,테스트,배포를 자동화 하여 주는 기능이다.

1. 특정 브랜치(main)에 코드 push
2. github action workflow 실행
-> workflow는 여러 Job으로 이루어진 하나의 프로세스이다. yml 파일로 구성되어 있고 아래에서 자세히 알아보자.
3. s3에 빌드된 파일을 업로드 한다
4. Aws Code Deploy를 통해 Ec2에 배포한다
5. Ec2에서 기존 프로세스를 종료하고 새로 배포된 파일을 실행시킨다

repository에 action 메뉴를 선택하고 자신의 프로젝트 빌드에 맞는 서비스를 configure 시킨다.
spring은 빌드툴로 gradle을 많이 사용하니 gradle을 configure하면 gradle.yml 파일 작성이 나온다. gradle.yml이 workflow를 위한 설정 파일이다.
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
branches: [ "master" ]
env:
AWS_REGION: us-east-2
AWS_S3_BUCKET: github-action-code
AWS_CODE_DEPLOY_APPLICATION: githubaction
AWS_CODE_DEPLOY_GROUP: github-action
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: CI서버에 체크아웃
uses: actions/checkout@v3
- name: 자바 17 버전 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: application.yml 설정파일 세팅
run: |
mkdir -p ./src/main/resources
touch ./src/main/resources/application.yml
echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.yml
- name: gradlew 권한 설정
run: chmod +x gradlew
- name: 빌드
run: ./gradlew build
- name: AWS credential 설정
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESSKEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRETKEY }}
- name: S3에 업로드
run: aws deploy push --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --ignore-hidden-files --s3-location s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip --source .
- name: EC2에 배포
run: aws deploy create-deployment --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} --s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip
하나씩 의미를 알아보자.
name: Java CI with Gradle
workflow의 이름이다.
main브랜치에 push를 할거나 pr 들어왔거나 등 다양한 상황에 따라 workflow가 존재할 수 있으므로 이를 구분시켜주기 위해 필요하다.
on:
push:
branches: [ "master" ]
어떤 이벤트가 발생할때 해당 workflow를 실행시킬지에 대한 부분이다. 이 workflow는 "master" 브랜치에 push가 되면 실행된다.
env:
AWS_REGION: us-east-2
AWS_S3_BUCKET: github-action-code
AWS_CODE_DEPLOY_APPLICATION: githubaction
AWS_CODE_DEPLOY_GROUP: github-action
환경 변수 값이다.
jobs:
build:
runs-on: ubuntu-latest
jobs는 workflow에 정의된 하나의 실행 단위 이다. github action은 기본적으로 가상환경에서 빌드 하므로 운영체제를 선택해 주어야 한다. 이 workflow는 ubuntu의 가장 최신 버전 환경에서 빌드 한다.
steps:
- name: CI서버에 체크아웃
- uses: actions/checkout@v3
steps는 job 내부에서 실행되는 단계를 의미하는데 독립된 CI 서버에서 돌아가는 job과 달리, step은 동일한 CI 서버에서 순차적으로 수행된다.
uses는 action을 실행 시킨다. action은 빈번하게 필요한 반복 단계를 재사용하기 용이하도록 GitHub Actions에서 제공되는 일종의 작업 공유 서비스 이다. 자세한건 Github Marketplace를 참고하면 된다.
checkout action은 github에 올린 코드를 CI 서버에 올리고 해당 브랜치로 이동하는 작업이다.
- name: 자바 17 버전 세팅
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
ci서버에 자바를 세팅하는 부분이다. 자바 17버전에 temurin 배포판을 세팅하였다.
- name: application.yml 설정파일 세팅
run: |
mkdir -p ./src/main/resources
touch ./src/main/resources/application.yml
echo "${{ env.APPLICATION }}" > ./src/main/resources/application.yml
repository에는 보안을 위해 application.yml파일을 ignore처리 했으므로 application파일을 세팅 해주었다. APPLICATION은 reposiory setting에 Actions secrets and variables 부분에 넣어 관리 하였다.
- name: gradlew 권한 설정
run: chmod +x gradlew
- name: 빌드
run: ./gradlew build
gradle을 통한 빌드를 위해 권한 설정 및 빌드이다.
- name: AWS credential 설정
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESSKEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRETKEY }}
s3에 업로드와 배포를 위해 권한 설정을 해준다.
- name: S3에 업로드
run: aws deploy push --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --ignore-hidden-files --s3-location s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip --source .
- name: aws code deploy 에 배포 생성
run: aws deploy create-deployment --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} --s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip
s3에 업로드 및 aws code deploy에 배포 생성
gradle.yml을 이용하여 Aws Code Deploy에 배포 생성까지를 완료하였다.CI부분은 끝났지만 CD부분은 아직 진행하지 못하였다. 이제 Aws Code Deploy가 처리해야할 작업에 대한 파일을 작성해야 한다. 루트 경로에 appspec.yml 파일을 만들고 Aws Code Deploy가 해야 할 작업에 대해 작성하자.
appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/face-backend
overwrite: yes
permissions:
- object: /
owner: ubuntu
group: ubuntu
hooks:
ApplicationStop:
- location: scripts/stop.sh
timeout: 60
ApplicationStart:
- location: scripts/start.sh
timeout: 60
files:
- source: /
destination: /home/ubuntu/face-backend
overwrite: yes
모든 폴더를 /home/ubuntu/face-backend 위치에 내려받고 overwrite를 허용한다.
permissions:
- object: /
owner: ubuntu
group: ubuntu
권한을 설정한다. 관리자 계정인 ubuntu로 설정해주었다.
hooks:
ApplicationStop:
- location: scripts/stop.sh
timeout: 60
ApplicationStart:
- location: scripts/start.sh
timeout: 60
hooks는 어떤 작업을 할지 설정하는 부분이다.
현재 파일에선
AfterInstall 단계에 scripts/stop.sh 파일 실행
->기존 어플리케이션 종료
stop.sh
#!/bin/bash
ROOT_PATH="/home/ubuntu/face-backend"
JAR="$ROOT_PATH/application.jar"
STOP_LOG="$ROOT_PATH/stop.log"
SERVICE_PID=$(pgrep -f $JAR) # 실행중인 Spring 서버의 PID
if [ -n "$SERVICE_PID" ]; then
echo "서비스 종료 " >> $STOP_LOG
kill "$SERVICE_PID"
else
echo "서비스 NouFound" >> $STOP_LOG
fi
ApplicationStart 단계에 scripts/start.sh 파일 실행이다.
->갱신된 jar파일을 통해 어플리케이션 실행
start.sh
#!/bin/bash
ROOT_PATH="/home/ubuntu/face-backend"
JAR="$ROOT_PATH/application.jar"
APP_LOG="$ROOT_PATH/application.log"
ERROR_LOG="$ROOT_PATH/error.log"
START_LOG="$ROOT_PATH/start.log"
NOW=$(date +%c)
echo "[$NOW] $JAR 복사" >> $START_LOG
cp $ROOT_PATH/build/libs/portLogistics-1.0.0.jar $JAR
echo "[$NOW] > $JAR 실행" >> $START_LOG
nohup java -jar $JAR > $APP_LOG 2> $ERROR_LOG &
SERVICE_PID=$(pgrep -f $JAR)
echo "[$NOW] > 서비스 PID: $SERVICE_PID" >> $START_LOG