Github Action 으로 물리서버에 자동배포하기

Ron Park·2022년 7월 28일
4
post-thumbnail

이번에 토이프로젝트중 하나로 사내 서비스용 챗봇서비스를 만들기 시작했다. 그런데 스케일 아웃을 고려할 필요 없는 작은 규모의 서비스이기 때문에 가장 간단한 배포 방법을 찾아보기로 했다.

요구사항

  • 서버는 하나만 사용한다 (스케일 아웃 염두 X)
  • 배포 관련 설정이 과하지 않도록
  • 서버에 직접 들어가지 않고 머지되면 자동으로 배포가 가능하도록
  • 무중단 배포를 고려하지 않는다 (너무 길지만 않으면...)

이렇다 보니, 기존에 사용하던 도커나 쿠버네티스보다 더 간단한 Github Action 을 이용해서 배포하는 방법을 적용하게 되었다.

설정

서버에 Runner 설치

서버를 이미 발급받아서, ssh 로 접근 가능한 상태라고 가정한다

가장 먼저해야 할 부분은 Github 에서 서버를 조작할 수 있는 환경을 만들어야 한다. 그 방법으로 Github Action Runner 를 서버에 설치하는 방법을 선택했다.

  1. <repository url>/settings/actions/runners/new 로 바로 들어가거나 github -> 상단 setting -> Actions -> Runnes 순서로 들어가기

  2. 자신의 OS 에 맞게 선택 (필자는 CentOS 이기 때문에 Linux 로 선택)

  3. 하단에 노출되는 Download 스크립트를 복사해서 서버에서 실행

  4. github Runner 를 service 로 등록해서 서버가 부팅되면 자동 실행되도록 아래 스크립트 실행

sudo ./svc.sh install
sudo ./svc.sh start
  1. <repository url>/settings/actions/runners 로 바로 들어가거나 github -> 상단 setting -> Actions -> Runners 순서로 들어가기
    Github Runner 로 등록되어 목록에 추가되었고, Idle 상태인지 확인

  • 여기까지 완료되었으면, Github workflow 를 실행하면 등록한 서버에서 실행하게 된다.
  • 서버에 ssh 로 접근해 git repository checkout 하고, 설치하는 과정을 모두 Github workflow 에 정의하면 되는것.

배포 workflow 정의

Github workflow 는 .github/workflows 하위에 yaml 확장자의 파일을 생성해야 한다.
Github Action 문법은 https://docs.github.com/en/actions 에서 참고하자. 문법을 여기에서 다루기보다는 문서를 쭉 살펴보는 것이 좋을 것 같다.

필자는 node 서버를 배포하는 것이기 때문에, 자신의 서버에 맞춰야 한다.

.github/workflows/deploy.yml 파일에 아래와 같이 정의했다.

name: App install and start

concurrency: 
  group: production
  cancel-in-progress: true

on:
  push:
    branches: [ main ]
  workflow_dispatch:
jobs:
  build:
    runs-on: [ self-hosted ]

    steps:
    - uses: actions/checkout@v2
      with:
        clean: false

    - name: Use Node.js 16.x
      uses: actions/setup-node@v1
      with:
        node-version: 16.x

    - name: Install dependencies
      working-directory: service
      run: npm install
        
    - name: Stop old server (ignore error)
      run: |
        killall -9 node || true

    - name: Remove old server in ~/soruce (ignore error)
      run: |
        rm -rf ~/source || true

    - name: Copy new server to ~/soruce
      run: |
        mkdir -p ~/source
        cp -R ./ ~/source
        
    - name: Run new server (in background)
      env:
        RUNNER_TRACKING_ID: ""
      run: |
        cd ~/source
        nohup npm run start </dev/null >/dev/null 2>&1 &

하나씩 살펴보도록 하자.

concurrency: 
  group: production
  cancel-in-progress: true

동시성 설정이다. 배포 workflow 이기 때문에, 여러개의 workflow 가 실행될 때 맨 마지막 workflow 만 남기고 모두 취소한다. (어차피 중간에 실행된 workflow 는 모두 덮어씌워져 없어지니까)

on:
  push:
    branches: [ main ]
  workflow_dispatch:

해당 workflow 의 실행 조건이다

  • main 브랜치에 푸시 (PR 을 통해서 머지되는 경우와 직접 푸시한 경우)
  • 직접 github 에서 트리깅하는 경우 (서버에 이슈가 발생한 경우 수동으로 재시작하기 위함)
- uses: actions/checkout@v2
  with:
    clean: false

github repository 를 clone 혹은 fetch 한다

  • 다만 추가적으로 실행할 때 빠르게 받아올 수 있도록 clean: false 을 설정했다
- name: Use Node.js 16.x
  uses: actions/setup-node@v1
  with:
    node-version: 16.x

- name: Install dependencies
  working-directory: service
  run: npm install

부가적인 환경설정

  • node 환경 준비
  • npm dependencies 설치
- name: Stop old server (ignore error)
  run: |
    killall -9 node || true

- name: Remove old server in ~/soruce (ignore error)
  run: |
    rm -rf ~/source || true

기존에 배포된 서버 Clean Up

  • 기존에 구동중인 node 서버 모두 kill
  • 기존에 설치된 ~/source 폴더 제거
  • 두 action 모두 에러가 날 수 있기 때문에 오류를 무시하도록 || true 추가
- name: Copy new server to ~/soruce
  run: |
    mkdir -p ~/source
    cp -R ./ ~/source

runner 폴더에 저장된 repository 를 ~/source 로 복사

  • cp 하는데 폴더가 없으면 에러가 발생해서 mkdir -p ~/source 를 먼저 실행해서 폴더를 만들어 둔다
- name: Run new server (in background)
  env:
    RUNNER_TRACKING_ID: ""
  run: |
    cd ~/source
    nohup npm run start </dev/null >/dev/null 2>&1 &

이 Article 에서 가장 핵심인 부분이다. (삽질을 많이 했다)

  • env 에 RUNNER_TRACKING_ID="" 를 등록한다. Runner 가 종료될 때 자동으로 붕뜨게 된 프로세스(=orphan process)를 모두 닫는데, background 로 띄워둔 서버도 같이 닫히게 된다. 비공식적인 부분이지만, 위 값을 등록해서 이를 방지한다.
  • nohup 은 로그아웃 신호를 무시하는 프로세서이다
  • npm run start 가 원래 서버를 구동하기 위한 명령어였다. (이 부분은 구성에 따라 수정이 필요하다)
  • </dev/null : 프로그램의 입력을 받지 않도록 함
  • >/dev/null : 프로그램의 출력을 받지 않도록 함
  • 2>&1 : 프로그램의 에러를 출력으로 보냄, (위의 >/dev/null 를 통해 무시하도록 함)
  • & 해당 프로세스를 백그라운드로 실행

여기까지 작업했으면 workflow 설정이 약간 복잡하긴 하지만, Github 을 통해 서버 배포를 할 수 있게 된다.
물론 scale out 을 고려하지 않기 때문에 가능한 구성이다.

profile
안정적인 서비스와 효율적인 협업을 추구하는 풀스택 개발자입니다 https://www.instagram.com/ronpark.dev/

1개의 댓글

comment-user-thumbnail
2022년 12월 10일

제 은인이십니다. 감사합니다 감사합니다 감사합니다. RUNNER_TRACKING_ID: "" 이걸 찾고 있었습니다.

답글 달기