Github action + AWS CodeDeploy 를 이용한 EC2 CI/CD 설정 (Java with Gradle) - 완성!

최성원·2023년 10월 23일
2

백엔드 데브코스

목록 보기
5/6

프로젝트 코드의 통합 및 배포를 자동화하는 과정에 예전부터 관심 있었는데 이번 기회에 직접 처음부터 모든 작업을 다 해보면서 겪었던 과정을 적어보려고 한다!
본 글에서는 Java(Gradle) + Spring 프로젝트에 CI/CD를 적용해볼것이다

개요

전체적인 파이프라인은 다음 그림이랑 거의 같다

그림 출처: aws blog - Integrating with GitHub Actions – CI/CD pipeline to deploy a Web App to Amazon EC2

텍스트로 설명을 하자면
1. Github Repository에 push가 되면 (trigger 조건)
2. Github action 이 작동하면서 해당 프로젝트를 빌드한 뒤
3. AWS IAM을 통해 AWS 권한 인증을 처리하고
4. 빌드 파일 (.jar)을 압축하여 S3에 업로드한다
5. S3에 압축파일이 업로드되면 aws CodeDeploy 애플리케이션이 실행되고
6. 최종적으로 aws EC2에서 빌드 파일을 백그라운드로 실행하게 한다
(그림에 나와있는 EC2 auto scaling 작업은 진행하지 않는다)

Github action

Github action 탭에 들어가면 기존에 작성되어있는 workflow를 가져다 쓸 수도 있고 본인이 직접 만들 수도 있다
workflow를 만들게 되면 레포지토리의 .github/workflows 폴더안에 yml파일이 생기게 된다
다음은 현재 본인이 사용중인 workflow yml 파일을 가져온 것이다

name: Execute CD

on:
  push:
    branches: [ "develop" ]

permissions:
  contents: read

env:
  BUCKET_NAME: space-club-be-bucket
  DIRECTORY_NAME: space-club-be-directory
  CODE_DEPLOY_APP_NAME: space-club-be-deploy
  DEPLOYMENT_GROUP_NAME: space-club-be-deploy-group

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Check Repo code With Submodules
        uses: actions/checkout@v3
        with:
          submodules: 'true'
          token: ${{secrets.GH_ACCESS_TOKEN}}

      - name: Setup JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          
      - name: Set encrypt Secret key
        run: echo ${{ secrets.encrypt }} > scripts/properties.sh
        shell: bash

      - name: Permission for gradlew
        run: chmod +x ./gradlew
        shell: bash

      - name: Gradle Build Action
        uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # 2.6.0
        with:
          arguments: bootJar

      - name: Make Zip File
        run: zip -qq -r ./$GITHUB_SHA.zip .
        shell: bash

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-access-key-id: ${{ secrets.ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.PRIVATE_KEY }}
          aws-region: ap-northeast-2

      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$DIRECTORY_NAME/$GITHUB_SHA.zip

      - name: Deploy to EC2 Instance
        run: aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME --deployment-group-name $DEPLOYMENT_GROUP_NAME --deployment-config-name CodeDeployDefault.OneAtATime --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$DIRECTORY_NAME/$GITHUB_SHA.zip

주요 설명

  • 가장 상단의 name: 해당 workflow의 이름을 지정한다
  • jobs: 주요 동작들이 아래에 정의된다
    • runs-on: ec2 인스턴스를 ubuntu linux 로 만들었으므로 ubuntu-latest 로 작성한다
    • steps: 실제 동작들이 하나하나 적힌다
      • uses에 적힌 내용이 해당 step의 실제 작업이라고 생각하면 된다

서브모듈

이 프로젝트에서는 서브모듈을 사용하여 기밀 정보를 관리했는데 자세한 사항은 인터넷에 검색을 추천한다
위 workflow는 서브모듈이 적용된 깃허브 레포의 workflow 이므로 서브모듈을 적용하지 않은 경우 첫번째 step의 with 부분을 지우면 된다

추가 설정

  • ${{ secrets.xxx }}에 해당하는 변수들은 깃허브 레포에서 따로 입력해줘야 한다
    • 경로: 레포의 Settings -> Secrets And variables -> Actions -> New Repository Secret
      • secrets.GH_ACCESS_TOKEN: 본인의 깃허브 토큰을 발급받아 입력해주면 된다
        • 해당 토큰엔 workflow, admin, user 권한을 주면 된다
      • secrets.ACCESS_KEY, PRIVATE_KEY: AWS IAM에서 발급받은 액세스 키와 보안 키를 각각 입력해주면 된다
      • secrets.encrypt: jasypt 라는 외부 라이브러리의 비밀번호를 저장해놓은 shell 코드이다 (해당 라이브러리를 안 쓸 경우 지워도 됨)
  • $GITHUB_SHA: 이 값은 깃허브에서 workflow마다 자동으로 설정되는 해시값이라 별도의 설정이 필요없다
  • env에 해당하는 값들은 AWS에서 만든 이름과 동일하게 설정해야 한다!!!
    • 아래 과정을 따라하면서 env 값이 어떻게 쓰이는지 알아야 할 때마다 설명을 써두었다

AWS CodeDeploy

이 부분에서는 AWS 전반적인 내용보다는 CodeDeploy와 그에 필요한 내용들 위주로 작성해보겠다

IAM CodeDeploy 역할 만들기

