본문 바로가기
Git

[GitHub Actions] Spring boot, vue 통합, 배포(CICD) 구축

by sky-j 2023. 11. 1.
반응형

CI/CD(Continuous Integration/Continuous Delivery)란?

CI/CD(지속적 통합/지속적 배포)는 애플리케이션 개발 단계를 자동화하는 방법이다.

CI/CD 종류(Jenkins, Github Actions)

저는 Github Acions를 이용했습니다.

GithubActions

yml 파일을 이용해 자동화를 수행 할 workflow를 설정

Github에서 발생하는 이벤트(push, merge)를 트리거로 동작 시킨다.

CI/CD 프로세스(Back-end: Spring boot)

1. 원격 저장소에 있는 main branch에 push를 기준으로 트리거
2. 프로젝트 빌드
3. 서버에 ssh 접속
4. 기존의 jar 파일 백업
5. jar파일 전송
6. 실행 권한 변경 및 docker 재시작

yml 작성 전 Github Action으로 서버에 ssh 접속을 위한 key 값 설정

경로 : Git Repository -> Settings -> Secrets and variables -> Actions

key 설정

New repository secret 을 클릭해 이런식으로 추가해준다.

STAGING_SSH_HOST: ip 혹은 Domain

STAGING_SSH_KEY: 발급 받은 Private Key 값( 밑에서 자세하게 설명)

STAGING_SSH_PORT: 22(ssh 기본 접속 포트)

STAGING_SSH_USER: 서버에 유저 name

ssh-keygen으로 서버 SSH_KEY 발급 받기

윈도우 CMD (public key, private key 발급)

ssh-keygen -t rsa -b 4096 -C "example@gmail.com"

명령 입력 후

1. Key를 저장할 경로 지정 (기본값: $HOME/.ssh/id_rsa)

2. 추가로 사용할 암호(기본값: 없음)

3. 암호 확인

저는 암호는 추가로 설정하지 않아서 Enter 키를 눌러주고 넘어갔습니다.

Public Key 서버에 저장

/.ssh/authorized_keys 파일에 공개키를 넣어줍니다.

(최초 발급 받은 공개키에서 enter나 space등 다른 값들이 잘 못들어가지 않게 주의)

홈(/)에 .ssh 폴더가 없다면

# 홈(/)경로에 .ssh 폴더만들기
mkdir /.ssh

# .ssh 폴더에 authorized_keys 파일 만들기
vi /.ssh/authorized_keys

Private Key Github Actions에 Key값 넣어주기

key 설정

STAGING_SSH_KEY: 발급 받은 Private Key 값

( -----BEGIN OPENSSH PRIVATE KEY-----와 -----END OPENSSH PRIVATE KEY----- 부분까지 넣어줍니다.)

Workflow yml 작성

name: Multi-Module Deployment # Workflow의 이름을 지정합니다.

on: # Workflow의 트리거 조건을 설정합니다.
  push: # 코드가 push 될 때마다 실행되는 조건을 설정합니다.
    branches: [ "main" ] # main 브랜치에 push가 발생할 때만 실행됩니다.

permissions: # Workflow가 GitHub Repository 내에서 수행할 수 있는 권한을 설정합니다.
  contents: read # 이 Workflow는 리포지토리의 컨텐츠를 읽는 것만 허용됩니다.

