본문 바로가기

devops

GithubAction과 CodeDeploy를 활용한 CICD:EC2에 SpringBoot 배포-3(Appspec파일 작성,배포 스크립트 작성,github action workflow 작성 및 배포확인)

728x90

Appspec파일 작성

CodeDeploy에서 배포를 위해 참조할 AppSpec파일을 작성해야합니다.

AppSpec파일은 파일에 정의된 hooks를 통해 배포를 관리하는데 사용됩니다.

AppSpec파일은 루트 디렉토리에 위치해야합니다.

AppSpec Refrence

1.appspec.yml 위치

2.appspec.yml 

version: 0.0
os: linux

files:
  - source:  /
    destination: /home/ubuntu/app
    overwrite: yes

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

(1) files(배포 파일 설정)

source: 인스턴스에 복사할 디렉터리 경로
destination: 인스턴스에서 파일이 복사되는 위치
overwrite: 복사할 위치에 파일이 있는 경우 대체

AppSpec files Reference

(2) permissions( files 섹션에서 복사한 파일에 대한 권한 설정)

 object: 권한이 지정되는 파일 또는 디렉터리
 pattern (optional): 매칭되는 패턴에만 권한 부여
owner (optional): object 의 소유자
 group (optional): object 의 그룹 이름

AppSpec Permissions Referece

(3)hooks(배포 이후에 실행할 일련의 라이프사이클)

AfterInstall: 기존에 실행중이던 애플리케이션을 종료(stop.sh)
ApplicationStart: 새로운 애플리케이션을 실행(start.sh)
location: hooks 에서 실행할 스크립트 위치
timeout (optional): 스크립트 실행에 허용되는 최대 시간이며, 넘으면 배포 실패로 간주됨
runas (optional): 스크립트를 실행하는 사용자

AppSpec hooks Reference

 

배포 스크립트 작성

1.Stop.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/spring-webapp.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

이전에 구동되는 애플리케이션이 있으면 종료하는 스크립트입니다.

로그를 deploy.log에 남깁니다.

2.Start.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/spring-webapp.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

빌드 파일에 있는 jar 파일을 복사하여 서버를 구동하는 스크립트입니다.

로그는 deploy.log에 남깁니다.

에러로그는 error.log에 남깁니다.

3.build.gradle파일 수정

jar{
    enabled = false;
}

 

cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE 스크립트에서 libs에 있는 모든 jar파일을 복사하는데 plain.jar 파일이 만들어지지 않도록 build.gradle 파일을 수정합니다. 

Githubaction Workflow 작성

1.Github Repository Secrets 추가

.csv 저장한 IAM 사용자의 ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY키를 저장합니다.

PROPERITES는 application.properties 정보를 저장합니다.

2.Workflow 작성

(1) deploy.yml

name: Deploy to Amazon EC2

on:
  push:
    branches: [ "master" ]
    
# 리전, 버킷 이름, CodeDeploy 앱 이름, CodeDeploy 배포 그룹 이름
env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: yougeun-bucket
  CODE_DEPLOY_APPLICATION_NAME: codedeploy-cicd
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: codedeploy-cicd-deployment-group

permissions:
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    # (1) 기본 체크아웃
    - name: Checkout
      uses: actions/checkout@v3

    # (2) JDK 8 세팅
    - name: Set up JDK 8
      uses: actions/setup-java@v3
      with:
        distribution: 'temurin'
        java-version: '8'
    
    # application.properties 생성
    - name: make application.properties
      run:
        touch ./src/main/resources/application.properties
      shell: bash
      
    # application.properties 내용 추가
    - name: deliver application.properties
      run: echo "${{ secrets.PROPERTIES }}" > ./src/main/resources/application.properties
      shell: bash
    

    # (3) Gradle build
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      
    - name: run test
      uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
      with:
        arguments: test
        
    - name: run build
      uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
      with:
        arguments: clean build -x test

    # (4) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
    - 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 }}

    # (5) 빌드 결과물을 S3 버킷에 업로드
    - name: Upload to AWS S3
      run: |
        aws deploy push \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --ignore-hidden-files \
          --s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
          --source .

    # (6) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
    - name: Deploy to AWS EC2 from S3
      run: |
        aws deploy create-deployment \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --deployment-config-name CodeDeployDefault.AllAtOnce \
          --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
          --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip

(2)Reference

1.Githubactions Reference

2.Githubactions gradle Reference

3.Githubactions aws_credential Reference

4.CodeDeploy Reference

 

Githubaction 배포 확인

 master branch에 push가 일어나면 workflow가 실행됩니다.

1.Repository

2.CodeDeploy

Workflow 실패시 merge 제한

Github Team이나 Organization에 속한 Repository만 가능합니다.

yml 파일에서 작성한 name을 검색하여 설정합니다.

728x90