셀프호스티드 러너를 도입하기 전에 확인할 것

GitHub Actions는 기본적으로 GitHub이 제공하는 가상 머신에서 워크플로를 실행한다. 셀프호스티드 러너(self-hosted runner)는 이 실행 위치를 직접 준비한 머신으로 옮기는 방식이다. 러너 애플리케이션을 설치한 서버가 GitHub에 자신을 등록하고, 큐에 들어온 잡을 받아 실행한다. 겉보기에는 실행 장소만 바뀌는 것 같지만, 실제로는 머신의 준비·보안·유지보수 책임이 전부 사용하는 쪽으로 넘어온다. 이 책임 이동을 감당할 이유가 있는지가 도입 판단의 출발점이다.

GitHub 호스티드 러너와 무엇이 다른가

가장 큰 차이는 실행 환경의 수명이다. GitHub 호스티드 러너는 잡마다 새 가상 머신이 할당되고 끝나면 폐기된다. 셀프호스티드 러너는 기본 설정에서 같은 머신을 계속 재사용하므로, 이전 잡이 남긴 빌드 산출물·캐시·환경 변수·로그인 상태가 다음 잡에 그대로 남는다. 공식 문서도 이 점을 셀프호스티드 러너의 특성으로 명시한다.

항목 GitHub 호스티드 러너 셀프호스티드 러너
머신 준비·유지보수 GitHub이 담당 사용자가 담당
실행 환경 초기화 잡마다 새 인스턴스, 종료 후 폐기 기본은 재사용, 초기화하려면 별도 구성 필요
사전 설치 도구 러너 이미지에 포함된 툴체인 제공 필요한 런타임·빌드 도구를 직접 설치
하드웨어·OS 선택 제공되는 사양 중 선택 물리 서버, VM, 컨테이너, 온프레미스 자유
사내망·전용 장비 접근 공개 엔드포인트 위주 내부 네트워크·라이선스 장비 직접 접근 가능
Actions 사용 분 과금 플랜별 무료 분 소진 후 과금 러너 사용 자체에는 Actions 분 과금이 없음(머신 비용은 별도)
공개 저장소 사용 제한 없음 공식 문서에서 권장하지 않음
잡 최대 실행 시간 공식 문서 기준 6시간 공식 문서 기준 5일

공개 저장소에서 권장되지 않는 이유

GitHub 공식 문서는 퍼블릭 저장소에 셀프호스티드 러너를 붙이지 말라고 명시적으로 경고한다. 누구나 저장소를 포크해 풀 리퀘스트를 열 수 있고, 그 풀 리퀘스트에 포함된 워크플로 코드가 러너 머신에서 실행될 수 있기 때문이다. 결과적으로 외부에서 제출한 코드가 머신의 파일 시스템, 로컬에 남은 자격 증명, 그리고 그 머신이 접근 가능한 내부 네트워크까지 닿을 수 있다. 이 위험은 설정으로 완전히 제거되지 않으므로, 셀프호스티드 러너는 프라이빗 저장소나 통제된 조직 범위에서 쓰는 것이 전제다.

등록 범위 — 저장소·조직·엔터프라이즈

러너는 저장소 단위, 조직 단위, 엔터프라이즈 단위 중 하나로 등록한다. 저장소 단위는 해당 저장소 전용이고, 조직 단위는 조직 내 여러 저장소가 공유한다. 저장소마다 러너를 따로 두면 관리 대상이 저장소 수만큼 늘어나므로, 두 개 이상 저장소가 같은 빌드 환경을 쓴다면 처음부터 조직 단위로 올리는 편이 낫다. 다만 범위를 넓힐수록 접근 통제가 중요해지고, 이때 러너 그룹을 함께 설계해야 한다.

설치와 등록 절차

사전 요건 — OS, 아키텍처, 네트워크

러너 애플리케이션은 리눅스, 윈도우, macOS에서 동작하며 x64와 ARM64 계열을 지원한다. 지원 목록은 러너 버전에 따라 갱신되므로 설치 전 공식 문서의 지원 아키텍처 표를 확인하는 것이 안전하다. 네트워크 요건은 단순한 편이다. 러너가 GitHub 쪽으로 HTTPS 아웃바운드 연결을 열어 잡을 가져오는 구조이므로 인바운드 포트를 열 필요가 없다. 방화벽에서 아웃바운드를 통제하는 환경이라면 GitHub이 문서로 공개하는 도메인 목록과 메타 정보 API를 기준으로 허용 목록을 만든다. 프록시 환경에서는 러너 디렉터리의 환경 파일이나 프록시 관련 환경 변수로 설정한다.

등록 토큰과 config 실행

등록은 저장소나 조직의 설정 화면에서 Actions 러너 추가 메뉴를 열면 나오는 명령을 그대로 따르는 방식이다. 순서는 러너 패키지 내려받기, 압축 해제, 설정 스크립트 실행, 실행 스크립트 기동이다. 리눅스와 macOS는 config.shrun.sh, 윈도우는 config.cmdrun.cmd를 쓴다. 설정 단계에서 대상 URL과 등록 토큰을 입력하고, 러너 이름과 레이블, 작업 디렉터리를 지정한다.

서비스 등록과 제거