jobs: # Workflow 내에서 실행될 작업을 정의합니다.
  deploy: # deploy라는 이름의 작업을 정의합니다.
    runs-on: ubuntu-latest # 이 작업은 ubuntu-latest 가상 환경에서 실행됩니다.

    steps: # 작업의 단계를 순차적으로 나열합니다.

      - name: checkout # 현재 GitHub 리포지토리의 코드를 체크아웃합니다.
        uses: actions/checkout@v3 # actions/checkout 액션을 v3 버전으로 사용합니다.

      - name: Set up JDK 17 # JDK 17을 설정합니다.
        uses: actions/setup-java@v3 # actions/setup-java 액션을 v3 버전으로 사용합니다.
        with:
          java-version: '17' # 사용할 Java의 버전을 지정합니다.
          distribution: 'temurin' # Java 배포판을 temurin으로 지정합니다.

      - name: Grant execute permission for gradlew # gradlew 파일에 실행 권한을 부여합니다.
        run: chmod +x gradlew # chmod 명령어를 사용하여 gradlew 파일에 실행 권한을 추가합니다.

      - name: Build with Gradle # Gradle을 사용하여 빌드합니다.
        uses: gradle/gradle-build-action@v2.2.1 # gradle/gradle-build-action 액션을 v2.2.1 버전으로 사용합니다.
        with:
          arguments: clean build # gradle 명령어 인자로 clean build를 실행합니다.

      - name: Configure SSH # SSH 설정을 구성합니다.
        run: | # 다음의 스크립트를 실행하여 SSH 설정을 합니다.
          mkdir -p ~/.ssh/
          echo "$SSH_KEY" > ~/.ssh/staging.key
          chmod 600 ~/.ssh/staging.key
          cat >>~/.ssh/config <<END
          Host staging
            Port $SSH_PORT
            HostName $SSH_HOST
            User $SSH_USER
            IdentityFile ~/.ssh/staging.key
            StrictHostKeyChecking no
          END
          chmod 400 ~/.ssh/config
        env: # 환경 변수를 설정합니다.
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}
          SSH_KEY: ${{ secrets.STAGING_SSH_KEY }}
          SSH_HOST: ${{ secrets.STAGING_SSH_HOST }}
          SSH_PORT: ${{ secrets.STAGING_SSH_PORT }}

      - name: ssh 1 connect # SSH를 통해 서버에 첫 번째로 연결합니다.
        uses: appleboy/ssh-action@master # appleboy/ssh-action 액션을 사용하여 SSH 연결을 수행합니다.
        with:
          host: ${{ secrets.STAGING_SSH_HOST }}
          username: ${{ secrets.STAGING_SSH_USER }}
          key: ${{ secrets.STAGING_SSH_KEY }}
          port: ${{ secrets.STAGING_SSH_PORT }}
          script: | # 다음 스크립트를 서버에서 실행합니다.
            echo /home/${{ secrets.STAGING_SSH_USER }} 
            cd /home/${{ secrets.STAGING_SSH_USER }} &&
            mv admin-api-0.0.1-SNAPSHOT.jar admin-api-0.0.1-SNAPSHOT-$(date +'%Y%m%d%H%M%S').jar &&
            mv client-api-0.0.1-SNAPSHOT.jar client-api-0.0.1-SNAPSHOT-$(date +'%Y%m%d%H%M%S').jar
        env:
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}

      - name: scp jar # jar 파일을 서버로 안전하게 복사합니다.
        run: |
          rm -f ~/.ssh/known_hosts # 기존에 저장된 known_hosts 파일을 삭제합니다. 이는 서버의 호스트 키가 변경되었을 때 발생하는 문제를 방지합니다.          
          scp -v admin-api/build/libs/admin-api-0.0.1-SNAPSHOT.jar staging:/home/$SSH_USER/admin-api-0.0.1-SNAPSHOT.jar # admin-api jar 파일을 서버의 지정된 위치로 복사합니다.
          scp -v client-api/build/libs/client-api-0.0.1-SNAPSHOT.jar staging:/home/$SSH_USER/client-api-0.0.1-SNAPSHOT.jar # client-api jar 파일을 서버의 지정된 위치로 복사합니다.
        env: # SCP 명령을 실행할 때 사용할 환경 변수들을 설정합니다.
          SSH_USER: ${{ secrets.STAGING_SSH_USER }} # 서버의 SSH 사용자 이름
          SSH_HOST: ${{ secrets.STAGING_SSH_HOST }} # 서버의 호스트 주소

      - name: ssh 2 connect # SSH를 통해 서버에 두 번째로 연결합니다.
        uses: appleboy/ssh-action@master # appleboy/ssh-action 액션을 사용하여 SSH 연결을 수행합니다.
        with:
          host: ${{ secrets.STAGING_SSH_HOST }} # SSH 호스트 정보
          username: ${{ secrets.STAGING_SSH_USER }} # SSH 사용자 이름
          key: ${{ secrets.STAGING_SSH_KEY }} # SSH 키
          port: ${{ secrets.STAGING_SSH_PORT }} # SSH 포트
          script: | # 다음 스크립트를 서버에서 실행합니다.
            chmod 755 /home/${{ secrets.STAGING_SSH_USER }}/admin-api-0.0.1-SNAPSHOT.jar # admin-api jar 파일에 실행 권한을 부여합니다.
            chmod 755 /home/${{ secrets.STAGING_SSH_USER }}/client-api-0.0.1-SNAPSHOT.jar # client-api jar 파일에 실행 권한을 부여합니다.
        env: # SSH 연결을 위한 환경 변수들을 설정합니다.
          SSH_USER: ${{ secrets.STAGING_SSH_USER }} # 서버의 SSH 사용자 이름

 

