GitHub Action (SpringBoot 앱) 을 통한 배포

공부는 혼자하는 거·2023년 8월 29일
0

Spring Tip

목록 보기
46/52

자동 배포 옵션에 대한 고민

지금까지는 쭉 젠킨스를 사용해왔다. 젠킨스는 수많은 기능을 지원해주는 다양한 플러그인 생태계가 존재하고, 오픈소스이다. 지금까지 사용해왔을 때 딱히 아쉬운 점을 못 느꼈다. 다만 기본적으로 무거운 편이며 나는 젠킨스의 강력한 기능들을 다 사용할 필요도 없고, 쓰지도 않고 있기 때문에, 다소 과한 옵션이라고 생각이 든다.

젠킨스를 제외하고 다른 옵션을 시도할 때, 무엇이 베스트일까..
상황은 이렇다. 현재 AWS EC2 2대에 SpringBoot로 만든 서버를 배포해야 한다.

  1. 최대한 저비용, 되도록이면 무료
  2. 하나의 툴로만 전체 프로세스 관장
  3. 브랜치마다 다른 배포 전략 수행
  4. 수동 배포 옵션 설정가능 (푸시 트리거 무효화)

여러 개를 고민하다가, 깃허브 액션을 골랐다. 위의 조건 대부분을 달성할 수 있으면서 가장 간단하고 빠른 솔루션이라고 생각했다. 무엇보다, 회사 명의로 깃허브 엔터프라이즈 플랜을 신청해서 받아냈기 때문에 (내가 신청함..) 이 때가 적극적으로 써 먹어볼 기회라 생각했다.

설정

  1. 먼저 SSH 터널링을 통해 접근할 수 있게 키를 만들어두자. 기존에 발급받은 키를 갖다 쓸 수도 있지만, 보안을 위해 따로 배포용 키를 만들어두는 게 나중의 정신건강을 위해 좋다.
mkdir ci-key

# 키 생성

ssh-keygen -t rsa -b 4096 -f ~/Downloads/ci-key/ci-key

# 새로 생성한 키를 접속할 서버에 등록합니다.

cat ~/Downloads/ci-key/ci-key.pub | ssh -i "pem키경로" <SSH_USER>@<SSH_HOST> "cat >> ~/.ssh/authorized_keys"


# permission denied 뜨면

chmod 400 "pem경로"


# 접속 테스트

ssh -i ~/Downloads/ci-key <SSH_USER>@<SSH_HOST>
# sudo 명령을 실행할 때 비밀번호를 입력하지 않도록

sudo visudo

shane ALL=(ALL:ALL) NOPASSWD: /usr/sbin/fuser -k 8080/tcp, /usr/bin/nohup
  1. 프로젝트 레포에 환경변수를 세팅해둔다.

  1. 스크립트를 실행하는 데 있어서 미리 권한 같은 건 다 허가해두도록 하자.
chmod 777 'path'

workFlow 작성

# workflow의 이름
name: api workflow
 
on:
  workflow_dispatch:   # manullay trigger
    inputs:
      BRANCH:
        description: 'Branch to use'
        required: true
        default: 'dev'
        type: choice
        options:
        - dev       
        - prod
        - stage
        - dev2
 
permissions:
  contents: read

env:
 BRANCH_NAME: ${{ github.head_ref || github.ref_name }} # 무적권 main으로 빠진다..내가 생각한개념이 아닌듯..
 
