CICD 파이프 라인

김창모·2023년 7월 20일
0

Project

목록 보기
6/13

Intro

지난 국비과정에서 진행한 아주아주 미흡했던 프로젝트를 경험하고서
그때 하지 못한것들을 너무너무 하고싶었다. 그래서 이번에 진행중인 프로젝트를 진행중이기도 하고
그중 하나가 cicd 자동배포 를 완성하는 것이였다.
아무 지식도 없고 aws 프리티어 계정을 만들었다가 월 5천원 미만의 이유모를 돈을 내고 있었는데 이제야 활용해볼수 있게 되었다.

이동욱 님의 springboot with aws 책이 큰 도움이 되었지만 그때와 여러 설정도 다른것같고 어찌어찌 검색과 수많은 시도로 완성하였기에 이를 남기고 싶었다.

구성

전체 과정을 이해하는데도 한참이 걸렸다 모두 처음보는 단어이고 아직도 완벽한 사용법은 모른다.
하지만 무수한 시도끝에 알게된 점들을 공유하고자 한다.

전체 프로세스

  1. 각 팀원이 작업한 내용을 pr 을 날린다.
  2. 현재 pr 은 2개의 approve 가 필요하며 이때 git action 이 동작한다.
  3. 현재 pr 내용에 대해 zip 파일을 만들어 s3 에 업로드 한다.
  4. codedeploy 를 통해 업로드된 s3 버킷에 있는 zip 파일을 ec2 인스턴스에 배포한다.
  5. codedeploy 의 설정파일인 appspec.yml 이 동작하여 스크립트 파일을 실행한다.

전체 과정은 아 이렇구나 할수 있지만 각각 처음보는 스크립트 들을 수정하고 테스트하며 100개가 넘는 pr을 지우고 보내고 반복하였다.
니가이기나 내가 이기나 해보자
각각 과정에 대해 상세히 설명하도록 하겠다.

git action ( main.yml )

git action 이 어떻게 동작할지 설정하는 파일이다.
레포지토리 -> action -> New workflow -> Publish Java Package with Gradle

// 이름
name: deploy # (0) GitHub Action에서 보여질 이름을 지정합니다. 

// 언제 실행할지
on:
  release:
    types: [push] # (1) push시 자동으로 실행됩니다.
  push:
    branches: [main] # (2) main 브랜치에서 동작합니다.
  pull_request:
    branches: [main]
  workflow_dispatch: # (3) 수동으로도 실행이 가능합니다.

// 환경변수 설정
env: 
// s3 버킷 이름
// 프로젝트 이름
// codedeploy 에서 설정한 application 이름
// codedeploy 에서 설정한 deploy gruop 이름
  S3_BUCKET_NAME: foreverpets3
  PROJECT_NAME: foreverpet-backend
  CODE_DEPLOY_APP_NAME: foreverpet-backend
  CODE_DEPLOY_GROUP_NAME: foreverpet-group
  
  
// 동작목록
  
jobs:
  build: 
  
// 최신버전의 ubuntu 에서 동작한다.
    runs-on: ubuntu-latest # (4) 해당 스크립트를 작동할 OS 입니다.
    
// 작업에서 사용할 권한설정을 한다.
    permissions:
      id-token: write
      contents: read 
      packages: write
// actions/checkout 의 v3 버전을 사용하여 해당 프로젝트의 코드를 가져온다.
    steps:
    - name: Checkout 
      uses: actions/checkout@v3  # (5) 프로젝트 코드를 CheckOut합니다.
      
// actions/setup-java 의 v3 버전을 사용하여 java 버전을 17로 설정한다.
    - name: Set up JDK 17
      uses: actions/setup-java@v3 # (6) 
      with:
        java-version: '17' 
        distribution: 'temurin' 

// gradlew 파일에 대한 실행권한 부여        
    - name: Grant execute permission for gradlew
      run: chmod +x ./gradlew # (7)
      shell: bash
// gradlew 스크립트를 실행하고 이전에 빌드된 파일을 정리하며 테스트를 제외하고 빌드한다.
    - name: Build with Gradle
      run: ./gradlew clean -x test build # (8)
      shell: bash
// 언제 수정되었는지를 표시하기 위한 현재시간 설정 및 보여줌
    - name: Get current time
      uses: 1466587594/get-current-time@v2 
      id: current-time
      with:
        format: YYYY-MM-DDTHH-mm-ss # (9)
        utcOffset: "+09:00"

    - name: Show Current Time
      run: echo "CurrentTime=${{steps.current-time.outputs.formattedTime}}" # (10)
      shell: bash

