Github Action으로 자동배포 문제점 해결하기

2023. 3. 15. 01:31·혼자하는 프로젝트/스프링 부트로 구현한 웹

전 글로 Github Action으로 자동배포를 성공했다. 하지만 문제점이 하나 존재할 때, 이 deploy.yml을 사용하면 지금 현재 모든 파일을 EC2에 올려버린다. 그러면 submodule로 만든 보안을 유지해야 하는 정보들 조차 EC2에 올라가 버린다. 이러면 안 되기 때문에 다른 방법을 찾아봤다.

 

목표

목표는 EC2에는 appspec.yml과 .jar파일, start.sh, stop.sh 4개만 올릴 것 이다.

 

CodeDeploy의 행동

  • CodeDeploy는 Zip파일을 받는다. jar 파일은 받지 않는다.
  • EC2에 올리기전 자동으로 zip파일을 압축 해제하고 appspec.yml을 실행한다.
  • 이제 appspec.yml의 코드대로 코드가 수행된다.

 

흐름 이해 

  • github reposiotry에 push를 한다.
  • githubAction에 workflow가 실행된다.
    1. Workflow는 서브 모듈을 확인한다.
    2. 빌드 한다. (jar 파일 생성)
    3. 위의 4개 파일을 zip 한다.
    4. AWS를 인증한다.
    5. S3에 zip 파일 올리기
    6. CodeDeploy에 보내기
  • CodeDeploy에서 zip파일 압축풀기
  • appspec.yml 실행
  • 순서대로 stop.sh, start.sh 실행!!

 

실제 코드

이제 흐름을 이해 했으므로 직접 deploy.yml을 작성해 가면서 구현을 해봤다.

 

deploy.yml

name: Deploy to Amazon EC2

