Github Action 배포 사용해보기(Spring Boot, React, Ubuntu, Docker)

2023. 8. 19. 14:41Server

Github Action 배포 사용해보기(Spring Boot, React, Ubuntu, Docker)

 

Github Action를 사용해 보았습니다.

많은 블로그에서는 AWS에 대해 배포하는 방법이 있는데 이번 포스팅에서는 순수하게 파일을 전송하는 방법, Docker Hub로 Push하는 방법을 포스팅하겠습니다. 

 

자세한 코드는 아래 링크를 통해 확인해 주세요. 해당 포스팅은 코드에 대한 설명입니다.

 

 

Github Action에 적용된 부분

1. Spring Boot, React 변경이 된 부분만 반영

2. 파일을 Server로 직접 전송

2.1 파일을 Docker Hub로 push

3. Private Repository에서 테스트

feat. Oracle Cloud(Ubuntu 22.04) 배포

 

 

Github Repository 구조

├─.github
│  └─workflows
├─react-action
├─spring-action
└─README.md

# react-action에는 React(Front)가 있습니다.
# spring-action에는 Spring Boot(backend)가 있습니다.

 

* Spring Boot(.jar)

* JDK 17, Gradle

* React v18

 

# Github Action 코드에 이상이 있는지 검사하는 사이트

Github Action Checker : https://rhysd.github.io/actionlint

 

# Github Action Docs

https://docs.github.com/ko/actions

 

GitHub Actions 설명서 - GitHub Docs

GitHub Actions를 사용하여 리포지토리에서 바로 소프트웨어 개발 워크플로를 자동화, 사용자 지정 및 실행합니다. CI/CD를 포함하여 원하는 작업을 수행하기 위한 작업을 검색, 생성 및 공유하고 완

docs.github.com


 

< 직접 전송하는 Github Action Code 보러가기>

< Docker Hub로 Push하는 Github Action Code 보러가기>


Github Action 코드 구조

jobs:
    changes:
        runs-on: ubuntu-latest
        steps:
            ...
    build:
        runs-on: ubuntu-latest
        steps:
            ...
    deploy:
        runs-on: ubuntu-latest
        steps:
            ...

Github Action 은 job안에 여러개의 step이 존재할 수 있습니다.

job의 이름은 사용자가 정의할 수 있습니다.

 

 

on:
  push:
    paths:
        - 'spring-action/'
        - 'react-action/'
    branches: [ "develop" ]
  pull_request:
    branches: [ "develop" ]

push 혹은 pull_request에 대한 이벤트가 일어났을 때 아래 job이 실행됩니다.

path는 프로젝트 구조가 폴더 안에 실제 코드가 있다면 위 처럼 폴더를 적어 주어야 합니다.

 

 

(추가) env 설정은 전역적으로 사용이 가능합니다.

env:  
  working-directory-be: ./spring-action
  working-directory-fe: ./react-action


job안에 env설정은 다른 job에서는 사용할 수 없습니다.
경로같은 경우 전역적으로 사용할 수 있도록 job 밖에 빼서 선언이 가능합니다.

 

 

파일을 Server로 직접 전송 하는 방법

changes job에서는 변경을 감지합니다.

  changes:
    runs-on: ubuntu-latest
    outputs:
      backend: ${{ steps.filter.outputs.backend }}
      frontend: ${{ steps.filter.outputs.frontend }}

    steps:
    - name: checkout
      uses: actions/checkout@v3
      with:
        ref: develop
        repository: PARKJINHOH/github-action
        token: ${{ secrets.TOKEN_GITHUB }}

    - name : Run Paths Filter
      uses: dorny/paths-filter@v2
      id: filter
      with:
        filters: |
          backend:
            - 'spring-action/**'
          frontend:
            - 'react-action/**'
  • runs-on은 실행 환경을 지정합니다. ubuntu-20.04 , windows-2022 , macos-13 등이 있으며 고정 버전을 사용할 수 있습니다. runs-on 설명서
  • actions/checkout@v3 에서는 repository를 checkout합니다. 아래 변경을 감지하기 위해 필요합니다.
    • token은 해당 repository에 접근하기 위해 사용되었습니다. Private Repository에서는 필요했습니다.
  • dorny/paths-filter@v2 에서는 with/filters에 위치한 경로에 변경을 감지합니다.
  • outputs은 변수입니다. 아래 코드에서는 backend, frontend 2개의 변수가 선언되어 있으며 steps.filter.outputs.backend(front)에 대한 value값을 가지고 있습니다.
    • dorny/paths-filter에서는 변경이 있으면 true없으면false를 반환합니다.

 

 

back Job에서는 gradle build를 담당합니다.

