[프로젝트 배포] EC2 인스턴스에 Spring boot 배포하기 (feat. CI/CD) -5편

Geonu LEE·2024년 10월 1일

이전 포스트 보러가기 : EC2 Github Action 연결하기

이전 포스트에서 빌드의 과정을 소개한 적이 있다.
그 포스트에 이어 이번엔 Spring boot 를 배포하기 위한 파이프라인을 구축할 것이다.

사전 작업

GitHub Action secrets key 등록하기

먼저 EC2 에서 Github repository로 접근하려면 EC2에 정보를 내 저장소에 등록해줘야한다.
Github Action Setting 탭으러 들어가 EC2에 정보를 알려준다.

  • host : EC2 IP 주소
  • USERNAME : ec2-user 이름 작성 (주로 ubuntu가 default 인 것 같다)
  • KEY : EC2 ssh 비밀 키 등록
  • PORT : 22(SSH 프로토콜 포트 키는 22이다)

EC2 비밀키에 대한 자세한 설명은 EC2 Github Action 연결하기를 클릭한다!

GitHub가 EC2에 접근할 수 있도록 보안 그룹 설정

EC2 인스턴스 보안그룹을 통해 Github에서 SSH 프로토콜 접근할 수 있도록 해줘야한다.
개발 초기단계에는 편하게 인바운드 규칙을 모두 허용하는 게 편하다!

1. CI / CD 파이프라인 구축하기

먼저 기초적으로 설정해야할 Github Action에 대해서는 지난 포스트를 참고하여 진행한다.

CI 구축하기


name: CI/CD Pipeline

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      # jar build
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'


      - name: Gradle 빌드
        run: |
    		chmod +x ./gradlew
    		./gradlew build 


      # JAR 파일을 EC2로 복사
      - name: JAR 파일 서버로 전송
        uses: appleboy/scp-action@v0.1.0 
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.KEY }}
          port: ${{ secrets.PORT }}
          source: build/libs/프로젝트명.jar 
          target: /home/ubuntu 
  • name: CI/CD Pipeline: 파이프라인 이름 설정.
  • on: push: main 브랜치로 푸시될 때 파이프라인 실행.
  • runs-on: ubuntu-latest: 최신 Ubuntu 서버에서 작업 실행.
  • Checkout code: GitHub 리포지토리의 소스 코드 가져오기.
  • Set up JDK 17: Java 17 환경 설정.
  • Gradle 빌드: Gradle을 사용해 프로젝트 빌드(JAR 파일 생성).
  • JAR 파일 서버로 전송: SCP를 사용해 생성된 JAR 파일을 EC2 서버로 복사.

CD 구축하기


  deploy:
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: 이전 JAR 프로세스 종료
        uses: appleboy/ssh-action@v0.1.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.KEY }}
          port: ${{ secrets.PORT }}
          script: |
            cd /home/ubuntu/build/libs/ 
            
            # JAR 파일을 사용하는 프로세스의 PID 찾기
            PID=$(pgrep -f "$JAR_PATH")
            
            if [ -n "$PID" ] && [ "$PID" -gt 1 ]; then
              echo "이전 프로세스($PID)가 실행 중입니다. 종료합니다."
              kill "$PID"
              sleep 20  # 프로세스가 종료될 시간을 확보
            else
              echo "실행 중인 프로세스가 없습니다."
            fi
            
            # 프로세스가 종료되었는지 확인
            PID=$(pgrep -f "$JAR_PATH")
            
            if [ -n "$PID" ] && [ "$PID" -gt 1 ]; then
              echo "프로세스($PID)가 아직 종료되지 않았습니다. 강제 종료합니다."
              kill -9 "$PID"
              sleep 10  # 강제 종료 후 잠시 대기
            else
              echo "이전 프로세스 종료가 완료되었습니다."
            fi



      - name: 새로운 JAR 파일 실행
        uses: appleboy/ssh-action@v0.1.0
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.KEY }}
          port: ${{ secrets.PORT }}
          script: |
            cd /home/ubuntu/build/libs/ 
            echo "현재 작업 디렉토리 확인: $(pwd)"
            JAR_PATH={프로젝트명}.jar
            LOG_FILE=/home/ubuntu/app.log  
            
            if [ -f "$JAR_PATH" ]; then
            echo "JAR 파일을 찾았습니다. 애플리케이션을 시작합니다."
            
            nohup sudo java -jar "$JAR_PATH" > "$LOG_FILE" 2>&1 &
            echo "애플리케이션이 백그라운드에서 실행 중입니다."
            else
            echo "JAR 파일을 찾을 수 없습니다!"
            exit 1
            fi
  • deploy:
    역할: build 작업이 완료된 후에 실행

  • runs-on: ubuntu-latest
    역할: 배포 작업이 실행될 환경을 정의

  • 이전 JAR 프로세스 종료
    역할: 서버에서 이전에 실행 중인 JAR 파일 프로세스를 찾아 종료하는 작업

  • pgrep -f "$JAR_PATH": JAR 파일을 실행하는 프로세스의 PID를 찾음.
    kill "$PID": 찾은 프로세스를 종료.
    kill -9 "$PID": 강제 종료가 필요할 경우 사용하는 명령.

  • sleep 20 / sleep 10
    프로세스가 안전하게 종료될 수 있도록 대기 시간 추가

  • 새로운 JAR 파일 실행
    새로 전송된 JAR 파일을 서버에서 백그라운드로 실행

    nohup sudo java -jar "$JAR_PATH" > "$LOG_FILE" 2>&1 &
    : JAR 파일을 백그라운드에서 실행하며, 로그를 $LOG_FILE에 기록

    if [ -f "$JAR_PATH" ]: JAR 파일이 있는지 확인 후, 애플리케이션 실행을 시도


    추가로 여러 옵션의 스크립트를 적용하여 빌드시간을 줄이거나 환경에 따라 적용가능 한 것 같다!

    그럼 완성하였으니 git push 를 해보도록 하자!

    Spring boot 애플리케이션이 서버에서 잘 작동하는지 확인해보자

    $ ps aux | grep java
    명령어를 통해 jar 파일이 백단에서 잘 작동하는지 확인해 볼 수 있다.

    만약 서버가 실행되지 않았다면 EC2 인스턴스에서 /home/ubuntu/ 경로에 app.log를 생성하도록 하였으니,
    cat app.log 명령어를 사용하여 에러 내용을 확인해 볼 수 있다.


0개의 댓글