jobs:
  build:  # build job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          #ref: ${{ github.event.inputs.target-branch }}  # 왜 안 먹히냐...
          ref: ${{ inputs.branch }}  # 내가 선택한 브랜치로 체크아웃

      - name: Determine Branch        
        run: echo "${BRANCH_NAME}"

      - name: input branch show Scripts
        run: |
          if [[ "${{ inputs.branch }}" == "stage" ]]; then
            echo "hi stage"
          elif [[ "${{ inputs.branch }}" == "dev" ]]; then
            echo "hi dev"
          elif [[ "${{ inputs.branch }}" == "prod" ]]; then
            echo "hi prod"
          elif [[ "${{ inputs.branch }}" == "dev2" ]]; then
            echo "hi dev2"
          else
            echo "No specific script found for this branch. but maybe kt?"
          fi
        
            
      # - name: Set up JDK 17
      #   uses: actions/setup-java@v3
      #   with:         
      #     java-version: '17'
      #     distribution: 'temurin'

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: '17'
          
      - name: Build with Gradle
        run: ./gradlew clean build -x test  
        shell: bash
        
      - name: Upload artifact
        uses: actions/upload-artifact@v2
        with:
          name: cicdsample
          path: build/libs/*.jar

      - name: Upload script
        uses: actions/upload-artifact@v2
        with:
          name: cicdsample
          path: scripts/*.sh
 
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v2
        with:
           name: cicdsample
      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.5.4
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
      - name: Add remote server to known hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan ${{ secrets.SERVER_IP1 }} >> ~/.ssh/known_hosts
          ssh-keyscan ${{ secrets.SERVER_IP2 }} >> ~/.ssh/known_hosts

      - name: check File List
        run: | 
         pwd
         ls -al
         
          
      - name: SCP transfer
        run: | 
         scp deploy-dev.sh deploy-prod.sh *.jar ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP1 }}:/springboot/api/deploy
         scp deploy-dev.sh deploy-prod.sh *.jar ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP2 }}:/springboot/api/deploy
                 
      - name: Execute remote commands
        run: |         
          if [[ "${{ inputs.branch }}" == "dev" ]]; then
             ssh -v ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP1 }} "sudo sh /springboot/api/deploy/deploy-dev.sh"
             ssh -v ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP2 }} "sudo sh /springboot/api/deploy/deploy-dev.sh"
          elif [[ "${{ inputs.branch }}" == "prod" ]]; then
             ssh -v ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP1 }} "sudo sh /springboot/api/deploy/deploy-prod.sh"
             ssh -v ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP2 }} "sudo sh /springboot/api/deploy/deploy-prod.sh"
          else
            echo "No specific script found for this"
          fi
  

간단히 설명하자면, 내가 선택한 브랜치로 체크아웃하게 한 다음, 빌드에 필요한 기타설정을 세팅하고, 빌드를 진행한 뒤, 프로젝트 내의 scripts 폴더 안의 파일들과 jar파일들을 업로드한 후 다운받았다. 그리그 그 파일들을 미리 세팅해둔 키를 통해 각각의 인스턴스에 전송하고, 스크립트 파일을 실행하는 단계로 설정된다.

echo " "
echo "========================"
echo "Path move"
echo "========================"

cd /springboot/api/deploy

pwd

echo " "
echo "========================"
echo "remove exist process"
echo "========================"


PORT=2001
PID=$(sudo lsof -t -i:$PORT)

if [ -n "$PID" ]; then
    # 프로세스가 실행 중인 경우 종료합니다.
    echo "포트 $PORT를 사용하는 프로세스를 종료합니다 (PID: $PID)..."
    sudo kill -9 "$PID"
    sleep 5
else
    echo "포트 $PORT를 사용하는 프로세스가 실행 중이지 않습니다."
fi


echo " "
echo "========================"
echo "Jar execute"
echo "========================"


# Gradle 설정에서 
#	tasks.jar {
#    	enabled = false
#	}

sudo nohup /usr/bin/java -jar *.jar --spring.profiles.active=prod > nohup.log 2>&1 &

간단한 배포 스크립트 전문이다.

권한 설정 꼭 사전에 체크하자.. 이것 땜에 2시간 날렸다..

실행

두 개의 JOB으로 구분되어 실행되는 걸 볼 수 있다.

두개의 인스턴스 모두 프로세스가 떠진 것을 확인할 수 있다.

SELF HOSTED RUNNER 등록

과금 옵션이 아닌 기본 컴퓨팅 스펙

깃허브 액션의 컴퓨팅 파워가 답답하다면, 과금을 할 수도 있으나, SELF HOSTED RUNNER를 고려해볼 수도 있다.

들어가면 명령어 스크립트가 나올 것이다. 본인이 액션 호스트로 쓸 서버에 고대로 따라치면 된다. 실행하고, 라벨도 불여주자.

jobs:
  build:  # build job
    runs-on: [self-hosted, macOS, ARM64, kang]

러너 교체

참고

https://fe-developers.kakaoent.com/2022/220106-github-actions/

https://zzsza.github.io/development/2020/06/06/github-action/

https://shanepark.tistory.com/388

https://shanepark.tistory.com/465

https://velog.io/@chlee4858/20211205-github%EC%97%90%EC%84%9C-CICD-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-github-action

https://stackoverflow.com/questions/58033366/how-to-get-the-current-branch-within-github-actions

https://www.daleseo.com/github-actions-artifacts/

https://aerocode.net/375

https://danawalab.github.io/common/2022/08/24/Self-Hosted-Runner.html

https://kotlinworld.com/383

https://kingofbackend.tistory.com/263

profile
시간대비효율

0개의 댓글