티스토리 뷰

공연 동행 구인 웹 서비스 프로젝트에 참여하며

CI/CD를 직접 적용해보게 되어 그 과정을 기록해보고자 합니다👣

 

이전에는 깃에 코드를 올리고, aws ec2를 통해 pull 받아와 jar 파일을 실행하는 방식으로 배포해왔었습니다.

매번 develop 브랜치가 업데이트 될 때마다 수동으로 빌드 후 jar 파일을 실행해야 하며 번거로웠기에

깃에서 제공해주는 "GitHub Action"을 통해 자동화를 적용하여 개발에 좀 더 집중해보고자 합니다😀

 


CI/CD란? 

지속적 통합 및 지속적 배포

 

CI 

Continuous Integration, 빌드와 테스트 자동화

 

새로운 코드 변경 사항이 정기적으로 빌드 및 테스트 되어 
공유 레포지토리에 통합하는 것을 의미합니다.

 

CD 

Continuous Delivery 혹은 Continuous Depolyment, 배포 자동화

 

개발자의 변경 사항이 레포지토리를 넘어,

고객의 프로덕션 환경까지 릴리즈 되는 것을 의미합니다.

 

 

정리하면

CI 빌드 -> 테스트 -> 통합
CD 배포

 


서버 구성

EC2, RDS, ElastiCache, S3, Code Deploy

 


전체적인 CI/CD 흐름

  1. 깃 레포지토리에 이벤트 발생
  2. 깃헙 액션 워크 플로우 동작
    • build, test 성공
    • s3에 레포지토리가 압축형태로 업로드
  3. CodeDeploy에서 S3의 파일을 이용해 EC2에 배포 시작

전체적인 서버 구성 및 CI/CD 흐름


서버 구성 및 CI/CD 적용 과정

1. VPC 및 Subnet 생성

 

2. EC2 생성

생성한 VPC에 EC2를 생성하고, S3와 CodeDeploy 접근을 허용하는 역할을 생성하여 부여합니다.

 

SSH, MySQL, Redis, http, https로부터의 접근을 위한 인바운드 규칙을 생성합니다.

 

ip 주소 고정을 위해 탄력적 ip 주소를 생성 후 부여합니다.

 

EC2에 접속하여 자바와 CodeDeploy를 설치합니다.

- 자바 설치
sudo apt update sudo apt install openjdk-17-jdk

 

- codedeploy 설치

https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html

 

Ubuntu Server용 CodeDeploy 에이전트 설치 - AWS CodeDeploy

출력을 임시 로그 파일에 쓰는 것은 Ubuntu Server 20.04에서 install 스크립트를 사용하여 알려진 버그를 해결하는 동안 사용해야 하는 해결 방법입니다.

docs.aws.amazon.com

 

3. RDS(MySQL) 생성

VPC에 RDS(MySQL) 생성 후 EC2와 연결합니다.

 

4. ElastiCache(Redis) 생성

VPC에 Redis 캐시 생성 후, 접속을 위한 인바운드 규칙을 설정합니다.

 

➕ElastiCache는 같은 VPC 내부에서만 direct하게 접속이 가능하다.

redis 접근 시에는 SSH를 통해 EC2를 거쳐서 접속해야 합니다.

 

5. S3 생성

S3 버킷을 생성합니다.

 

6. Code Deploy 설정

Code Deploy 애플리케이션을 생성합니다.

 

7. Git Action 워크플로우 작성

develop 브랜치에 push 또는 pr 이벤트가 발생하면 스크립트에 정의해둔 깃헙 액션이 실행됩니다.

name: CI

on:
  # develop 브랜치에서 일어난 push/pull request에 작동한다.
  push:
    branches: [ "develop" ]
  pull_request:
    branches: [ "develop" ]


  workflow_dispatch:

env:
  PROJECT_NAME: dongoorami
  BUCKET_NAME: dongoorami-bucket
  CODE_DEPLOY_APP_NAME: dongoorami-codedeploy
  DEPLOYMENT_GROUP_NAME: dongoorami

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - name: JDK 17 설치
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'adopt'

      # gitignore한 파일 생성해주기
      - name: create applications.yml
        shell: bash
        run: |
          if [ ! -d "./src/main/resources" ]; then
            mkdir -p ./src/main/resources
          fi
          touch ./src/main/resources/application.yml
          echo "${{ secrets.APPLICATION }}" >> ./src/main/resources/application.yml

      # gradlew 파일 실행권한 설정
      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew

      # 빌드 시작
      - name: Build with Gradle
        run: ./gradlew build

      # 프로젝트 zip파일로 압축
      - name: Make Zip File
        run: zip -qq -r ./$GITHUB_SHA.zip .

      # aws 접근 id, key
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      # s3에 압축한 zip파일 업로드
      - name: upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      # s3에 업로드한 파일 code Deploy에서 배포 요청
      - name: deploy with AWS codeDeploy
        run: aws deploy create-deployment
          --application-name $CODE_DEPLOY_APP_NAME
          --deployment-config-name CodeDeployDefault.AllAtOnce
          --deployment-group-name $DEPLOYMENT_GROUP_NAME
          --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

 

8. Appspec.yml 작성

CodeDeploy에서 배포를 관리하는 데 사용하는 YAML 형식 또는 JSON 형식의 파일

CodeDeploy가 가장 먼저 호출할 설정파일로 프로젝트 최상단에 생성합니다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/dongoorami
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

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

 

9. deploy.sh 작성

appspec.yml 파일에서 deploy.sh 파일을 수행하게 됩니다.

기존에 실행중이던 jar 프로세스를 종료하고, 새로운 jar를 실행시키는 작업을 수행합니다.

#!/usr/bin/env bash

REPOSITORY=/home/ubuntu/dongoorami
cd $REPOSITORY

APP_NAME=dongoorami
JAR_NAME=$(ls $REPOSITORY/build/libs/ | grep 'SNAPSHOT.jar' | tail -n 1)
JAR_PATH=$REPOSITORY/build/libs/$JAR_NAME

CURRENT_PID=$(pgrep -f $APP_NAME)

if [ -z "$CURRENT_PID" ]
then
  echo "> 종료할것 없음."
else
  echo "> kill -9 $CURRENT_PID"
  kill -15 "$CURRENT_PID"
  sleep 5
fi

echo "> $JAR_PATH 배포"
nohup java -jar "$JAR_PATH" > jarExecute.log 2>&1 < /dev/null &

 

 

CI/CD 확인👀

깃에서 작업 후 develop 브랜치로 push 또는 pr 시에 실행되는 것을 확인할 수 있습니다!

 

 


생각보다 서버 구성하면서 권한 설정, 보안 규칙 설정, 서브넷, VPC .. 등등 해주어야 하는 작업들이 많아서 복잡했지만, 자동화되어 편하게 개발에 집중할 수 있을 것 같습니다! 이번 계기로 AWS의 여러 서비스와 GitHub Action 다루어볼 수 있었습니다👍