본문 바로가기

항해99

23.11.11 항해 99 16기 실전 프로젝트 34일차

오늘 공부한 것

* Git Action 및 Code Deploy 정리

 

프로젝트를 진행하다보니 자동배포가 필요한 시점이왔다

고민 끝에 결정한 Git Action 및 Code Deploy 에 대해 정리해보고자 한다

 

1. CI /CD 란 무엇일까?

 1) CI : 개발자를 위한 자동화 프로세스인 지속적인 통합(Continous Intergrantion) 을 의미 즉 Github Action

            Code - Build -Test 단계에서 꾀할 수 있다

       (1) Code : 개발자가 코드를 원격 저장소 (Ex. GitHub Repository) 에 push 하는 단계

       (2) Build : 원격 코드 저장소로부터 코드를 가져와 유닛 테스트 후 빌드하는 단계

       (3) Test : 코드 빌드의 결과물이 다른 컴포넌트와 잘 통합되는지 확인하는 과정

 

이 과정에서 개발자는 코드를 잦게 원격 코드 저장소에 push 하고, 테스트 및 빌드를 하며 빌드 결과를 통해 빌드가

성공했는지 실패했는지 확인하고, 통합 테스트 결과를 통해 개선방안을 찾게 된다

    -> 지속적 통합이 적용된 개발팀은 코드 머지 전 이미 코드 오류나 테스트 오류를 확인하여 훨씬 더 효율적인 개발이

        가능하다

 

 2) CD : 지속적인 서비스 제공(Continuous Delivery) 및 지속적인 배포(Conitnuous Deployment)를 의미 하며 이 두용어는

             상호 교환적으로 사용된다 즉 Code Deploy

              Release - Deploy - Operate 단계에서 꾀할 수 있다

       (1) Release : 배포 가능한 소프트웨어 패키지 작성

       (2) Deploy : 프로비저닝을 실행하고 서비스를 사용자에게 노출함, 실질적 배포 부분

                          * 프로비저닝 : 특정 서비스를 제공 받기 위해 서비스 실행부터 시작해 서비스를 제공 받기 전 단계까지

                                                  처리되는 일련의 절차

       (3) Operate : 서비스 현황을 파악하고 생길 수 있는 문제 감지

 

CD 의 경우 코드 변경 사항의 병합부터 프로덕션에 적합한 빌드 제공에 이르는 모든 단계로 테스트 자동화와 코드 배포

자동화가 포함된다

    -> 이 프로세스를 완료하면 프로덕션 준비가 완료된 빌드를 코드 리포지토리에 자동으로 배포할 수 있기 때문에

        운영팀이 보다 빠르고 손쉽게 애플리케이션 프로덕션으로 배포할 수 있게 된다

 

2. CI / CD 파이프 라인이란?

    배포 과정을 자동화 시키는 방법을 구축하는 것

    1) Source 단계 : 원격 저장소에 관리되고 있는 소스 코드에 변경 사항이 일어날 경우 이를 감지하고 다음 단계로

                               전달하는 작업 수행

    2) Build 단계 : Source 단계에서 전달받은 코드를 컴파일, 빌드, 테스트하여 가공한다. 또한 Build 단계를 거쳐 생성된

                           결과물을 다음 단계로 전달하는 작업 수행

    3) Deploy 단계 : Build 단계로부터 전달받은 결과물을 실제 서비스에 반영하는 작업 수행

 

3. 기술 결정

 1) 선택지

     (1) Github Action

           a) 장점

               (a) Github 와의 기본 통합

               (b) 간단하고 직관적인 사용자 인터페이스로 설정 및 사용이 쉽다

               (c) 모든 환경에서 호환됨

           b) 단점

               (a) 클라우드 기반 도구이기 때문에 대규모 프로젝트의 확장성에 제한

               (b) 레퍼런스가 부족

     (2) Jenkins

           a) 장점

               (a) 많은 플러그인을 지원하고 커스터마이징이 다양하다

               (b) 많은 사용자를 보유하고 있고 관련 문서가 많다

               (c) 호스팅을 직접하기 때문에 모든 부분을 관리할 수 있다

          b) 단점 

               (a) 규모가 작은 프로젝트의 경우 설정하는데 리소스 낭비 발생

               (b) 호스팅을 직접해야하기 때문에 서버 운영 및 관리 비용 발생

               (c) 환경 호환성을 위해 Docker 사용이 필요

 2) 결정

      Github Action / Code Deploy

 3) 이유

     (1) 빌드과정을 쉽게 볼 수 있으며 오류도 쉽게 확인이 가능하다

     (2) Github 와의 연동이 편하다 Pull request 이후 Merge 될 때 동작하도록 구성이 편함

     (3) 민감 정보를 Secret 을 이용하여 손쉽게 관리할 수 있다

     (4) Code Deploy 의 경우 현 프로젝트에서 AWS 의 EC2, S3, RDS 를 사용하므로 함께 사용하기 편함

 

4. Github Action 이란?

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

 2) 레포지토리에서 Pull Request 나 push 같은 이벤트를 트리거로 Workflows 를 구성할 수 있다

     (1)  Workflows 

            .yml 또는 .yaml 파일에 의해 구성되며 테스트, 배포 등 기능에 따라 여러개를 만들 수도 있으며 생성된

            Workflows 는 .github/workflows 디렉토리에 위치한다

 3) 비공개 레포지토리의 경우 Github Actions 가 작동할 때의 용량과 시간제한이 있으나 공개 레포지토리는 무료로 

     사용가능

 

