Migrating Your GitHub CI to Hugging Face Jobs
Quick Summary
GitHub Actions의 제어 흐름은 유지하면서 실제 CI 작업을 허깅페이스 잡스의 임시 CPU·GPU 러너에서 실행하면, 맞춤형 하드웨어와 컨테이너 이미지를 활용해 속도와 GPU 테스트 범위를 개선할 수 있다.
🖼️ 인포그래픽
🖼️ 4컷 인포그래픽
💡 한 줄 요약
GitHub Actions의 제어 흐름은 유지하면서 실제 CI 작업을 허깅페이스 잡스의 임시 CPU·GPU 러너에서 실행하면, 맞춤형 하드웨어와 컨테이너 이미지를 활용해 속도와 GPU 테스트 범위를 개선할 수 있다.
📌 핵심 요약
- 트래키오는 GitHub 호스팅 러너의 속도, 유지보수 중단 가능성, 범용 환경, 제한적인 GPU 접근 문제를 해결하기 위해 CI 실행 환경을 허깅페이스 잡스로 이전했다.
- 허깅페이스 잡스는 실행 명령, 도커 이미지, CPU 또는 GPU 하드웨어, 환경 변수와 비밀값을 지정해 서버리스 환경에서 작업을 실행하는 서비스다.
- 디스패처 스페이스와 GitHub 앱이 대기 중인 워크플로 작업을 감지하고, 단기 등록 토큰을 발급해 허깅페이스 잡스 안에 일회성 자체 호스팅 러너를 생성한다.
- 사용자는 디스패처 스페이스와 GitHub 앱을 구성한 뒤 워크플로의 runs-on 값을 hf-jobs-cpu-upgrade 또는 hf-jobs-t4-small 같은 레이블로 바꾸면 된다.
- 트래키오 사례에서는 적절한 플레이wright 이미지를 사용한 CPU 작업이 1분 10초로 기존보다 약 30% 빨라졌고, t4-small GPU 검사는 45초 만에 완료됐다.
🧩 주요 포인트
- 트래키오는 GitHub 호스팅 러너의 속도, 유지보수 중단 가능성, 범용 환경, 제한적인 GPU 접근 문제를 해결하기 위해 CI 실행 환경을 허깅페이스 잡스로 이전했다.
- 허깅페이스 잡스는 실행 명령, 도커 이미지, CPU 또는 GPU 하드웨어, 환경 변수와 비밀값을 지정해 서버리스 환경에서 작업을 실행하는 서비스다.
- 디스패처 스페이스와 GitHub 앱이 대기 중인 워크플로 작업을 감지하고, 단기 등록 토큰을 발급해 허깅페이스 잡스 안에 일회성 자체 호스팅 러너를 생성한다.
- 사용자는 디스패처 스페이스와 GitHub 앱을 구성한 뒤 워크플로의 runs-on 값을 hf-jobs-cpu-upgrade 또는 hf-jobs-t4-small 같은 레이블로 바꾸면 된다.
- 트래키오 사례에서는 적절한 플레이wright 이미지를 사용한 CPU 작업이 1분 10초로 기존보다 약 30% 빨라졌고, t4-small GPU 검사는 45초 만에 완료됐다.
🧠 상세 정리
1. 마이그레이션의 배경과 목표
많은 저장소는 간단한 설정만으로 머신을 제공받을 수 있다는 이유로 GitHub Actions의 ubuntu-latest 호스팅 러너를 기본 CI 환경으로 사용한다. 그러나 이 환경은 작업이 느려지거나 유지보수로 중단될 수 있고, 제공되는 머신이 범용 구성이며, 오픈소스 프로젝트가 실제 GPU 하드웨어를 손쉽게 사용하는 데에도 한계가 있다. 트래키오는 기본 단위 테스트와 프런트엔드 검사를 위한 안정적인 CPU CI뿐 아니라 CUDA 하드웨어에서만 확인할 수 있는 GPU 테스트도 필요했다. 이에 GitHub Actions가 워크플로의 제어와 상태 보고를 계속 담당하되, 실제 작업은 허깅페이스 잡스에서 실행하는 구조를 구축했다. 그 결과 CPU 작업 시간은 약 30% 줄었고, 이전에는 실행하기 어려웠던 GPU 전용 테스트 모음도 CI에 추가할 수 있었다.
2. 허깅페이스 잡스의 실행 모델
허깅페이스 잡스는 허깅페이스의 서버리스 인프라에서 명령이나 스크립트를 실행할 수 있도록 하며, 작업마다 필요한 하드웨어 종류를 선택하게 해준다. 하나의 작업은 실행할 명령, 도커 허브 또는 허깅페이스 스페이스에서 가져올 도커 이미지, CPU나 t4-small·h200 같은 GPU 하드웨어, 선택적인 환경 변수와 비밀값으로 구성된다. 명령 중심이고 깨끗한 환경에서 시작한다는 점은 기존 CI 작업의 실행 방식과 잘 맞으며, 테스트 특성에 따라 필요한 하드웨어를 지정할 수 있다는 장점도 있다. 특히 기계학습 라이브러리는 상시 가동하는 자체 GPU 러너를 유지하지 않고도 실제 GPU에서 테스트 모음을 실행할 수 있다. 따라서 핵심 과제는 CI 자체를 새로 만드는 것이 아니라, GitHub Actions가 대기 중인 작업을 허깅페이스 잡스의 실행 환경에 안전하게 연결하도록 만드는 것이다.
3. GitHub Actions와 잡스를 연결하는 구조
이 연동을 위해 huggingface/jobs-actions라는 브리지가 사용되며, GitHub Actions 작업을 허깅페이스 잡스 내부에서 실행되는 임시 자체 호스팅 러너로 변환한다. 풀 리퀘스트가 워크플로를 시작하면 GitHub는 hf-jobs-cpu-upgrade 또는 hf-jobs-t4-small처럼 현재 사용할 수 없는 runs-on 레이블의 작업을 대기열에 넣고, GitHub 앱을 통해 서명된 workflow_job.queued 웹훅을 디스패처에 보낸다. 디스패처 스페이스는 웹훅을 검증하고 hf-jobs- 접두사가 붙은 레이블인지 확인한 뒤, 수명이 짧은 GitHub 러너 등록 토큰을 발급하고 해당 하드웨어의 허깅페이스 잡스를 시작한다. 새 잡스 컨테이너는 일회성 토큰으로 저장소에 러너를 등록하며, GitHub는 대기 중인 작업을 그 러너에 배정한다. 러너는 저장소의 워크플로 단계를 수행하고 GitHub에 상태를 보고한 뒤 종료되므로, GitHub에는 자체 호스팅 러너로 보이고 허깅페이스에는 워크플로를 실행하는 일반 잡스로 보인다.
4. 디스패처 스페이스 준비
첫 단계는 GitHub의 workflow_job 웹훅을 수신하고 그에 대응하는 허깅페이스 잡스를 시작하는 작은 도커 기반 디스패처 스페이스를 복제하는 것이다. GitHub 앱을 만들 때 웹훅 주소가 필요하고 그 주소는 스페이스에서 제공되므로, 디스패처를 먼저 생성해야 한다. 사용자는 쓰기 권한이 있는 개인 또는 조직 네임스페이스 아래에 huggingface/jobs-actions-dispatcher를 복제하고, 이름을 jobs-actions-dispatcher로 지정할 수 있다. 실제 CI에서는 GitHub 웹훅을 안정적으로 받을 수 있도록 cpu-upgrade 하드웨어가 권장되며, cpu-basic은 시험에는 사용할 수 있지만 비활성 상태에서 잠들 수 있어 깨어나는 동안 도착한 워크플로가 계속 대기할 가능성이 있다. 빌드가 끝난 스페이스의 첫 화면에는 다음 단계에서 사용할 네임스페이스별 웹훅 주소가 표시되며, 같은 복제 과정은 hf 명령줄 도구로도 수행할 수 있다.
5. GitHub 앱 생성과 권한 설정
다음 단계에서는 복제한 디스패처 스페이스의 설정 화면에 CI를 실행할 GitHub 조직과 저장소를 입력하고, 해당 화면에서 GitHub 앱 생성 절차를 시작한다. 이 앱은 대기 중인 워크플로 작업을 수신하고 임시 자체 호스팅 러너의 등록 토큰을 만들 수 있는 권한이 필요하다. 앱 이름은 사용자나 조직에서 사용할 수 있는 값이면 되며, 생성이 끝난 화면은 앱 자격 증명을 hf 명령줄 도구로 디스패처 스페이스에 올리는 구체적인 방법을 안내한다. 또한 잡스를 실행할 권한이 있는 허깅페이스 토큰을 준비해 디스패처 스페이스의 HF_TOKEN 비밀값으로 저장해야 하며, 이 토큰은 실제 비용이 귀속될 개인 또는 조직과 대응해야 한다. 마지막으로 앱을 앞서 지정한 GitHub 저장소에 설치해야 하며, 조직 저장소라면 조직 설정의 앱 설치 관리 화면에서 설치 대상을 선택한다.
6. 네임스페이스와 워크플로 변경
GitHub 앱 설정 과정에서 생성된 명령을 실행하면 앱 자격 증명, 웹훅 비밀값, 허깅페이스 토큰이 디스패처 스페이스에 등록된다. 기본적으로 허깅페이스 잡스는 디스패처 스페이스와 같은 네임스페이스에서 실행되지만, 비용을 다른 개인이나 조직에 귀속하려면 스페이스 변수 HF_NAMESPACE를 별도로 지정하고 스페이스를 다시 시작할 수 있다. 이때 앞 단계에서 설정한 토큰도 선택한 실행 네임스페이스에 대응하는 권한을 가져야 한다. 디스패처 구성이 끝나면 GitHub Actions 워크플로의 실제 변경은 작아서, 기존 runs-on: ubuntu-latest를 CPU 작업의 runs-on: hf-jobs-cpu-upgrade로 교체하면 된다. 실제 GPU가 필요한 테스트에는 runs-on: hf-jobs-t4-small 같은 GPU 레이블을 사용하며, 디스패처가 처리하는 레이블로 이 한 줄을 바꾸는 것이 개별 작업 이전의 핵심이다.
7. 시험 실행과 상태 확인
설정을 검증하려면 풀 리퀘스트, 기본 브랜치 푸시, 수동 실행에 반응하는 최소 워크플로를 만들고, 실행 레이블을 hf-jobs-cpu-upgrade로 지정할 수 있다. 워크플로 단계에는 저장소 체크아웃과 간단한 메시지 출력만 넣어도 GitHub에서의 작업 대기, 웹훅 전달, 잡스 생성, 임시 러너 등록, 작업 실행이라는 전체 흐름을 확인할 수 있다. 파일을 커밋하고 푸시한 뒤에는 gh run list로 최근 GitHub Actions 실행을 조회하고, hf jobs ps로 지정한 네임스페이스의 잡스 상태를 살펴본다. 문제가 있거나 처리 과정을 자세히 확인해야 할 때는 hf spaces logs로 디스패처 스페이스의 로그를 읽을 수 있다. 정상 동작하면 일반 GitHub Actions와 마찬가지로 실행 상태와 로그를 볼 수 있으며, 동시에 허깅페이스 쪽에서도 생성된 잡스와 실행 기록을 확인할 수 있다.
8. 이미지 선택, 성능 결과와 로그 활용
초기 CPU 구성은 ubuntu:22.04 이미지에서 매번 부족한 시스템 패키지를 설치했지만, GitHub의 ubuntu-latest와 달리 기본 개발 도구가 적어 불필요한 준비 시간이 발생했다. 트래키오의 사용자 인터페이스 테스트에는 플레이wright 브라우저, 노드, ffmpeg, sqlite, git과 일반적인 리눅스 빌드 의존성이 필요했기 때문에 mcr.microsoft.com/playwright:v1.60.0-jammy 이미지로 바꿨고, GPU 작업에는 nvidia/cuda:12.4.0-runtime-ubuntu22.04를 사용했다. 그 결과 CPU 작업은 GitHub 기준 1분 40초에서 1분 10초로 약 30% 빨라졌으며, t4-small GPU 검사는 45초 만에 통과했고 해당 시간의 비용은 1센트 미만이었다. 잡스 로그는 hf jobs logs 명령으로 파일에 저장해 로컬 도구나 코딩 에이전트로 분석할 수 있고, 브리지는 GitHub Actions 작업 로그도 잡스 로그에 복제해 양쪽에서 디버깅 정보를 제공했다. 트래키오 CI에서는 사용하지 않았지만 허깅페이스 잡스는 볼륨 마운트도 지원하므로, CI 중 허깅페이스의 데이터셋이나 모델을 빠르게 불러와야 하는 경우에 활용할 수 있다.
🧾 핵심 주장 / 시사점
- 이 구성은 GitHub Actions를 대체하는 것이 아니라, GitHub의 워크플로 관리와 상태 보고를 유지하면서 실행 머신만 필요할 때 생성되는 허깅페이스 잡스로 분리한다.
- CPU 작업의 성능 향상은 실행 플랫폼만 바꾼 결과가 아니라, 테스트에 필요한 도구가 미리 포함된 플레이wright 이미지를 선택해 매번 발생하던 패키지 설치 비용을 줄인 결과다.
- 트래키오 사례에서 가장 큰 변화는 기존 GitHub 호스팅 환경에 없던 GPU CI를 추가한 것으로, t4-small에서 실제 CUDA 테스트를 45초 안에 실행하면서 상시 GPU 러너 운영을 피했다.
✅ 액션 아이템
- GitHub Actions 제어 흐름은 유지한 상태에서 HF Jobs 이전 대상을 선별하고 CPU·GPU 워크플로를 분리 실행하도록 정한다.
- 디스패처 스페이스와 GitHub 앱을 구성해 pending 작업에서 단기 등록 토큰 발급 후 일회성 자체 호스팅 러너를 띄우는 경로를 반영한다.
- runs-on 라벨을 hf-jobs-cpu-upgrade 및 hf-jobs-t4-small로 변경하고 도커 이미지·환경변수·비밀값 조합을 맞춰 성능을 점검한다.
❓ 열린 질문
- CPU 워크플로에서 기존 대비 1분10초·약30% 단축이 실제 프로젝트에서도 재현되려면 어느 단계 구간에서 비교 측정해야 하는가?
- 플레이wright 사례와 유사한 수준으로 GPU 검사를 단축하려면 t4-small 이외에 어떤 하드웨어 구성 조합이 추가로 필요한가?
- 단기 등록 토큰 기반 즉시생성 러너가 긴 대기 큐에서도 안정적으로 작동하려면 토큰 수명 정책을 어떻게 조정해야 하는가?