Git Actions를 통한 CI/CD pipeline 구축

bagt13·2024년 8월 6일
0

AWS

목록 보기
5/6

GitHub Actions란?

Github가 공식적으로 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼

repository에서 PR이나 push 같은 이벤트(event)를 트리거(trigger)로 github 작업 workflow를 구성할 수 있다. workflow는 하나 이상의 작업이 실행되는 자동화 프로세스로, 각 작업은 자체 가상 머신 또는 컨테이너 내부에서 실행된다.

workflow는 yml파일에 의해 구성되며, 테스트, 배포 등 기능에 따라 여러 개의 workflow도 만들 수 있다. 생성된 workflow는 .github/workflows 디렉토리 이하에 위치한다.


배포 Flow

  • 설정 파일(.yml)에 명시된 특정 branch로의 push를 trigger로 Github Actions가 실행되도록 구성한다.

주의 사항

  • Pulbic Repository여야 무료로 사용할 수 있다.
  • AWS CLICode Deploy Agent가 EC2에 설치되어 있어야 한다.
  • S3 버킷이 생성되어 있어야 한다.

리소스 설정하기

Github Actions 생성하기

  1. 프로젝트 repository -> Actions로 이동해 workflow를 설정한다.

set up a workflow yourself 를 클릭하여 빈 yml 설정파일로 workflow를 설정할 수 있고, 추천 workflow 구성(Java with Gradle 등)을 선택하여 진행할 수 있다.

  1. set up a workflow yourself로 workflow를 생성하면, main.yml 파일이 생성됨과 동시에 workflow에 작성되어있는 trigger(특정 branch로의 push)로 인해 Github Actions가 실행된다.

Actions 탭에서 생성된 workflow의 각 단계별 진행 상황을 확인할 수 있으며, 진행/성공/실패 여부는 repository에서 최근 commit 내역과 함께 표시된다.


Github Actions 수정

이번엔 생성한 S3 버킷에 프로젝트 빌드 결과물을 전송해야 한다.

Github Actions에서 workflow를 실행하는 과정에서 access key가 필요하지만, 공개되면 보안 이슈가 발생할 수 있다. 따라서 Github Secret을 이용해 access key 값을 저장한 후 사용한다.

1. Github Secret 등록하기

1-1. Repository -> Settings > Secrets > Actions 탭으로 이동한 후 New repository secret를 클릭한다.

1-2. Name-Value에 IAM User 생성 시 볼 수 있는 Access Key ID 값과, 비밀 access key 값을 각각 저장합니다.

  • 이는 gradle.yml에서 secret 변수를 불러오는 부분과 연결된다.

2. Github Action 설정 파일 수정하기

설정한 Secret을 반영하기 위해 기존의 gradle.yml 파일에 하단에 다음 코드를 추가한다.

main.yml

name: Backend CICD
run-name: Running
on:
  push:
    branches:
      - sungmin

env:  #env를 통해 자주 사용할 변수를 지정한다.
  AWS_REGION: ap-northeast-2
  AWS_S3_BUCKET: moim-image
  AWS_CODE_DEPLOY_APPLICATION: mogether-cd
  AWS_CODE_DEPLOY_GROUP: mogether-cd-group

jobs:
  build-with-gradle:
    runs-on: ubuntu-latest
    
    steps:
    - name: sungmin branch로 이동
      uses: actions/checkout@v3
      with:
        ref: sungmin
    - name: Install JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'corretto'
    
    # gradlew 파일이 있는 곳으로 이동 후 명령을 실행한다.
    - name: gradlew에 실행 권한 부여
      run: cd backend/mogether && chmod +x ./gradlew
    - name: Build with Gradle
      run: cd backend/mogether && ./gradlew clean build
      
    # 디렉토리 생성
    - name: Make Directory
      run: mkdir -p deploy
        
    # Jar 파일 복사
    - name: Copy Jar
      run: cp backend/mogether/build/libs/moim-0.0.1-SNAPSHOT.jar ./deploy
      
    # appspec.yml 파일 복사
    - name: Copy appspec.yml
      run: cp backend/mogether/appspec.yml ./deploy
      
    # script files 복사
    - name: Copy script
      run: cp backend/mogether/scripts/start.sh ./deploy
      
    - name: Make zip file
      run: zip -r ./mogether.zip ./deploy
      shell: bash

	# 등록한 ACCESS/SECRET KEY를 사용하기 위해 변수 등록
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-region: ${{ env.AWS_REGION }}
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}


    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./mogether.zip s3://$AWS_S3_BUCKET

build 파일 배포 및 실행

프로젝트의 빌드 결과와 배포에 필요한 script를 S3 버킷에 업로드했고, 이제 CodeDeploy를 통해 S3의 파일을 EC2로 배포하는 과정을 진행한다.

CodeDeploy 설정

  1. CodeDeploy -> 배포 -> 애플리케이션 생성을 클릭한다.

  2. 애플리케이션 이름을 작성하고, 컴퓨팅 플랫폼은 EC2/온프레미스를 선택한다.

    애플리케이션 이름의 경우 Github Actions workflow에 작성할 것이기 때문에 규칙에 맞게 작성해야 한다.

  3. 생성 완료 후, 배포 그룹을 생성한다.

    배포 그룹은 방금 전 생성한 애플리케이션에 생성되어야 하며, 배포 그룹 이름 역시 Github Actions workflow에 작성이 필요하기 때문에, 애플리케이션과 구분할 수 있도록 규칙에 맞게 이름을 작성해야 한다.

    CodeDeploy 의 권한 부여를 위한 IAM 역할을 생성되어있다면 선택하면 되고, 없다면 생성 후 선택한다.

  4. 환경 구성 파트에서는 EC2 인스턴스 태그를 이용해 배포 그룹 환경을 구성한다.


