AWS

[AWS] Github Actions 사용하여 EC2에 Spring Boot 배포 자동화하기

NCOOKIE_ 2022. 11. 2. 01:54

지난 글에 작성했던 것처럼 코드를 작성하여 master 브랜치에 push 하면 EC2 인스턴스에서 동작하고 있는 스프링 어플리케이션에 반영되도록 만드려고 한다.

 

자세한 내용들은 아래 블로그에서 친절하게 설명해주고 있어서 여기서는 따라하면서 내가 헷갈렸던 부분을 위주로 언급한다.

 

https://bcp0109.tistory.com/363

 

Github Actions CD: AWS EC2 에 Spring Boot 배포하기

Overview 애플리케이션을 개발하면 외부에서도 접근 가능하도록 클라우드 환경에 배포합니다. 이전에 포스팅 했던 AWS 1편에서는 마지막에 scp 명령어로 로컬에 존재하는 빌드 파일을 EC2 인스턴스

bcp0109.tistory.com

 

작업 순서

 

먼저 해야할 작업들은 아래와 같은데,

 

  1. Github Actions 에서 AWS 에 배포하는 방법
  2. AWS EC2 설정 추가
  3. AWS S3 버킷 생성
  4. AWS CodeDeploy 앱 생성 및 배포 설정
  5. Github Actions 에서 사용할 사용자 권한 추가
  6. AppSpec 파일 작성
  7. 배포 스크립트 작성
  8. Github Actions Workflow 작성
  9. Github 에서 push 로 배포하기

 

6번부터 조금씩 다른 부분들이 있었다. 나는 EC2 인스턴스에 amazon linux를 설치했었기 때문에 설정들이 조금씩 달랐다. username은 우분투의 ubuntu와 다르게 ec2-user이기 때문에 그에 맞게 수정해주었다. 그리고 프로젝트 별로 디렉터리를 만들고 싶어서 해당 값들을 수정해주었다.

 

appspec.yml

version: 0.0
os: linux

# 배포 파일 설정
## source: 인스턴스에 복사할 디렉터리 경로
## destination: 인스턴스에서 파일이 복사되는 위치
## overwrite: 복사할 위치에 파일이 있는 경우 대체
files:
  - source:  /
    destination: /home/ec2-user/apps/spring-practice
    overwrite: yes

# files 섹션에서 복사한 파일에 대한 권한 설정
## object: 권한이 지정되는 파일 또는 디렉터리
## pattern (optional): 매칭되는 패턴에만 권한 부여
## owner (optional): object 의 소유자
## group (optional): object 의 그룹 이름
permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

# 배포 이후에 실행할 일련의 라이프사이클
# 파일을 설치한 후 `AfterInstall` 에서 기존에 실행중이던 애플리케이션을 종료
# `ApplicationStart` 에서 새로운 애플리케이션을 실행
## location: hooks 에서 실행할 스크립트 위치
## timeout (optional): 스크립트 실행에 허용되는 최대 시간이며, 넘으면 배포 실패로 간주됨
## runas (optional): 스크립트를 실행하는 사용자
hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ec2-user

 

start.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ec2-user/apps/spring-practice"
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

 

stop.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ec2-user/apps/spring-practice"
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

 

 

security 파일 자동 업데이트

 

application.properties과 같은 보안과 관련된 파일들은 gitignore에 포함되어 있어 직접 파일 내용을 복사해주거나 할 수 있지만, github action을 사용하여 배포 시 자동으로 업데이트할 수도 있다. IAM 계정의 키값을 등록해준 것처럼, 원하는 보안 파일의 내용을 등록해준다.

 

 

그리고 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: Spring Boot & Gradle CI/CD

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ master ]

# 해당 코드에서 사용될 변수 설정
env:
  AWS_REGION: ap-northeast-2
  PROJECT_NAME: spring-practice
  S3_BUCKET_NAME: ncookie-github-actions-s3-bucket
  CODE_DEPLOY_APP_NAME: codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: codedeploy-deployment-group

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      # create application.properties
      - name: make application-aws.properties
        if: true # branch가 develop일 때
        run: |
          # spring의 resources 경로로 이동
          cd ./src/main/resources
          touch ./application-aws.properties
          # GitHub-Actions에서 설정한 값을 application-dev.properties 파일에 쓰기
          echo "${{ secrets.PROPERTIES }}" > ./application-aws.properties
        shell: bash

      # gradlew 파일 실행권한 설정
      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash

      # Gradle build (Test 제외)
      - name: Build with Gradle
        uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
        with:
          arguments: build

      # 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 }}

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

      # S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
      - name: Deploy to AWS EC2 from S3
        run: |
          aws deploy create-deployment \
            --application-name ${{ env.CODE_DEPLOY_APP_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

 

 

참고 링크

https://bcp0109.tistory.com/363

 

Github Actions CD: AWS EC2 에 Spring Boot 배포하기

Overview 애플리케이션을 개발하면 외부에서도 접근 가능하도록 클라우드 환경에 배포합니다. 이전에 포스팅 했던 AWS 1편에서는 마지막에 scp 명령어로 로컬에 존재하는 빌드 파일을 EC2 인스턴스

bcp0109.tistory.com

https://geonoo.tistory.com/162

 

Spring Boot - Github Action, S3, EC2, CodeDeploy 연동

Github Action을 이용해서 Spring Boot(Gradle) 웹 어플리케이션을 자동으로 빌드해주는 과적을 작성하려고 한다. 매번 build를 하고, 빌드된 jar파일을 EC2 서버에 접근해서 올리는 번거로운 작업이 사라지

geonoo.tistory.com

https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/application-revisions-push.html

 

Amazon S3에 CodeDeploy의 개정 푸시(EC2 온프레미스 배포 전용) - AWS CodeDeploy

push 명령은 애플리케이션 Artifact와 AppSpec 파일을 개정으로 번들링합니다. 이 개정의 파일 형식은 압축된 ZIP 파일입니다. 이 명령은 각각 JSON 형식 또는 YAML 형식의 AppSpec 파일인 개정을 예상하기

docs.aws.amazon.com

https://earth-95.tistory.com/132

 

[SpringBoot 2.5↑] 빌드 시 2가지 jar가 생성되는 현상 (executable jar & plain jar)

들어가기 전에 기존에 쓰던 springboot 2.4.11 버전을 빌드할 때에는 문제가 없었지만, springboot 2.5 버전 이후를 사용하니 빌드 시 jar가 2개 생겨 github action을 통해 진행하는 CD 프로세스가 제대로 작동

earth-95.tistory.com