Self-hosted action runner란?
GitHub Actions는 코드 변경을 자동으로 감지하여 빌드, 테스트, 배포 등의 작업을 수행할 수 있는 강력한 CI/CD 플랫폼입니다. 기본적으로 GitHub에서는 자체적으로 관리되는 호스티드 러너(Hosted Runner)를 제공하며, 사용자는 별도의 설정 없이 워크플로를 실행할 수 있습니다.
하지만 때로는 GitHub에서 제공하는 러너로는 한계가 있을 수 있습니다. 이럴 때 사용하는 것이 바로 self-hosted Action Runner입니다. Self-hosted runner는 GitHub Actions 워크플로를 실행할 수 있는 러너를 사용자가 직접 운영하는 방식으로, GitHub에서 제공하는 러너와 동일한 기능을 제공하면서도 다음과 같은 이점이 있습니다
- 비용 절감: GitHub의 호스티드 러너는 사용량에 따라 비용이 발생하지만, self-hosted runner는 자체 인프라를 활용하므로 요금을 줄일 수 있습니다.
- 높은 유연성: 필요에 따라 원하는 도구, 라이브러리, 하드웨어(GPU 등)를 설치해 커스텀 환경을 구성할 수 있습니다.
- 직접 제어 가능: runner의 리소스, 보안 정책, 확장 전략 등을 사용자가 직접 관리할 수 있습니다.
Runner Set과 Runner Controller
GitHub에서 사용자가 Self hosted runner를 운영할 수 있도록 Runner Set과 Runner Controller를 제공합니다. 이 둘은 서로 다른 목적을 가지고 있으며, 함께 사용하여 GitHub Actions의 유연성과 확장성을 극대화할 수 있습니다.
- Runner Set: GitHub Actions 워크플로를 실행하기 위한 러너의 집합을 정의합니다. 사용자는 Runner Set을 통해 필요한 리소스와 환경을 설정하고, GitHub Actions에서 사용할 수 있는 러너를 생성할 수 있습니다.
- Runner Controller: Runner Set을 관리하고, GitHub Actions와 통합하여 워크플로를 실행하는 역할을 합니다. Runner Controller는 Runner Set의 상태를 모니터링하고, 필요한 경우 자동으로 러너를 생성하거나 삭제하여 리소스를 효율적으로 관리합니다.
실습 환경 구성
minikube cluster 생성
필자는 개인 개발 환경에서 Minikube를 사용하고 있어, 아래와 같이 Kubernetes 클러스터를 생성하였습니다.
만약 이미 사용 중인 Kubernetes 클러스터가 있다면, 이 단계는 생략하셔도 괜찮습니다.
만약 구버전인 RunnerDeployment를 원하신다면 [구버전 사용법] 여기를 참고하세요.
# node 2대, CPU 2core, Memory 2GB
# CRI는 containerd, CNI는 cilium으로 구성하였습니다.
minikube start -p=runner-profile --nodes 2 \
--container-runtime=containerd --cni=cilium \
--cpus=2 --memory=2048MB \
--addons=metrics-server
Runner Set Controller 설치
# controller 설치
NAMESPACE="arc-systems"
helm upgrade --install arc \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller \
--namespace "${NAMESPACE}" --create-namespace
# 생성 확인
kubectl get pods -n arc-systems
# 결과
NAME READY STATUS RESTARTS AGE
arc-gha-rs-controller-57c67d4c7-kw2gg 1/1 Running 0 24h
values-docker.yaml 파일 구성
Docker in Docker(DinD) 모드로 실행하기 위한 설정 파일을 다음과 같이 작성합니다.
여기서 containerMode를 dind로 설정하면, runner 생성 시 docker:dind 컨테이너가 Sidecar 형태로 Runner와 함께 실행됩니다.
values-docker.yaml
# 자신이 사용하는 GitHub Repository의 URL을 입력합니다.
githubConfigUrl: "https://github.com/개인또는그룹깃헙/레포명"
# 개인 GitHub Token을 사용하여 인증합니다.
githubConfigSecret:
github_token: "ghp_1234567890..."
runnerScaleSetName: "docker-runner-set"
containerMode:
type: "dind"
kubernetesModeWorkVolumeClaim:
accessModes: ["ReadWriteOnce"]
storageClassName: "dynamic-blob-storage"
resources:
requests:
storage: 1Gi
Runner Set 생성
INSTALLATION_NAME="docker-runner-set"
NAMESPACE="arc-runners"
helm upgrade --install "${INSTALLATION_NAME}" \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set \
--namespace "${NAMESPACE}" --create-namespace \
-f values-docker.yaml
Runner Set이 GitHub에 등록되었는지 확인
GitHub Repository의 Actions > Runners 메뉴에서 등록된 Self-hosted runners 탭에서 정상적으로 등록되었는지 확인할 수 있습니다.