5. Github Action 을 이루는 요소들

 1) Worklows

     여러 Job 으로 이루어진 하나의 프로세스이다 예를 들어서 테스트 & 빌드 Worklows 나 배포 Worklows 를 만들어서

      순서대로 실행시킬 수 있다

 2) Events 

     레포지토리에서 PR이 들어왔거나 Issue 생성 등을 말하는데 이런 특정 이벤트들이 발생했을 때 특정 Worklows 가

     실행되게 할 수 있다 우리 코드에서는 PR 후 Merge 되었을 때 동작하게 설정되었다

 3) Jobs

      Worklows 에 정의된 하나의 스탭이다 Sell script 를 실행하는 Job 일 수도 있고 특정 Action 을 실행하는 Job

      일 수도 있다

 4) Actions

     Github Actions 플랫폼에 맞게 만들어진 애플리케이션이다 쉽게 예를 든다면 크롬과 크롬 확장 프로그램의 관계와

     비슷하다고 할 수 있다. 내가 직접 만들수도 있고 Marketplace 에서 이미 만들어 진것을 찾아 쓸 수 있다.

 5) Runner

     지금 까지 설명에서 Github Action 은 컴퓨터에서 돌아가는 프로그램과 같은 것인데 컴퓨터는 어떻게 동작한다는

     이야기가 없었다 Runner 가 바로 그 컴퓨터 이다 Ubuntu, window, mac 등 에서 OS 를 선택할 수 있고 거기에 맞게

     돌아가는 가상 머신 또는 가상 서버이다     

 

6. 우리 프로젝트에 적용된 것

참고 블로그

https://velog.io/@juhyeon1114/%EC%8B%A4%EC%A0%84-Github-actions-AWS-Code-deploy%EB%A1%9C-Spring-boot-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0

 

실전! Github actions, AWS Code deploy로 Spring boot 배포 자동화하기

아휴 힘드러 🤮

velog.io

 

환경 세팅 과 Code Deploy 세팅은 위의 블로그를 참고했다

중요한 것은 아래 3가지 이므로 자세히 알아보자

 

1. workflows 작성 main.yml

    민감한 정보는 레포지토리의 Settings -> Secrets and variables -> Actions 를 통해 등록가능

// workflows 의 이름
name: Gallae

// Trigger
// develop2 브랜치에 pull request 이후 merge 가 되었을 때 동작하게 만듬
on:
  pull_request:
    branches: [ "develop2"]
    types:
      - closed
      
// 변수기입
env:
  AWS_REGION: ${{ secrets.AWS_REGION }}
  S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
  CODE_DEPLOY_APPLICATION_NAME: test
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: test-group

permissions:
  contents: read

// 어떻게 실행할 것인지
jobs:
  deploy:
    name: Deploy
    // Runner 가 실행되는 환경 정의
    runs-on: ubuntu-latest
    environment: production

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

    - uses: actions/checkout@v3
    - run: touch ./src/main/resources/application-server.properties
    - run: echo "${{secrets.APPLICATION}}" > ./src/main/resources/application-server.properties
    - run: cat ./src/main/resources/application-server.properties

     # gradlew 실행 권한 부여
    - name: Run chmod to make gradlew executable
      run: chmod +x gradlew

    - name: Build with Gradle
      uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
      with:
        arguments: clean build -x test

    # 빌드해서 생긴 JAR 파일을 깃허브 아티팩트로 업로드!!
    - name: Upload build artifact
      uses: actions/upload-artifact@v2
      with:
        name: team2project
        path: build/libs/team2project-0.0.1-SNAPSHOT.jar

    # AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.CICD_ACCESS_KEY}}
        aws-secret-access-key: ${{ secrets.CICD_SECRET_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}

    # 빌드 결과물을 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 .

    # 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. appspec.yml 작성

version: 0.0

# Deploy 대상 서버의 운영체제를 표시
os: linux

# 코드 파일 전송과 관련된 설정
files:
  # 코드 파일의 소스 경로
  - source: /
    # 코드 파일의 대상 경로 -> /home/ubuntu/app 디렉토리로 파일을 복사한다.
    destination: /home/ubuntu/app
    # 대상 경로에 이미 파일이 존재하는 경우, 덮어쓰기를 허용할지 여부
    overwrite: yes

# 파일 및 디렉토리 권한에 관련된 설정
permissions:
  # 권한을 설정할 대상 경로
  - object: /
    # 모든 파일 및 디렉토리를 의미
    pattern: "**"
    # 파일 및 디렉토리의 소유자를 ec2-user로 설정
    owner: ubuntu
    # 파일 및 디렉토리의 그룹을 ec2-user로 설정
    group: ubuntu

# Deploy 전후에 실행할 스크립트 또는 명령에 관련된 설정
hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ubuntu
  # 애플리케이션 시작시 실행할 스크립트 또는 명령에 관련된 설정
  ApplicationStart:
    # 실행할 스크립트 또는 명령의 위치
    - location: scripts/start.sh
      # 스크립트 또는 명령 실행의 제한 시간을 설정
      timeout: 60
      # CodeDeploy 중 실행되는 스크립트 또는 명령을 실행할 사용자를 지정
      runas: ubuntu
      #

    

3. 실행 정지 script 작성

 1) 실행

#!/usr/bin/env bash

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

# 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) 정지

#!/usr/bin/env bash

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