github action 적용기

Choco·2023년 8월 25일
post-thumbnail

Github action 이란


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

Github action flow



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

프로젝트에 Github action 적용



repository에 action 메뉴를 선택하고 자신의 프로젝트 빌드에 맞는 서비스를 configure 시킨다.

spring은 빌드툴로 gradle을 많이 사용하니 gradle을 configure하면 gradle.yml 파일 작성이 나온다. gradle.yml이 workflow를 위한 설정 파일이다.

gradle.yml

# 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에 배포 생성

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
profile
주니어 백엔드 개발자 입니다:)

0개의 댓글