.yml 파일 설정

  1. 프로젝트 디렉토리 root 경로에 appspec.yml 파일을 생성한다. (Code Deploy의 작동과 연결)

❗️ appspec.yml의 위치

하지만 프로젝트 구조에 따라 appspec.yml을 다른 곳에 위치시키고, main.yml에서 올바른 appspec.yml의 위치를 명시해주기만 해도 상관 없다.

나는 협업 프로젝트이기 때문에 /backend/mogether 하위에 위치시켰다. (build.gradle과 같은 위치)

(꼭 프로젝트의 root에 위치시켜야 한다는 글이 너무 많아서 많이 헤맸다😭)


appspec.yml

version: 0.0
os: linux

files:
  - source:  /
    destination: /home/ubuntu/app/   #이 위치에 복사한 파일들을 둘 예정이다.
    overwrite: yes

permissions:
  - object: /home/ubuntu/app/   #이 위치에 복사한 파일들을 둘 예정이다.
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: start.sh
      timeout: 60
      runas: ubuntu
  1. 마찬가지로 /backend/mogether 위치에 scripts 디렉토리를 생성한 후 scripts 아래에 start.sh 파일을 생성한다. (EC2 배포 진행 상황 별 로그를 기록하고 새로 배포된 빌드 파일을 실행한다)

여기서도 삽질을 많이 했는데, main.yml에서 start.sh 파일만을 복사하도록 명시했기 때문에 결국 다른 복사한 파일들과 동일한 곳에 위치하게 된다. (/home/ubuntu/app)

따라서 location에는 그냥 start.sh 라고만 명시해주면 된다.


start.sh

#!/usr/bin/env bash

REPOSITORY=/home/ubuntu/app
JAR_NAME=$(ls -tr $REPOSITORY/*SNAPSHOT.jar | tail -n 1)

echo "> 현재 구동 중인 애플리케이션 pid 확인"

# CURRENT_PID=$(pgrep -fla java | grep hayan | awk '{print $1}' | pgrep -f $JAR_NAME)
CURRENT_PID=$(pgrep -f $JAR_NAME)

echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID" >> /home/ubuntu/app/deploy.log

if [ -z "$CURRENT_PID" ]; then
  echo "현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ubuntu/app/deploy.log
else
  echo "> kill -15 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

echo "> 새 애플리케이션 배포" >> /home/ubuntu/app/deploy.log

JAR_NAME=$(ls -tr $REPOSITORY/*SNAPSHOT.jar | tail -n 1)

echo "> JAR NAME: $JAR_NAME"

echo "> $JAR_NAME 에 실행권한 추가" >> /home/ubuntu/app/deploy.log

chmod +x $JAR_NAME

echo "> $JAR_NAME 실행" >> /home/ubuntu/app/deploy.log

nohup java -jar -Duser.timezone=Asia/Seoul $JAR_NAME >> $REPOSITORY/nohup.out 2>&1 &
  • 현재 실행중인 application의 PID를 찾고 중지시킨 뒤, 새로운 jar 파일을 실행시킨다.
  • 배포 log는 /home/ubuntu/app/deploy.log 파일에 저장된다.

Github Actions - Code Deploy 연결하기

이제 모든 환경 세팅이 완료되었고, Github Actions workflow를 수정하여 배포 자동화를 구성한다. main.yml 하단에 Code Deploy 배포 명령을 추가하면 된다.

main.yml 하단에 CodeDeploy 배포 명령 추가

# CodeDeploy에게 배로 명령을 내린다.
    - name: 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=${{ env.AWS_S3_BUCKET }},bundleType=zip,key=mogether.zip

CodeDeploy 설정하며 작성한 CodeDeploy 애플리케이션의 이름, CodeDeploy 배포 그룹의 이름을 표시된 곳에 각각 작성한다.


배포 결과 및 로그 확인하기

1. 배포 결과 확인하기

EC2 터미널을 통해 main.yml에 작성한대로 /home/ubuntu/app 디렉토리 내에 빌드 파일이 이동했고, ps -ef | grep java로 해당 빌드 파일이 실행 중인지 확인할 수 있다.


배포 성공 확인

2. 배포 로그 확인하기

  • start.sh에는 배포가 진행될 때마다 상황을 기록하도록 작성 되어있다.

  • 배포를 마치면 /home/ubuntu/app 디렉토리 내에 로그가 기록된 deploy.log 파일에 배포 상황이 기록된다.


🟢 CodeDeploy 사용에 필요한 정보

CodeDeploy 배포에 사용된 파일 확인

cd /opt/codedeploy-agent/deployment-root/{deployment-group-id}/{deployment-id}/deployment-archive

CodeDeploy 배포 log 확인

/var/log/aws/codedeploy-agent

CodeDeploy-Agent 실행 여부 확인 및 재시작

sudo service codedeploy-agent status
sudo service codedeploy-agent restart

❗️IAM User를 등록하지 않았다면, 등록 후 꼭 CodeDeploy-Agent를 restart 해줘야 한다.

profile
주니어 백엔드 개발자입니다😄

0개의 댓글