on:
  push:
    branches: [ "main" ]

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: todaysgym-github-actios-s3-bucket
  CODE_DEPLOY_APPLICATION_NAME: todaysgym-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: todaysgym-codedeploy-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 11 세팅
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        distribution: 'temurin'
        java-version: '11'
        
    # (3) 서브 모듈 접근하기
    - name: Checkout repo
      uses: actions/checkout@v3
      with:
        token: ${{ secrets.TOKEN }}
        submodules: true

    # (4) 서브 모듈 변경 점 있으면 update
    - name: Git Sumbodule Update
      run: |
        git pull --recurse-submodules
        git submodule update --remote --recursive

    # (5) gradle 권한 변경
    - name: Run chmod to make gradlew executable
      run: chmod +x ./gradlew

    # (6) Gradle build (Test 제외)
    - name: Build with Gradle
      uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
      with:
        arguments: clean build -x test
	
    # (7) 원하는 파일 Zip 하기
    - name: Zip build file and deploy sh
      run: |
        mv ./build/libs/*.jar ./
        zip buildFile.zip ./appspec.yml ./*.jar ./scripts/start.sh ./scripts/stop.sh

    # (8) 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 }}

    # (9) 빌드 결과물을 S3 버킷에 업로드
    - name: Upload to AWS S3
      run: |
        aws s3 cp \
          --region ap-northeast-2 \
          buildFile.zip s3://$S3_BUCKET_NAME/community-build/

    # (10) 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=community-build/buildFile.zip,bundleType=zip

저번 글의 코드와 거의 비슷하지만 달라진 것은 zip을 하는 부분과 S3에 업로드 하는 부분이다.

s3는 cp를 사용해 복사해서 이동시켰다. 

이렇게 하면 성공적으로 코드가 실행 된다.

 

stop.sh

#!/usr/bin/env bash

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

#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/todaysgym-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)

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar \
-Dspring.profiles.active=main \
$JAR_FILE > $APP_LOG 2> $ERROR_LOG &

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG

여기서 주목해야 할 점은 -Dspring.profiles.active=main이다 자동 배포를 할 때 무조건 main으로 머지 될 겨우에만 EC2에 자동배포된다. 그러므로 profiles를 main으로 설정해줘야 한다. 그 이유는 서브 모듈에서 2개의 yml 파일을 만들 었다. dev 브랜치에서 사용할 yml파일 한개, main 브랜치에서 사용할 yml파일 한개이다. 그러므로 EC2 인스턴스에는 main yml을 받아서 실행해줘야 한다.

 

트러블 슈팅

이렇게 실행을 해도 계속 application-main.yml에 접근을 하지 못했다. 분명 빌드를 하면 config 폴더에 있는 2개의 yml이 src/main/resources에 복사되어야 한다.

이 역할을 해주는 부분이 

task copyGitSubmodule(type: Copy) {
   from './config'
   include '*.yml'
   into 'src/main/resources'
}

build.gradle에 추가한 이 부분이다. 하지만 이 부분이 실행이 안되고 있었다. 구글링을 해보니 한개의 코드가 빠져 있었다.

processResources.dependsOn('copyGitSubmodule')
task copyGitSubmodule(type: Copy) {
   from './config'
   include '*.yml'
   into 'src/main/resources'
}

위의 processResources.dependsOn('copyGitSubmodule')을 추가해줘야 한다.

processResources.dependsOn('copyGitSubmodule')란?
processResources는 빌드 프로세스 중에 실행되는 작업 중 하나이다. 이 작업은 src/main/resources
디렉토리에 있는 파일을 클래스 경로에 복사한다.

dependsOn은 Gradle에서 작업 간의 의존성을 정의하는 방법 중 하나이다.
dependsOn은 processResources작업이 copyGitSubmodule작업에 의존한다는 것을 나타낸다. 즉, processResources 작업이 실행되기 전에 copyGitSubmodule 작업이 선행되어야 다.

결국 main/src/resources/application.yml을 읽으러 가기전에 config에 있는 2개의 yml에 먼저 접근을 안해서 이런문제가 생긴것이다 ㅜㅜ

그래도 하나더 배웠다.

'혼자하는 프로젝트 > 스프링 부트로 구현한 웹' 카테고리의 다른 글

Github Actios를 사용하여 자동배포하기  (0) 2023.03.14
서브모듈을 이용해 application관리하기  (1) 2023.03.12
EC2 서버에 프로젝트 배포하기  (0) 2023.03.12
스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현하기 - 네이버  (0) 2023.03.09
세션 저장소로 데이터베이스 사용하기  (0) 2023.03.09
'혼자하는 프로젝트/스프링 부트로 구현한 웹' 카테고리의 다른 글
  • Github Actios를 사용하여 자동배포하기
  • 서브모듈을 이용해 application관리하기
  • EC2 서버에 프로젝트 배포하기
  • 스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현하기 - 네이버
인프라 감자
인프라 감자
  • 인프라 감자
    삶은 인프라
    인프라 감자
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 클라우드&인프라 (28)
        • 인프라 공부 (4)
        • AWS 구조와 서비스 (18)
        • 클라우드 공부 (4)
        • Terraform (2)
      • AWS Cloud School (13)
        • project (5)
        • Linux, Network (6)
        • Docker (2)
      • BackEnd (162)
        • JAVA 공부 (15)
        • 알고리즘 공부 (71)
        • MySQL 문제 풀기 (8)
        • 스프링 핵심 원리 - 기본편 (18)
        • 스프링 MVC 1편 (4)
        • 자바 ORM 표준 JPA 프로그래밍 (21)
        • 실전! 스프링 부트와 JPA 활용1 (8)
        • 실전! 스프링 부트와 JPA 활용2 (5)
        • 스프링 데이터 JPA (8)
        • Querydsl (4)
      • 혼자하는 프로젝트 (32)
        • 배달의 민족 클론코딩 (7)
        • 나만의 프로젝트 (10)
        • 스프링 부트로 구현한 웹 (15)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Email
    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    linux
    백트래킹
    조합
    중첩 선언
    완전탐색
    상속
    이것이 자바다
    자동 배포
    다이나믹 프로그래밍
    네트워크 기본 용어
    유니온 파인드
    정렬
    프로그래머스
    querydsl
    자바
    VPN
    dp
    스프링 핵심 원리-기본편
    쿼드 압축
    디팬스 게임
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
인프라 감자
Github Action으로 자동배포 문제점 해결하기
상단으로

티스토리툴바