You are currently viewing Self-hosted Github Action Runner로 GitHub 사용 비용 줄이기

Self-hosted Github Action Runner로 GitHub 사용 비용 줄이기

TL DR:

  1. GitHub Action의 비용은 일반 클라우드서비스 대비 4배정도 비쌈
  2. Self-Hosted로 전환하여 동일스펙 저렴비용 or 동일비용 높은스펙 확보 가능
  3. Cloud의 서비스와 유사하게, Managed vs Self-hosted 문제 > 관리포인트 증가


1. Intro

GitHub 기반의 환경에서 개발 환경을 구축할 경우, CI/CD 파이프라인 도구에 있어 Jenkins와 같은 별도 시스템을 외부에 구축하기도 하나, GitHub 환경과 긴밀히 통합되어있는 GitHub Action의 사용을 고려하기도 한다.


그러나 GitHub이 호스팅하는 GitHub-Hosted Runner의 경우 무료가 아니다. Enterprise 등급을 제외하고는 전체 파이프라인 작동시간에 대해 월간 2,000~3,000시간에 대해서 무료이지만, 그 외의 추가 사용시간에 대해 (일반적인) Linux 서버의 경우 시간당 0.008$의 비용이 청구된다.


현재 사용량이 무료 사용량 내에 해당한다면 GitHub-Hosted 액션을 사용하는게 유리하다. 별도의 보안적인 요구나 그외 특이 요구사항이 있지 않은 한, 굳이 Self-Hosted로 전환하여 추가적인 관리 부담 + Runner machine 운영비를 지불할 필요가 없기 때문이다.


그러나 사용량이 점점 많아져 무료 사용분으로 커버되지 않을 경우 그때부터는 Self-Hosted와의 편익을 비교해보는것이 좋다. 클라우드 서비스의 인스턴스 비용과 비교하기 위해, 추가 사용량에 대한 비용인 분당 0.008$를 시간당으로 환산하면 시간당 0.48$이다. 대부분의 기업 환경에서는 Private repository에서 운영할 것이기에, 프라이빗 레포의 깃헙호스트 러너의 스펙은 2코어 7기가 램이다. 이를 AWS의 기본 EC2 스펙에 대조해서 살펴보면, 대략 시간당 0.1$의 가격대로 4배정도 차이가 난다. 또한 EC2의 경우 Spot Instance나 RI/SP등의 정기계약으로 비용절감을 할 수 있다는점을 생각하면 비용의 차이는 꽤나 벌어진다

  • 같은 Spec의 머신을 1/4+a 가격으로 사용하기 (시간당 0.48$ vs 시간당 0.1x$)
  • 같은 비용으로, 2~4배 성능의 머신 사용하기 (2core,8GB Ram vs 4~8core,16~32GB Ram)


반대로 Self-Hosted Build 환경에는 관리 지점 증가라는 downside가 존재한다. 비용적인 측면으로만 접근하면 Self-hosted Runner를 사용하지 않을 이유가 없다. 그럼 무조건 좋아지기만 하는것인가? Self-hosted를 사용하기 위해서는 기존에 고려하지 않았던 여러 부분에 대해 결정을 해야한다

  • Self-hosted Runner의 보안
    • 기업의 코드나 내부 개발환경등 self-host 러너가 어디까지 접근할 수 있는가
    • Self-host의 버전관리는 어떻게?
  • (생략)의 환경 구성
    • 추후 살펴보겠지만 기본 Self-host는 alpine급의 깡통이미지이다.
    • 개발 환경에 맞게 러너의 구성을 어떻게 진행할것인가? 구성정보의 저장은?
    • 빌드 / 배포마다 독립적인 환경을 어떻게 제공할 수 있을지?
  • (생략)의 운영 안정성
    • 빌드머신이 안돌아요! > 파이프의 문제? vs Github의 문제? + Runner의 문제?(NEW!)
    • Runner 부하시 vs 평상시의 Gap을 어떻게 대응?
    • Self-host의 장애상황이면 어떻게 문제의 원인을 확인하고 대응할것인가