Git push main을 트리거로 Github Actions에 들어가 확인 할 수 있다.

 

같은 방식으로 Vue프로젝트에도 적용하면 되기 때문에 프론트쪽 workflow만 예시로 보여드릴게요

 

# 이 워크플로우는 Node.js 의존성을 깨끗하게 설치하고, 캐시/복원하며, 소스 코드를 빌드하고 다양한 버전의 Node에서 테스트를 실행합니다.
# 자세한 정보는 다음에서 확인할 수 있습니다: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI # 워크플로우의 이름을 설정합니다.

on: # 워크플로우가 언제 실행될지 설정합니다.
  push:
    branches: [ "main" ] # main 브랜치에 푸시가 발생할 때

jobs:
  build: # 빌드 작업을 정의합니다.

    runs-on: ubuntu-latest # 작업이 실행될 환경을 설정합니다. 여기서는 최신의 Ubuntu를 사용합니다.

    strategy:
      matrix:
        node-version: [18.16.0] # 사용할 Node.js 버전을 설정합니다.

    steps:
      # 0. 체크아웃
      - name: checkout
        uses: actions/checkout@v3 # GitHub 저장소를 체크아웃하기 위한 액션입니다.

      # 1. Node.js 환경 설정
      - name: Set up Node.js
        uses: actions/setup-node@main # Node.js를 설정하기 위한 액션입니다.
        with:
          node-version: 18.x # Node.js의 버전을 설정합니다.

      # SSH 설정
      - name: Configure SSH
        run: | # 서버에 SSH로 접근하기 위한 설정을 합니다.
          mkdir -p ~/.ssh/
          echo "$SSH_KEY" > ~/.ssh/staging.key
          chmod 600 ~/.ssh/staging.key
          cat >>~/.ssh/config <<END
          Host staging
            Port $SSH_PORT
            HostName $SSH_HOST
            User $SSH_USER
            IdentityFile ~/.ssh/staging.key
            StrictHostKeyChecking no
          END
          chmod 400 ~/.ssh/config
        env: # SSH 연결을 위한 환경 변수를 설정합니다.
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}
          SSH_KEY: ${{ secrets.STAGING_SSH_KEY }}
          SSH_HOST: ${{ secrets.STAGING_SSH_HOST }}
          SSH_PORT: ${{ secrets.STAGING_SSH_PORT }}

      # 2. 의존성 패키지 설치
      - name: Install dependencies
        run: npm install # npm을 사용하여 프로젝트 의존성을 설치합니다.

      # 3. 빌드
      - name: Build Page
        run: npm run build # 프로젝트를 빌드합니다.
        env:
          NODE_ENV: production # NODE_ENV 환경 변수를 production으로 설정합니다.

      # 4. 기존 빌드 파일 백업
      - name: Backing Up Existing Build Files
        uses: appleboy/ssh-action@master # SSH를 통해 서버에 접속하여 백업 스크립트를 실행합니다.
        with:
          host: ${{ secrets.STAGING_SSH_HOST }}
          username: ${{ secrets.STAGING_SSH_USER }}
          key: ${{ secrets.STAGING_SSH_KEY }}
          port: ${{ secrets.STAGING_SSH_PORT }}
          script: | # 기존에 있는 dist 디렉토리를 백업합니다.
            pwd
            cd /home/${{ secrets.STAGING_SSH_USER }}/jed-vue &&
            mv dist dist-$(date +'%Y%m%d%H%M%S')
        env:
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}

      # 5. 배포
      - name: Deploy Vue Application
        run: | # 압축된 빌드 파일을 서버로 전송하고 기존 파일을 제거합니다.
          rm -f ~/.ssh/known_hosts
          tar -czvf dist.tar.gz ./dist
          scp dist.tar.gz staging:/home/$SSH_USER/jed-vue/
          rm -f dist.tar.gz
        env:
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}

      # 6. 서버에서 압축 파일 해제, 삭제 및 Vue 앱 권한 설정
      - name: Set Vue App Permissions on Server
        uses: appleboy/ssh-action@master # SSH를 통해 서버에 접속하여 스크립트를 실행합니다.
        with:
          host: ${{ secrets.STAGING_SSH_HOST }}
          username: ${{ secrets.STAGING_SSH_USER }}
          key: ${{ secrets.STAGING_SSH_KEY }}
          port: ${{ secrets.STAGING_SSH_PORT }}
          script: | # 서버에서 압축을 해제하고, 파일 권한을 설정하고, 관련된 Docker 컨테이너를 재시작합니다.
            tar -xzvf /home/${{ secrets.STAGING_SSH_USER }}/jed-vue/dist.tar.gz -C /home/${{ secrets.STAGING_SSH_USER }}/jed-vue/
            rm -f /home/${{ secrets.STAGING_SSH_USER }}/jed-vue/dist.tar.gz
            chmod 755 /home/${{ secrets.STAGING_SSH_USER }}/jed-vue/dist
            docker restart jed_client
        env:
          SSH_USER: ${{ secrets.STAGING_SSH_USER }}

 

 