Workflow 실습 진행
필자는 개인 GitHub Private Repository를 구성하여 실습을 진행하였습니다. "arc-project"라는 이름의 Repository를 생성하고, 간단한 코드와 Dockerfile을 작성하였지만 이번 문서의 주제는 GitHub Action Self-hosted Runner 구축이므로, 코드 내용과 Dockerfile 내용은 생략하였습니다.
GitHub Repo Secret 생성
Action Runner가 코드를 가져와 Docker 이미지를 빌드하고, 이를 DockerHub에 Push 하려면 GitHub Token과 DockerHub Token이 필요합니다. 하지만 이러한 민감한 값은 workflow 파일 내에 직접 작성하면 보안상 문제가 발생할 수 있습니다. 따라서 GitHub에서는 Repository의 Secrets 기능을 제공하며, 토큰과 같은 민감한 정보를 안전하게 저장하고 워크플로에서 참조할 수 있도록 하고 있습니다.
아래 경로를 따라 이동하여 DOCKER_TOKEN과 같은 필요한 이름으로 Secret을 생성하면 됩니다. 이렇게 등록한 값은 GitHub Actions 워크플로에서 ${{ secrets.DOCKER_TOKEN }} 형태로 안전하게 사용할 수 있습니다.
GitHub Repo >> Settings >> Secrets and variables >> Actions >> New repository secret

또한 Variables에서는 DOCKER_USERNAME, IMAGE_NAME 변수를 선언하여 ${{ vars.DOCKER_USERNAME }}, ${{ vars.IMAGE_NAME }}으로 사용할 수 있습니다.
GitHub Repo >> Settings >> Secrets and variables >> Actions >> New repository variables

Workflow 파일 작성
GitHub Actions의 Workflow 파일은 .github/workflows 디렉토리 내에 위치해야 하며, YAML 형식으로 작성되어야 합니다. 아래는 Docker 이미지를 빌드하고, 이를 DockerHub에 Push하는 간단한 예시입니다.
.github/workflows/docker-build-push.yaml
name: Docker build runner
on:
push:
branches: [ "**" ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
jobs:
docker-build:
runs-on: docker-runner-set
steps:
# 코드 체크아웃
- name: Checkout code
uses: actions/checkout@v2
# DockerHub 로그인
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
# QEMU 설정
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Docker Buildx 설정
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Docker meta 태그 생성
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ vars.DOCKER_USERNAME }}/${{ vars.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
# Docker 이미지 빌드 및 푸시
- name: Build and push
uses: docker/build-push-action@v6
with:
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
platforms: linux/amd64,linux/arm64
cache-from: type=registry,ref=${{ vars.DOCKER_USERNAME }}/${{ vars.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ vars.DOCKER_USERNAME }}/${{ vars.IMAGE_NAME }}:buildcache,mode=max
위와 같이 cache-from, cache-to 옵션을 추가하면 DockerHub Registry에 cache데이터가 추가됩니다. 그러나 우리의 환경은 self hosted이고 DockerHub은 외부에 있다보니 Image Cache가 네트워크로 이동하는 과정에서 생각보다 많은 딜레이가 발생할 수 있습니다. 그렇기 때문에 오히려 빌드의 속도가 오래 걸리는 문제가 될 수 있으므로 상황에 따라 cache-from, cache-to 옵션은 제외하셔도 됩니다. 만약 Image registry를 내부에 Harbor, Nexus를 사용한다면 보다 빠르게 이미지 빌드를 수행할 수 있습니다.
이번 workflow에서는 linux/amd64, linux/arm64 2가지의 platform으로 빌드를 진행하지만 본인의 확경이 하나의 platform 환경에서만 구동 된다면 QEMU, Buildx 부분을 삭제하여 보다 빠른 이미지 빌드를 수행할 수 있습니다.
Workflow 실행하여 결과 확인
이제 작성한 Workflow 파일을 GitHub Repository에 Push하면, GitHub Actions가 자동으로 실행됩니다. Actions 탭에서 실행 상태를 확인할 수 있으며, 성공적으로 빌드 및 푸시가 완료되면 DockerHub에서도 확인할 수 있습니다.
GitHub Repo >> Actions >> Workflow

마지막으로 Hosted runner VS Self hosted runner
저는 개인적으로 절대적인 정답은 없다고 생각합니다. 따라서 Hosted Runner와 Self-hosted Runner의 장단점을 잘 비교하고, 각자의 환경과 목적에 맞는 최적의 선택을 하는 것이 중요합니다.
아래 표는 두 러너의 특성을 비교한 내용입니다. 표를 참고하셔서 여러분의 개발 환경에 가장 잘 맞는 러너를 선택하시기 바랍니다.
항목 | GitHub Hosted Runner | Self-hosted Runner |
인프라 제공 | GitHub에서 자동으로 VM 제공 | 사용자가 직접 서버/VM/Kubernetes 구성 |
비용 | 일정 사용량 이후 과금됨 | GitHub에는 무료, 인프라 비용은 사용자 부담 |
환경 커스터마이징 | 제한적 (사전 설치된 도구만 사용 가능) | 원하는 도구, 라이브러리, 하드웨어 설정 가능 |
실행 속도 | 동시 job 수 제한 시 대기 가능성 있음 | 러너 수 확장으로 빠르게 실행 가능 |
보안 | GitHub 클라우드에서만 실행 | 사내망, VPC 등 폐쇄 환경에서도 사용 가능 |
참고 문서
도커 공식 문서 : Docker GitHub Action
Self hosted runner 사용법 : Github self hosted
'DevOps' 카테고리의 다른 글
[GitHubAction] Self-hosted Runner(in Kubernetes) RunnerDeployment DinD 구축하기 (0) | 2025.05.11 |
---|---|
[Kubernetes] Pod Resource CPU 0.5 설정과 CFS 관계 (0) | 2025.04.27 |
[Helm] helm hook 사용법 (0) | 2025.04.26 |
[Terraform] 기본 개념과 기본 사용법 (0) | 2025.04.22 |
[CI/CD] GitHub Action을 이용한 CI 설정하기 (0) | 2025.04.19 |