시작할때는 위와같은 downside의 구체적인 내용을 알지 못했고, 기존 러너노드의 스펙제한에 아쉬움이 있었기에 Self-hosted를 구축해서 사용해보았다. 그 과정을 공유하고자 한다.

2. Github Action Controller(ARC)

Self-hosted Runner의 경우 빌드 머신을 단일 머신에 직접 구성한뒤 사용하거나, Action Runner Controller를 사용해 k8s 클러스터 상에 빌드 머신을 pod 형태로 구성하여 사용할 수 있다.


단일 머신 형태의 경우, 기대했던 작동을 구성하기 위해선 별도의 스크립트 작업이 필요하다. 빌드 머신에서는 매 작동마다 독립된 환경을 제공하여야 한다. 그러나 별도의 pre-job 또는 post-job 스크립트를 구성하지 않으면 이전 작업 환경의 환경 변수 또는 artifact등이 남아 독립적인 작업 환경을 구성할 수 없었다. 또한 머신 자체가 1개의 Runner로 등록되기 때문에 한번에 하나의 작업만을 수행할 수 있다. 하나의 머신을 다수의 러너로 구성하려면 별도의 작업이 필요했다.


매번 작업마다 독립적인 환경보장? 엥 그거 항상 컨테이너 강의 1장 1강에 나오는 내용아니냐.. 단일머신 환경에서 기존의 작업 환경을 이어서 할 수 있는 부분을 긍정적으로 보았으나 작동에 아쉬운점이 많아 k8s 위에 컨테이너로 빌드머신을 구성하도록 전환하였다.

Github Action Controller는 2020년도에 Community버전으로 개발되다가 2023년 7월부터 GitHub에 공식적으로 채택되어 GitHub supported 버전으로 공식 출시 되었다.


내용에 summerwind 라는 키워드가 들어있으면 구 Community버전에 관한 정보라고 생각하면 된다.(또는 cert-manager 설치) k8s상에서 패키지 설치를 위해 자주 찾아보는 Helm(Artifact Hub)에서 또한, Artifact Hub에 등록된 Github Action Controller은 구 Community 버전으로 2023년 11월 이후로 업데이트가 중지되어있다. 현재 사용되는 GitHub supported ARC의 경우 Github Registry에서 관리되고 있다.

About Actions Runner Controller

Github Supported ARC의 경우 크게 gha-runner-scale-set-controller 이라는 operator/controlplane(제어부)와 gha-runner-scale-set/dataplane(실행부)로 나누어져 구성되어 있다

  • runner-scale-set-controller
    • operator 패턴으로 클러스터 내부에서 github과의 연결
    • HTTPS long poll 방식으로 인증 및 작업 현황 파악
    • 신규 workflow job 생성 시 하단의 runner-set으로 전달
  • gha-runner-scale-set
    • 클러스터 내부에서 workflow job을 수행하는 runner 그룹
    • autoscalingrunnerset
      • scaling 가능한 runner 설정 관리
    • ephemeralrunnerset
      • 실제 작업을 수행하고 있는 runner 확인


3. Local에서 Github Action Controller 테스트하기

기본적인 runner의 구성, 등록 및 테스트를 위해서 minikube를 사용한 로컬 k8s 환경에 k8s runner 환경을 등록해볼 것이다.


3.1. Minikube 환경 구성

minikube start

기본 구성

3.2. Installing Actions Runner Controller

NAMESPACE="arc-systems"
helm install arc \
    --namespace "${NAMESPACE}" \
    --create-namespace \
    oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller

artifacthub가 아닌 Github registry 환경이므로 별도의 helm repo add 대신 chart 저장소를 다이렉트로 찍어 배포한다.

chart에 대한 values의 경우, values.yaml 을 통해 확인할 수 있다. controller의 replica 수, 환경변수, 리소스 request/limit, 파드 스케줄링(nodeSelector, tolerations, affinity, topologySpreadConstraints), 로깅 등에 대한 설정을 확인할 수 있다.