// zip 파일 생성
    - name: Make zip file
      run: zip -r ./$PROJECT_NAME.zip .         # (12)
      shell: bash

// aws credentials 생성
// repository -> settings -> secrets and variables -> actions
// 에 AWS 사용자 계정에서 생성한 엑세스 ID 와 시크릿 KEY 를 노출시키지 않고 사용하기 위해 등록해준다.
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1      #(13)
      with:        
        aws-access-key-id: ${{ inputs.AWS_ACCESS_KEY_ID ||  secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ inputs.AWS_SECRET_ACCESS_KEY ||  secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-2


// env 에서 설정한 내용을 바탕으로 s3 버킷에 zip 파일을 업로드한다.
    - name: Upload to S3
      run: aws s3 cp --region ap-northeast-2 ./$PROJECT_NAME.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$PROJECT_NAME.zip  #(14)


// codedeploy 를 사용하여 s3 버킷에 저장된 zip 파일을 ec2 인스턴스에 배포한다.
    - name: Code Deploy
      run: aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name $CODE_DEPLOY_GROUP_NAME --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$PROJECT_NAME.zip

appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app/step2/zip/
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  ApplicationStart:
    - location: scripts/deploy.sh
      timeout: 60
      runas: ec2-user

위의 main.yml 작업이 모두 성공적으로 이루어졌다면
aws s3 버킷에 프로젝트 zip 파일이 생성되었을것이다.
또 ec2 인스턴스에 접속해보면 위에서 설정한 destination 폴더에 s3 에서 내려받은 파일이
codedeploy 를 통해 들어와있을것이다.
파일이 제대로 들어온것인지 확인하고자 한다면 ll 명령어로 시간을 확인해보자.

책과 검색을 통해 매우 많은 시행착오를 겪으면서 찾은 문제중 하나는
script missing 이 발생할 경우 hooks 의 location 을 확인해보자
기존 책에선 그냥 deploy.sh 라고 되어있었는데 이부분에서 codedeploy 실패가 나왔다.
scripts/deploy.sh 로 바꾸어주니 잘 실행되었다.

deploy.sh

#!/bin/bash

REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=foreverpet-backend

echo "> Build 파일 복사"
cp $REPOSITORY/zip/build/libs/foreverpet-backend-0.0.1-SNAPSHOT.jar $REPOSITORY/

echo "> 현재 구동 중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f $PROJECT_NAME)

echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"

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

echo "> 새 애플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)

echo "> JAR_NAME: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME

echo "> $JAR_NAME 실행"
    nohup java -jar \
        -Dspring.config.location=classpath:/application.yml,classpath:/application-real.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.yml \
        -Dspring.profiles.active=real \
        $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

echo "> Nginx restart"
sudo service nginx start
sudo service nginx restart

codedeploy 의 설정 파일인 appspec.yml 을 보면 scripts/deploy.sh 파일을 찾아서 실행시킨다.
이 스크립트를 통해서 우리 프로젝트를 ec2 인스턴스 에서 실행시켜준다.
Build 파일 복사 부분에서 *.jar 파일을 찾지 못하는 문제가 발생하여 직접 jar 파일 이름을 하드코딩 하였다.
이부분에 대해선 차후 수정할 예정이다.

Dspring ~

우리 프로젝트에서 사용하는 yml or properties 파일들은 gitignore 로 보호해야한다.
따라서 s3 버킷에 zip 파일로 올라간 git에 있는 프로젝트 에는 이 설정파일들이 없다.
따라서 ec2 인스턴스 내부에 직접 생성하여 등록해주어야한다.

정리

  1. git push or pr or merge
  2. git action 에 등록된 main.yml 실행
  3. main.yml 동작에 의해 s3 버킷에 프로젝트 zip 파일 업로드 ,ec2 인스턴스에 zip 파일 배포
    codedeploy 의 appspec.yml 에 의해 deploy.sh 실행하여 ec2 인스턴스에서 프로젝트 실행

이렇게 작업해두고 현재 프로젝트를 진행하니 "/" 요청시 swagger api 명세 화면이 나오게 설정을
해두었는데 바로바로 업데이트 되는 내용을 프론트에서 확인할수 있다.

2개의 댓글

comment-user-thumbnail
2023년 7월 20일

잘 읽었습니다. 좋은 정보 감사드립니다.

1개의 답글