우선, IAM 역할부터 생성해보도록 하자

IAM 접속 후 역할 -> 역할 생성

  • 서비스 또는 사용 사례: CodeDeploy 선택
  • 사용 사례: CodeDeploy선택 (우리는 EC2로 배포를 할 거니깐)

이름 입력칸 뜰 때까지 다음 클릭

  • 역할 이름, 설명 자유롭게 작성
  • 역할 이름은 바로 아래에서 사용될 것이므로 기억해놓기!

CodeDeploy 애플리케이션 생성

AWS CodeDeploy 에 접속하여 애플리케이션 생성 클릭

애플리케이션 이름은 위에 CODE_DEPLOY_APP_NAME과 동일하게 작성
그 다음 배포 그룹 생성 클릭

배포 그룹 이름엔 위에 DEPLOYMENT_GROUP_NAME과 동일하게 작성
서비스 역할은 앞에서 만든 codedeploy IAM 역할 설정

환경 구성 ~ 로드 밸런서 설정은 아래와 같게 두기

S3 버킷 생성

AWS S3에 접속하여 버킷 만들기 클릭

버킷 이름엔 위에 BUCKET_NAME과 동일하게 작성
나머지 옵션은 기본 설정 사용

EC2 IAM 역할 수정

IAM EC2 역할 만들기

다시 IAM에 접속 -> 역할 생성 클릭

이번엔 사용사례에 EC2 선택
권한은 아래 2개 권한 체크해주기 (권한이 너무 많으니 검색해서 찾기 추천)

  • 역할 이름, 설명 자유롭게 작성
  • 마찬가지로, 역할 이름은 바로 아래에서 사용될 것이므로 기억해놓기!

EC2 역할 수정

  1. EC2 에 접속
  2. 인스턴스 탭 들어가서 내가 만든 인스턴스 체크
  3. 작업 -> 보안 -> IAM 역할 수정 클릭 (IAM 역할 수정 버튼이 비활성화된 경우 해당 인스턴스를 중지해보기)
  4. 방금 위에서 만든 ec2 역할로 수정

EC2 인스턴스 내부에 필요한 항목 설치

자세한 사항은 참고링크 확인

  1. EC2 인스턴스 내부로 접속
  2. 다음 명령어들을 차례대로 입력 (region: 아시아 태평양(서울) 기준)
sudo apt update
sudo apt install ruby-full
sudo apt install wget

cd /home/ubuntu
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
  1. 잘 설치 되었는지 확인
sudo service codedeploy-agent status
  1. 아래처럼 뜬다면 잘 작동된 것!
  2. 결과가 이상한 경우 아래 명령어를 입력한 경우 위의 3번~4번 다시 해보기
sudo service codedeploy-agent start

마지막으로 필요한 항목 작성

appspec.yml

깃허브 리포지토리 최상단에 appspec.yml 이름으로 파일 생성
내용은 아래와 같이 작성 (os: ubuntu 기준, amazon-linux로 생성시 내용 수정 필요)

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

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

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

shell 파일 (deploy.sh)

깃허브 리포지토리 최상단에 scripts 폴더 생성, 그 내부에 deploy.sh 파일 생성
내용은 아래와 같이 작성
(본인은 shell 언어를 잘 모름, 따라서 잘못됐거나 불필요한 부분이 있을 수 있음)

  • 마지막 줄의 --jasypt.encryptor.password 설정은 해당 외부 라이브러리를 안 쓸 경우 지워야 함
  • github action에서 properties.sh 파일 만드는 과정을 지웠을 경우 source /home/... 이 줄 지워야 함
  • profile의 경우 develop 말고 다른 profile을 사용하고 싶으면 자유롭게 변경
  • PROJECT_NAME은 본인 프로젝트의 이름으로 변경
#!/usr/bin/env bash

source /home/ubuntu/action/scripts/properties.sh

PROJECT_NAME=space-club-backend
REPOSITORY=/home/ubuntu/action
PACKAGE=$REPOSITORY/build/libs/
JAR_NAME=$(ls -tr $PACKAGE | grep 'SNAPSHOT.jar' | tail -n 1)
JAR_PATH=$PACKAGE$JAR_NAME

echo $JAR_NAME
echo $JAR_PATH

cd $REPOSITORY

CURRENT_PID=$(pgrep -f $PROJECT_NAME)

if [ -z $CURRENT_PID ]
then
  echo "> 종료할 애플리케이션이 없습니다"
else
  echo "> 실행 중인 애플리케이션 종료 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

echo "> 배포 - $JAR_PATH"
chmod +x $JAR_PATH

sudo nohup java -jar $JAR_PATH --spring.profiles.active=develop --jasypt.encryptor.password=${encrypt} > /home/ubuntu/log/nohup_log.out 2> /home/ubuntu/log/nohup_error.out &

설정 끝!

본인이 설정한 브랜치로 push 를 날린 후 ec2에서 서버가 정상적으로 뜰 때까지 1~2분 정도 걸릴 수 있다
만약 예상치 못한 문제사항 발생 시 댓글로 남겨주시면 해당 사항 확인 후 아는 선에서 최대한 도움을 드려보겠습니다

참고 링크

ec2 인스턴스에서 해줘야 하는 작업: https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html

위 작업에서 리전의 식별자 안내: https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names

profile
안녕하세요 백엔드 개발자입니다

0개의 댓글