Skip to content

Build CICD pipeline with Github Action ‐3 : AppSpec, shell script, Github Action workflow 파일 작성하기

HaileyKim edited this page Aug 13, 2023 · 1 revision

Build CICD pipeline with Github Action ‐3 : AppSpec, shell script, Github Action workflow 파일 작성하기

Written by Dayeon Kim

전체적인 프로세스

cicdprocess

저번장까지 환경 세팅을 다 했으므로 이번장부터는 배포 자동화 step에 맞도록 파일을 잘 작성해보자


🚀 1. AppSpec.yml

파일 위치 : 프로젝트의 루트 경로
CodeDeploy가 수행할 일들을 지정하는 파일이다
🚨 참고로 프로젝트 파일 안에서 루트가 아니라 repository 자체에서 루트이다.. (이거때문에 고생좀 했음) 스크린샷 2023-08-13 오후 10 17 22

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

✅ source

/ 인 경우 수정버전의 모든 파일이 인스턴스에 복사된다

✅ overwrite

현재 배포 중인 애플리케이션 수정 버전의 파일 버전이 인스턴스에 이미 있는 버전을 대체

✅ destination

인스턴스에서 파일이 복사되어야 하는 위치를 나타낸다 결과 이미지 첨부함
아래와같이 지정한 디렉토리에 복사됨
스크린샷 2023-08-13 오후 8 37 38

✅ object

파일 시스템 객체가 인스턴스로 복사된 이후 지정한 권한이 적용되는 파일 시스템 객체 (파일, 디렉토리,폴더)

✅ hooks (가장 중요)

배포이후에 수행할 스크립트를 지정하는 곳이다
pipeline은 아래와같이 구성된다

스크린샷 2023-08-13 오후 5 46 19

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ubuntu
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ubuntu

🔖 AfterInstall : 파일을 설치한 후 AfterInstall에서 기존에 실행중이던 어플리케이션을 종료시키고 .. →
🔖 ApplicationStart: ApplicationStart에서 새로운 어플리케이션을 실행한다


🚀 2. 배포 스크립트 작성

2-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

2-2. start.sh

실행하는 코드
build 할 JAR파일을 복사하여 nohup으로 실행한다

#!/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

2-3. build.grade 파일 수정

jar {
    enabled = false
}

2-4. build.grade.kts 파일 수정

tasks.getByName<Jar>("jar") {
    enabled = false
}

🚀 3. deploy.yml 파일을 작성해보자

workflow를 지정해주는 파일
GithubAction이 시작하는 파일로 이 파일을 기점으로 앞에서 만들어준 파일들이 실행됨

전체 코드는 아래와 같다

name: Deploy to Amazon EC2

on:
  push:
    branches:
      - feature/21-deploytestbranch

# 본인이 설정한 값을 여기서 채워넣습니다.
# 리전, 버킷 이름, CodeDeploy 앱 이름, CodeDeploy 배포 그룹 이름
env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: pochak-github-actions-s3-bucket
  CODE_DEPLOY_APPLICATION_NAME: pochak-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: pochak-codedeploy-deployment-group

permissions:
  contents: read

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

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

    # (2) JDK 17 세팅
    - name: JDK 17 설치
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'corretto'

    - name: gradlew에 실행 권한 부여
      run: chmod +x ./pochak/gradlew

    - name: init gradle
      run: gradle init

    # (3) Gradle build (Test 제외)
    - name: Build with Gradle
      uses: gradle/gradle-build-action@v1
      with:
        arguments: build
        gradle-version: 8.1.1 

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

에러가 났던 부분이나 중요한 부분 위주로 코드를 살펴보자

3-1. JDK 세팅 부터 Build까지

  • JDK 버전 맞춰주기
  • gradlew 경로를 찾지 못하는 문제에서는 프로젝트 파일로 직접 이동을 시켜줘야 했다

🚨 trouble shooting - 1

Cannot locate a Gradle wrapper properties file at '/home/runner/work/2023-POCHAK-server/2023-POCHAK-server/gradle/wrapper/gradle-wrapper.properties'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.

🤷🏻‍♂️ 해결방법

  • 버전을 명시해주라길래 gradle-version: 8.1.1 로 버전 명시
  • gradle init

🚨 trouble shooting - 2

* What went wrong:
Task 'clean' not found in root project '2023-POCHAK-server'.

🤷🏻‍♂️ 해결방법

  • clean이라는 메서드를 추가적으로 만들어주라고 함...
  • 참고했던 블로그들을 보니 그냥 arguments: build을 하여 해결하신 분들이 많길래 일단 이렇게 작성
  • 차이점을 추가적으로 좀 찾아봐야함

결론적으로 수정한 코드는 아래와 같음
   # (2) JDK 17 세팅
    - name: JDK 17 설치
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'corretto'

    - name: gradlew에 실행 권한 부여
      run: chmod +x ./pochak/gradlew

    - name: init gradle
      run: gradle init

    # (3) Gradle build (Test 제외)
    - name: Build with Gradle
      uses: gradle/gradle-build-action@v1
      with:
        arguments: build
        gradle-version: 8.1.1 

3-2. S3에 업로드

- name: Upload to AWS S3
  run: |
    aws deploy push \
      --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
      --s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
      --ignore-hidden-files \
      --source .

3-3. EC2 배포

- 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

결과
스크린샷 2023-08-13 오후 10 49 24

Clone this wiki locally