실행 스크립트를 직접 띄우면 터미널 세션이 끊길 때 같이 종료된다. 상시 운영에는 서비스 등록이 기본이다. 리눅스와 macOS는 러너 디렉터리의 서비스 스크립트로 설치·시작·상태 확인을 하고, 윈도우는 설정 단계에서 서비스로 실행할지 묻는다. 머신을 폐기할 때는 파일만 지우지 말고 제거 명령으로 GitHub 쪽 등록을 함께 해제해야 목록에 오프라인 러너가 쌓이지 않는다. 러너 애플리케이션은 기본적으로 자동 업데이트되며, 업데이트를 끄는 옵션을 쓰면 버전이 지원 범위를 벗어나지 않도록 관리하는 책임이 생긴다.

워크플로에서 러너를 지정하는 법

레이블 설계가 곧 라우팅 규칙이다

등록된 러너에는 self-hosted와 운영체제 레이블, 아키텍처 레이블이 기본으로 붙는다. 워크플로의 실행 대상 지정에 self-hosted 하나만 쓰면 조건을 만족하는 아무 러너에나 잡이 배정된다. GPU가 필요한 잡이 GPU 없는 머신으로 가거나, 특정 라이선스가 설치된 머신에서만 돌아야 할 잡이 엉뚱한 곳에서 실패하는 문제가 여기서 생긴다. 기본 레이블에 더해 용도를 나타내는 사용자 레이블을 붙이고, 워크플로에서는 레이블 배열로 교집합을 지정하는 편이 안전하다. 기본 레이블과 같은 이름의 사용자 레이블은 만들 수 없다.

러너 그룹으로 접근 제어

레이블은 어떤 머신에서 돌릴지를 고르는 장치이지 누가 쓸 수 있는지를 막는 장치가 아니다. 조직이나 엔터프라이즈 단위로 등록한 러너는 러너 그룹으로 묶어 어떤 저장소와 어떤 워크플로가 접근할 수 있는지를 제한한다. 그룹 기능의 제공 범위는 플랜에 따라 다르므로 조직 설정 화면에서 실제 노출 여부를 확인한다. 사내망에 접근 가능한 러너일수록 그룹 범위를 좁게 잡는 것이 원칙이다.

큐 대기와 실행 시간 제한

셀프호스티드 러너를 쓰면 실행 시간 제한이 느슨해지는 대신 대기 문제가 생긴다. 공식 문서 기준으로 잡 하나는 최대 5일까지 실행할 수 있지만, 셀프호스티드 러너를 기다리는 잡은 최대 24시간까지만 큐에 머물고 그 뒤에는 실패 처리된다. 러너 대수보다 동시 요청이 많은 CI 환경에서는 이 대기 시간이 그대로 파이프라인 지연이 된다. 러너 대수, 잡 평균 실행 시간, 하루 워크플로 실행 횟수를 함께 놓고 용량을 계산해야 한다.

운영 방식 선택 — 상시, 임시, 자동 확장

세 가지 방식의 성격

방식 잡 간 격리 확장 운영 부담
상시 러너 없음(환경 누적) 수동 증설 낮음
임시 러너(ephemeral) 잡 1건 후 등록 해제 재생성 자동화 필요 중간
쿠버네티스 기반 자동 확장 파드 단위 격리 큐 길이에 따라 자동 높음

상시 러너와 임시 러너

상시 러너는 한 번 설치하면 계속 도는 가장 단순한 형태다. 캐시가 그대로 남아 빌드가 빠르다는 장점이 있지만, 같은 이유로 이전 잡의 흔적이 다음 잡에 영향을 준다. 임시 러너는 설정 시 일회성 옵션을 주어 잡 하나를 처리한 뒤 스스로 등록을 해제하게 만드는 방식이다. 매번 깨끗한 상태에서 시작하므로 격리 수준이 올라가지만, 잡이 끝날 때마다 새 러너를 만들어 등록하는 절차를 자동화해야 의미가 있다. 이때 미리 발급한 일회성 등록 정보를 쓰는 방식이 함께 사용된다.

쿠버네티스 기반 자동 확장

큐 길이에 따라 러너 수를 자동으로 늘리고 줄이는 방식은 GitHub이 공개한 러너 컨트롤러를 쿠버네티스에 올려 구성한다. 잡마다 파드가 뜨고 사라지므로 격리와 확장을 동시에 얻지만, 클러스터 운영과 이미지 관리라는 별도 부담이 생긴다. 러너 몇 대로 충분한 규모에서 이 구성을 먼저 꺼내는 것은 과한 선택이다.

어떤 경우에 적합한가

셀프호스티드 러너가 유리한 조건

호스티드 러너를 유지하는 편이 나은 조건

정리하면 셀프호스티드 러너는 GitHub Actions의 실행 환경을 통제해야 할 분명한 이유가 있을 때 선택하는 수단이다. 접근해야 할 내부 자원이 있거나, 대체 불가능한 하드웨어·라이선스가 있거나, 실행량이 충분히 커서 비용 구조가 바뀌는 경우가 그 이유에 해당한다. 그런 이유 없이 도입하면 CI 파이프라인에 관리해야 할 서버가 하나 더 늘어날 뿐이다. 도입을 결정했다면 프라이빗 저장소 한정, 러너 그룹으로 범위 제한, 임시 러너로 잡 간 격리라는 세 가지를 기본값으로 잡고 시작하는 것이 안전하다. 세부 명령과 지원 플랫폼, 사용 제한 수치는 러너 버전에 따라 바뀌므로 구축 시점의 공식 문서를 기준으로 확인한다.