블로그 회사 시스템 구축기

GitHub Actions 무료 2,000분을 다 썼을 때 집 컴퓨터를 self-hosted 러너로 쓰는 방법

비공개 저장소 다섯 개를 돌리다가 월 2,000분 한도에 닿았습니다. 분을 줄이는 설정 세 가지, 집 컴퓨터를 조직 단위 러너로 등록하는 순서, 조직 변수 하나로 GitHub 러너와 집 러너를 오가는 구성을 적었습니다.

비공개 저장소가 다섯 개로 늘어난 시점에 GitHub Actions 무료 한도에 닿았습니다. 분을 줄이는 설정을 먼저 넣었고, 그래도 모자라서 집에 켜 둔 컴퓨터를 러너로 등록했습니다. 어디서 빌드할지는 조직 변수 하나로 바꿀 수 있게 해 뒀습니다.

git push 를 하면 조직 변수 BUILD_RUNNER 값에 따라 GitHub 러너 또는 집 컴퓨터 러너에서 빌드가 돈다

GitHub Actions 무료 한도와 러너별 요금

비공개 저장소에서 GitHub Free는 월 2,000분을 줍니다. 저장소가 늘고, 푸시할 때마다 Docker 이미지를 만들고, 테스트가 붙으면 금방 찹니다.

러너 종류에 따라 분당 요금이 다릅니다. GitHub 공식 요금 문서 기준입니다(2026년 10월 확인).

러너분당 요금
리눅스 2코어 x640.006달러
윈도우 2코어0.010달러
macOS 3~4코어0.062달러

macOS 러너는 리눅스 2코어보다 분당 요금이 10배가량 높습니다. 같은 문서에 self-hosted 러너에서 돈 작업은 Actions 사용 요금이 없다고 나와 있습니다.

한도에 닿으면 워크플로가 실행되지 않습니다. 결제 수단을 등록하면 초과분이 과금되고, 등록하지 않으면 다음 달까지 기다려야 합니다.

1단계: 러너를 옮기기 전에 분부터 줄이기

러너를 옮기기 전에 아래 세 가지 설정을 먼저 넣었습니다.

문서만 고친 커밋은 빌드하지 않는다

README나 문서만 고친 커밋에서는 Docker 이미지를 다시 만들 필요가 없습니다.

on:
  push:
    branches: [main]
    paths-ignore:
      - '**.md'
      - 'docs/**'
      - '.github/ISSUE_TEMPLATE/**'

paths-ignore로 걸러진 커밋은 워크플로가 아예 실행되지 않습니다. 이 워크플로를 필수 상태 검사로 걸어 두었다면 병합이 계속 대기 상태로 남습니다. 필수 검사로 쓰는 잡이라면 paths-ignore 대신 잡 안에서 조건 분기로 건너뛰게 하는 편이 안전합니다.

진행 중이던 앞 빌드는 취소한다

연달아 푸시하면 앞 빌드가 끝까지 돌면서 분을 씁니다.

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

main 브랜치 배포 워크플로에는 조심해서 겁니다. 배포 도중에 취소되면 중간 상태가 남을 수 있습니다. 저는 테스트·빌드 워크플로에만 걸고, 실제 배포 단계는 취소되지 않게 두었습니다.

캐시를 켠다

캐시가 없으면 의존성 설치가 매번 처음부터 돕니다.

- uses: actions/setup-node@v4
  with:
    node-version: '22'
    cache: 'npm'

# Docker 빌드라면
- uses: docker/build-push-action@v6
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

2단계: 집 컴퓨터를 self-hosted 러너로 등록하기

줄여도 모자라면 빌드가 도는 컴퓨터를 바꿉니다. GitHub이 빌려주는 컴퓨터 대신 내가 가진 컴퓨터를 러너로 등록합니다.

어디에 등록할지 먼저 정한다

범위쓰는 경우
저장소 단위한 저장소에서만 쓴다
조직 단위저장소 여러 개가 같이 쓴다

저는 저장소 다섯 개가 같은 러너를 쓰기 때문에 조직 단위로 등록했습니다. 저장소마다 따로 등록하면 같은 기계에 러너 프로세스가 다섯 개 뜹니다.

설치

조직 설정의 Actions → Runners → New runner 화면에 그 기계에 맞는 명령이 그대로 나옵니다. 리눅스 x64 기준으로는 이런 모양입니다.

mkdir actions-runner && cd actions-runner

curl -o actions-runner-linux-x64.tar.gz -L \
  https://github.com/actions/runner/releases/download/v2.x.x/actions-runner-linux-x64-2.x.x.tar.gz
tar xzf actions-runner-linux-x64.tar.gz

./config.sh --url https://github.com/<조직명> --token <등록토큰> --labels self-hosted,linux,x64

버전과 토큰은 화면에 나오는 값을 그대로 씁니다. 등록 토큰은 한 시간 뒤 만료됩니다.

서비스로 등록해서 재부팅 뒤에도 켜지게 하기

./run.sh로 띄우면 터미널을 닫을 때 같이 꺼집니다. 서비스로 등록합니다.

sudo ./svc.sh install
sudo ./svc.sh start
sudo ./svc.sh status

macOS라면 svc.sh가 launchd 에이전트를 만들어 줍니다. 이때 로그인 세션 밖에서도 도구를 찾을 수 있는지 확인해야 합니다. 로그인 셸에서만 PATH가 채워지는 구성이면 서비스로 뜬 러너에서 docker: command not found가 납니다. 같은 원인을 SSH로 명령을 던지면 command not found 가 나는 이유에서 다뤘습니다.