참고

https://seosh817.tistory.com/104

 

[CI/CD] CI/CD란? - 지속적 통합(Continuous Integration)/지속적 배포(Continuous Deployment) 기본개념

매번 개발자가 코드를 수정하고 빌드와 테스트를 하고 배포까지 한다면 상당히 많은 시간이 소요됩니다. 하지만 git에 코드를 올리는 것만으로도 누군가가 빌드와 테스트, 배포까지 해준다면,

seosh817.tistory.com

https://velog.io/@ssol_916/Github-Action%EC%9C%BC%EB%A1%9C-CICD-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0

 

Github Action으로 CI/CD 구성하기

개발자는 반복적인 작업을 싫어하는 사람들이라고 한다. 뉴비 개발자인 나도 귀찮은 걸 싫어한다. 똑같은 행위를 계속 반복해야 한다면 이것을 시스템으로 자동화 해버리면 되지 않을까?

velog.io

https://github.com/marketplace/actions/ssh-remote-commands

 

SSH Remote Commands - GitHub Marketplace

Executing remote ssh commands

github.com

 

반응형

'Git' 카테고리의 다른 글

Git 에서 CRLF 개행 문자 차이 해결  (0) 2023.06.28
협업 시 충돌 상황  (0) 2023.05.25
Github repository 만들기 및 함께할 팀원 추가  (0) 2023.05.04
Git token 컴퓨터에 저장하기  (0) 2023.05.04