backend:
    needs: changes
    if: ${{ needs.changes.outputs.backend == 'true' }}
    runs-on: ubuntu-latest
    env:  
      working-directory: ./spring-action

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

    - name: checkout
      uses: actions/checkout@v3
      with:
        ref: develop
        repository: PARKJINHOH/github-action
        token: ${{ secrets.TOKEN_GITHUB }}

    - name: Cache Gradle
      uses: actions/cache@v3
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
          
    - name: Gradle wrapper & build
      working-directory: ${{ env.working-directory }}
      run: |
        chmod +x ./gradlew
        ./gradlew clean bootJar
        ls ./build/libs
        
    - name: pwd
      run: ls -al .
        
    - name: Upload artifact
      uses: actions/upload-artifact@v3
      with:
        name: jar-artifact
        path: ${{ env.working-directory }}/build/libs #Full Path
  • if: ${{ needs.changes.outputs.backend == 'true' }} 위에서 선언했던 변수가 true라면 아래 가 실행됩니다.
    • backend: - 'spring-action/**'에 변경이 없다면 해당 job의 steps는 실행되지 않습니다.
  • env: working-directory: ./spring-action env설정입니다. backend의 경로를 입력했습니다.
  • actions/setup-java@v3 build에 필요한 JDK를 설정합니다.
  • actions/checkout@v3 에서는 repository를 checkout합니다. gradle build하기 위해 필요합니다.
  • actions/cache@v3 gradle build를 매번 할 시 시간이 매우 오래 걸리기 때문에 cache를 통해 좀 더 시간과 자원을 절약할 수 있습니다.
  • run에서는 script를 실행할 수 있습니다. ./gradlew clean bootJar를 통해 clean후 jar파일을 생성합니다.
  • actions/upload-artifact@v3 job간에는 파일을 이동할 수 없습니다. 워크플로우내에서 생성된 파일이나 데이터를 저장하고 다른 워크플로우에서 공유하기 위해 사용됩니다. 여기서는 build된 jar파일을 다른 job에 넘겨서 원격 서버에 전송하기위해 추가되었습니다.
    • path는 Full Path이며, 경로를 자세히 모르겠다면 -name pwd로 현재 경로를 확인할 수 있습니다.
    • name은 중요합니다. download할 때 해당 name으로 찾아서 download합니다.

 

 

 

backend-upload에서는 서버로 파일을 전송합니다.

  backend-upload:
    needs: backend
    runs-on: ubuntu-latest

    steps: 
    - name: Download artifact
      uses: actions/download-artifact@v3
      with:
        name: jar-artifact
        
    #- name: pwd
    #  run: ls -al .

    - name: copy file via ssh password
      uses: appleboy/scp-action@v0.1.4
      with:
        host: ${{ secrets.SSH_IP }}
        username: ubuntu
        password: ${{ secrets.SSH_PASSWORD }}
        port: 22
        key: ${{ secrets.SSH_RSA }}
        source: "*.jar"
        target: ${{ secrets.DIST_PATH_BACKEND }}/staging
  • actions/download-artifact@v3에서는 actions/upload-artifact@v3에서 업로드한 파일을 다운로드 합니다.
    • 파일을 다운로드 할 때는 name으로 찾습니다. upload의 name과 동일해야 합니다.
  • appleboy/scp-action은 ubuntu의 scp를 이용해 파일을 전송합니다.
    • SSH_IP는 도메인 혹은 IP도 가능합니다.
    • key가 필요한 server일 경우 secrets에 등록해서 사용할 수 있습니다.
    • source는 전송 대상입니다. *.jar일 경우 jar파일 모두, "./**"일 경우 현재 폴더 전체 파일 입니다.
      • pwd를 통해 현재 위치를 확인하세요.
    • target은 서버에서 받을 경로 입니다.

 

(Frontend) ssh 접속

    steps:
      - name: executing remote ssh commands using password
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_IP }}
          username: ubuntu
          password: ${{ secrets.SSH_PASSWORD }}
          port: 22
          key: ${{ secrets.SSH_RSA }}
          script: |
            cd ${{ secrets.DIST_PATH_FRONT }}
            #./2.deploy.sh

 ssh-action와 scp-action은 다릅니다. 철자에 주의해주세요.

  • appleboy/ssh-action을 통해 ssh에 접속할 수 있습니다.
    • script: |를 통해 서버에 있는 sh를 실행할 수도 있으며 sh를 아래 코드로 만들어 실행할 수 있습니다.

 

Frontend는 Backend와 구조가 비슷합니다.


파일을 Docker Hub로 push하는 방법

Docker Hub로 Push하는 방법은build 부분까지는 동일하지만  job과 step구조가 조금 다릅니다.

 

Docker Hub Login

- name: Login to Docker Hub
  uses: docker/login-action@v2
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }} # https://docs.docker.com/docker-hub/access-tokens
  • docker/login-action을 통해 docker에 login합니다.
    • password는 token을 생성해서 사용해도 되고, 실제 password를 사용해도 됩니다.

 

 

Docker Build & Docker push

    - name: web docker build and push
      working-directory: ${{ env.working-directory }}
      run: |
        pwd
        ls -al .
        # The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested 에러시 아래 사용.
        # docker build -t ${{ secrets.DOCKER_REPO }}/gitaction-be .
        docker build --platform linux/arm64 -t ${{ secrets.DOCKER_REPO }}/gitaction-be .
        docker push ${{ secrets.DOCKER_REPO }}/gitaction-be

저는 여기서 경로 때문에 조금 헷갈렸는데요.

pwd와 ls -al . 로 경로와 파일을 보면서 하면 좀 더 쉽습니다.

 

docker build를 하며 자신의 docker repository/이미지 이름으로 build합니다.

만약 배포할 서버가 arm64를 사용하면 --platform명령어를 사용해 build 합니다.

docker push하면 끝

 

 

[배포 서버] Docker pull

  backend-docker:
    needs: backend
    runs-on: ubuntu-latest
    env:  
      working-directory: ./spring-action
      
    steps:
    - name: docker pull
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SSH_IP }}
        username: ubuntu
        password: ${{ secrets.SSH_PASSWORD }}
        port: 22
        key: ${{ secrets.SSH_RSA }}
        script: |
          sudo docker pull ${{ secrets.DOCKER_REPO }}/gitaction-be

ssh-action으로 서버에 접속한 뒤, script를 통해 Docker hub에 push했던 image를 pull 합니다.

 

이후 재기동 및 배포관련 script를 작성하면 됩니다.

만약 서버에 실행하는 .sh파일이 있다면 `cd 경로` `./start.sh`를 적어주면 됩니다.