아키텍처를 맞춘다

Docker 이미지를 굽는다면 이 부분이 중요합니다. GitHub 호스팅 러너는 x86_64입니다. 자체 러너가 Apple 실리콘(arm64)이면 같은 Dockerfile로도 다른 아키텍처 이미지가 나옵니다. 운영 서버가 x86_64라면 그 이미지는 안 돕니다.

선택지는 두 가지입니다. 아키텍처가 같은 기계를 러너로 쓰거나, docker buildx로 크로스 빌드하는 것입니다. 크로스 빌드는 QEMU 에뮬레이션이 붙어 느려지므로, 저는 아키텍처가 같은 기계를 골랐습니다.

3단계: 조직 변수 하나로 GitHub 러너와 집 러너 오가기

워크플로에 runs-on: self-hosted를 직접 박으면, 그 기계가 꺼졌을 때 모든 저장소의 빌드가 멈춥니다.

그래서 어디서 돌릴지를 변수 하나로 뺐습니다.

jobs:
  build:
    runs-on: ${{ vars.BUILD_RUNNER || 'ubuntu-latest' }}
    steps:
      - uses: actions/checkout@v4
      # ...

조직 변수(Settings → Secrets and variables → Actions → Variables)에 BUILD_RUNNER를 self-hosted로 넣어 두면 집 컴퓨터에서 돕니다. 그 값을 지우면 ubuntu-latest로 되돌아갑니다.

이렇게 해 두면 좋은 점은 세 가지입니다.

  • 코드를 고치지 않고 오갈 수 있습니다. 커밋도 배포도 필요 없습니다.
  • 변수가 조직 단위라 저장소 다섯 개가 한 번에 바뀝니다.
  • 집 컴퓨터를 껐거나 급하게 빌드해야 할 때 변수만 지우면 됩니다.

한 가지 주의할 점은, 자체 러너가 오프라인인 상태에서 BUILD_RUNNER가 켜져 있으면 잡이 실패하지 않고 큐에서 대기한다는 것입니다. 러너가 다시 연결될 때까지 실패 알림 없이 기다립니다. 기계를 꺼둘 거라면 변수도 같이 지우는 편이 낫습니다.

공개 저장소에는 self-hosted 러너를 붙이지 않는다

자체 러너를 공개 저장소에 붙이면 안 됩니다. 공개 저장소는 누구나 풀 리퀘스트를 올릴 수 있고, 포크에서 올라온 워크플로가 자체 러너에서 실행될 수 있습니다. 남이 작성한 코드가 내 컴퓨터에서 도는 상태가 됩니다.

GitHub 공식 문서도 self-hosted 러너는 공개 저장소에 거의 쓰지 말아야 한다고 적고 있습니다(Secure use reference). 저는 비공개 저장소에만 붙였고, 빌드 머신과 실제 서비스가 도는 서버도 분리했습니다. 빌드는 이미지를 만들어 레지스트리에 올리는 데까지만 하고, 운영 서버는 그 이미지를 받아 갑니다.

비용과 빌드 속도

GitHub에 내는 분당 요금은 0원이 됩니다. 대신 그 컴퓨터를 켜 두는 전기 요금이 듭니다. 이미 다른 용도로 24시간 켜 두는 기계가 있다면 추가 비용은 거의 없습니다.

빌드 시간은 기계 사양을 그대로 따라갑니다. 오래된 기계라면 GitHub 호스팅 러너보다 느릴 수 있습니다. 저는 배포가 급하지 않은 작업은 자체 러너에서 돌리고, 급할 때만 변수를 되돌리는 방식으로 씁니다.

자주 묻는 질문

GitHub Actions 무료 분은 얼마나 주어지나요?

비공개 저장소 기준으로 GitHub Free는 월 2,000분입니다. 러너 종류에 따라 분당 요금이 달라서, macOS 러너는 리눅스 2코어 러너보다 분당 요금이 10배가량 높습니다(2026년 10월 기준). 공개 저장소는 GitHub 호스팅 러너가 무료입니다.

자체 러너를 붙이면 정말 무료인가요?

GitHub에 내는 분당 요금은 없습니다. 대신 전기 요금과 그 컴퓨터를 켜 두는 비용이 듭니다. 이미 켜져 있는 기계가 집에 있다면 추가 비용은 사실상 전기 요금뿐입니다.

공개 저장소에도 자체 러너를 붙여도 되나요?

권장하지 않습니다. 공개 저장소는 누구나 풀 리퀘스트를 올릴 수 있고, 그 안의 워크플로가 자체 러너 위에서 실행될 수 있습니다. 남이 작성한 코드가 내 컴퓨터에서 도는 상황이 되므로 GitHub 공식 문서도 공개 저장소에는 쓰지 말 것을 명시하고 있습니다.

자체 러너로 옮기면 빌드가 느려지나요?

기계 사양에 따라 다릅니다. 오래된 데스크톱이라면 GitHub 호스팅 러너보다 느릴 수 있습니다. 그래서 어디서 돌릴지를 변수로 빼 두고, 급할 때는 다시 GitHub 쪽으로 돌리는 구성을 권합니다.

#GitHub Actions#CI/CD#자가호스팅#1인 개발