Backend/기타

[GitHub Actions] Self-Hosted Runner를 활용한 CI 파이프라인 구축

sangwonYoon 2023. 7. 5. 21:50

지난 프로젝트에서 CI 파이프라인을 구축한 방법

지난 Open Domain Question Answering 프로젝트를 진행하면서 CI 파이프라인을 구축하기 위해 GitHub에서 제공하는 서버(GitHub-hosted runner)에서 GitHub Actions를 사용했다. 그러나, GitHub-hosted runner는 하드웨어적인 한계나 서버 인프라를 직접 관리할 수 없다는 한계가 있었기 때문에, 새로운 프로젝트에서는 self-hosted runner를 활용하기로 결정했다. 

 

GitHub-hosted runner의 한계점

  1. GPU를 활용할 수 없다.
    GitHub-hosted runner에서 GPU를 활용하기 위해서는 Team 또는 Enterprise plan에 가입해야 하는 것으로 알고 있다. 따라서 사실상 CPU밖에 활용할 수 없는 상황이라 매우 적은 양의 데이터로 모델의 학습 또는 추론을 테스트하더라도 시간이 오래 걸릴 수 밖에 없다. 반면, GPU가 있는 self-hosted runner를 사용한다면 이러한 시간을 상당히 단축시킬 수 있다.

  2. 저작권 문제가 있는 데이터를 활용한 테스트가 어렵다.
    데이터에 저작권 문제가 있는 경우, GitHub 저장소에 업로드할 수 없다. 따라서 지난 Open Domain Question Answering 프로젝트에서 테스트를 할 때에는 실제 데이터와 같은 형식의 가짜 데이터를 활용했는데, 이 경우에는 직접 데이터를 제작해야 하기 때문에 번거롭고, 많은 양을 만들기엔 시간적 제약이 존재할 뿐더러, 가짜 데이터에 bias가 존재해 제대로 된 테스트를 진행하기 어렵다는 우려가 있다. 하지만 self-hosted runner를 활용한다면 미리 서버에 데이터를 저장해둔 뒤, 해당 데이터를 활용하여 테스트를 진행할 수 있기 때문에 앞서 언급한 모든 문제들을 해결할 수 있다.

  3. 매 작업마다 모델과 종속 라이브러리를 새롭게 설치해야 한다.
    GitHub-hosted runner는 매 작업을 실행할 때마다 서버 인스턴스를 초기화하기 때문에, 모델과 종속 라이브러리를 매번 새롭게 설치해야 한다. 모델의 크기가 커지고 종속 라이브러리가 많아질수록 설치하는 시간이 많이 소요된다. 그러나 self-hosted runner를 사용하면 미리 모델과 종속 라이브러리를 설치해놓을 수 있기 때문에, 변경 사항이 있는 경우에만 설치를 하여 설치에 소요되는 시간을 절약할 수 있다.

 

self-hosted runner 등록

먼저, GitHub Actions에 사용할 서버를 등록해야 한다.

1. 저장소에서 Settings 탭을 클릭한다.

 

2. 좌측에 있는 Actions 탭에서 Runners를 클릭한다.

 

3. New self-hosted runner 버튼을 클릭해 서버의 운영체제에 맞는 등록 방식을 확인한다. 나는 GPU가 있는 Windows 데스크탑을 서버로 사용하기 위해 Windows의 등록 방식을 따랐다.

(Windows OS 기준) powershell에 주어진 명령어를 입력한다.

 

4. Configure을 보면 GitHub 저장소의 url과 인증 토큰을 등록해야 하는데, GitHub Actions에서 서버에 접근하는 방식이 아니라 서버가 GitHub Actions를 listening하는 방식이기 때문에 서버에 이러한 설정이 필요하다.

 

5. 여기까지 진행하면 서버가 GitHub에 등록이 완료된다.

 

6. (Windows OS 기준) run.cmd 파일을 실행시키면 서버를 활성화시킬 수 있다.

 

workflow 작성

이전에 작성했던 workflow 파일과 다른 부분을 중점적으로 살펴보자.

이전에 작성한 workflow 파일 보러가기

 

내가 작성한 workflow 파일은 아래와 같다.

name: Python application

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: self-hosted

    steps:
    - name: Update Code
      run: git pull
      working-directory: C:\Programming\boostcamp\mlops_practice

    - name: install dependencies
      run: |
        github_actions/Scripts/activate
        pip install -r requirements.txt
      working-directory: C:\Programming\boostcamp\mlops_practice
      
    - name: Get Model
      run: |
        ../github_actions/Scripts/activate; 
        $targetPath = "C:\Programming\boostcamp\mlops_practice\webapp\model"; 
        if (-not (Test-Path -Path "$targetPath" -PathType Container)) {
          git clone https://huggingface.co/SangwonYoon/klue-roberta-large-tapt model
        }
      working-directory: C:\Programming\boostcamp\mlops_practice\webapp
  
    - name: Test with pytest
      run: |
        github_actions/Scripts/activate
        pytest
      working-directory: C:\Programming\boostcamp\mlops_practice
  • runs-on: self-hosted
    self-hosted runner를 사용하여 workflow를 수행한다.

  • working-directory
    working-directory를 명시하지 않으면, 매 step마다 기본 working directory로 돌아가기 때문에 기본 working directory 밖에서 workflow를 수행해야하는 경우에는 working directory를 명시해야 한다. 기본 working directory는 self-hosted runner를 등록할 때 설정한다.
  • 가상 환경
    virtualenv를 통해 가상 환경을 구축하여 로컬 환경과 분리된 환경에서 workflow를 수행했다. 그런데 가상 환경을 활성화하더라도 다음 step으로 넘어가면 가상 환경이 비활성화되는 현상을 발견하여 현재는 매 step마다 가상 환경을 활성화하도록 구현했다.
  • “Get Model” step
    모델 폴더가 존재하는지 확인하고, 없다면 git clone을 통해 huggingface 저장소에 저장된 모델을 다운로드하도록 구현했다.

 

GitHub-hosted runner와의 실행 시간 비교

같은 작업을 GitHub-hosted runner로 수행했을 때 3분 20초가 걸린 반면, self-hosted runner(모델과 종속 라이브러리가 설치되어 있는 상태)로 수행했을 때는 20초가 걸렸다. 이러한 차이는 종속 라이브러리의 크기, 모델의 크기가 커지거나 GPU를 활용한 테스트를 수행해야 하는 상황에서 더 크게 벌어질 것이다.