3.3. Configuring a runner scale set

INSTALLATION_NAME="arc-runner-set"
NAMESPACE="arc-runners"
GITHUB_CONFIG_URL="https://github.com/<your_enterprise/org/repo>"
#GITHUB_CONFIG_URL="https://github.com/nasir17git" #계정/조직 내 모든 repo에 등곡
#GITHUB_CONFIG_URL="https://github.com/nasir17git/logonme" #특정 repository에 등록

GITHUB_PAT="<PAT>"
#GITHUB_PAT="github_pat_1xxx"
helm install "${INSTALLATION_NAME}" \
    --namespace "${NAMESPACE}" \
    --create-namespace \
    --set githubConfigUrl="${GITHUB_CONFIG_URL}" \
    --set githubConfigSecret.github_token="${GITHUB_PAT}" \
    oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set

ARC 컨트롤러와 유사하게, Runnerset 또한 해당 chart 저장소를 다이렉트로 찍어서 배포한다.

value 또한 values.yaml 통해 확인할 수 있다. 해당 release name으로 배포될 runner set의 배정 수준(조직,레포 단위) 및 인증정보(Github Apps 또는 PAT 토큰), Container mode (dind or dood), runner set 이름 및 replicas 개수 등을 설정할 수 있다.


배포가 끝나고나면, Github Web에서 Settings > Actions > Runners 항목에 Runner scale sets와 해당 설정으로 생성된 runner의 정보를 확인할 수 있다.

정상 작동중에는 Online

3.4. Using runner scale sets

# .github/workflows/demo.yaml
name: Actions Runner Controller Demo
on:
  workflow_dispatch:

jobs:
  Explore-GitHub-Actions:
    # You need to use the INSTALLATION_NAME from the previous step
    runs-on: arc-runner-set
    steps:
    - run: echo "🎉 This job uses runner scale set runners!"

위와 같은 workflow를 등록하여 배포된 ARC runner set에서 작업을 수행하는지 확인할 수 있다.


제일 큰 차이점은 runs-on: 필드에 ubuntu-latest 대신, 위에서 등록한 arc-runner-set 러너(그룹)명이 들어가있다는 점이다. 이를 통해 Github-Hosted가 아닌 Self-hosted runner에 workflow를 배정할 수 있다.

실제 action 수행기록 또한, 처음 Set up job시 k8s runner pod에 배정됨을 확인할 수 있다.

4. Outro

위의 테스트를 통해 기본적인 k8s cluster 상에 ARC pod를 배포하는 방법과, Github에 연결하여 workflow를 실행하는 과정을 살펴보았다.


그럼 이제 사용하면 되느냐? 하면 그렇지 않다. Github-Hosted Runner의 경우 원활한 사용을 위해 사전에 여러 개발도구가 내장되어 있다. (Ubuntu 24.04, Ubuntu 22.04) 그러나 Self-hosted Runner의 base image인 ghcr.io/actions/actions-runner의 경우 github action runner releaserunner container hooks만이 구성된 ubuntu 기반의 빈 머신이다. 실행시 github에 등록 및 종료시 github에 제거 외에 추가적인 도구는 하나도 구성되어있지않다 (curl, git 마저도!)


또는 빌드 환경 구성시 github action의 장점인 Action marketplace를 통해 구성할 수 있지 않느냐고 할 수 있다. 컨테이너 기반의 runner를 통해 매번 작업마다 독립된(=초기화된) 환경을 제공할 수 있지만 매번 setup단계를 반복적으로 수행하는것은 낭비아닐까.. 해당단계를 별도의 pvc에 마운트하여 캐싱을 한다면 설정시간/네트워크 사용량을 줄일 수 있지않을까?


마지막으로 self-hosted가 되면서 실제로 runner 내부에 접근할 수 있게되었다. workflow 작업 실패시 해당 state로 접근하는 설정 및 내부 구조등을 추후 글로 다룰 예정이다.

Leave a Reply