Actions Runner Controller 살펴보기
Actions Runner Controller 살펴보기
자체 러너를 호스팅하고 GitHub Actions 워크플로에서 작업을 실행하는 환경을 커스터마이즈하는 방법을 함께 알아볼게요.
본문
Actions Runner Controller 소개
Actions Runner Controller(ARC)는 GitHub Actions용 자체 호스팅 러너를 오케스트레이션하고 확장하는 Kubernetes 오퍼레이터(operator)예요. 자세한 내용은 Kubernetes 문서의 Operator 패턴을 참고하세요.
ARC를 사용하면 리포지토리, 조직, 엔터프라이즈에서 실행되는 워크플로 수에 따라 자동으로 확장되는 러너 스케일 세트(runner scale sets)를 만들 수 있어요. 제어되는 러너는 임시(ephemeral)이고 컨테이너 기반일 수 있으므로 새 러너 인스턴스를 빠르고 깨끗하게 늘리거나 줄일 수 있어요. 자동 확장에 대한 자세한 내용은 자체 호스팅 러너 참조를 참고하세요.
다음 다이어그램은 ARC의 자동 확장 러너 스케일 세트 모드의 아키텍처를 보여줘요.
[!NOTE] 아래 다이어그램을 더 크게 보려면 Actions Runner Controller 리포지토리의 자동 확장 러너 스케일 세트 모드 문서를 참고하세요.

- Actions Runner Controller가 제공된 Helm 차트를 사용해 설치되고, 컨트롤러 매니저 포드가 지정된 네임스페이스에 배포돼요. 새 AutoScalingRunnerSet 리소스가 제공된 Helm 차트 또는 커스터마이즈된 매니페스트 파일을 통해 배포돼요. AutoScalingRunnerSet 컨트롤러는 GitHub의 API를 호출해서 러너 스케일 세트가 속하게 될 러너 그룹 ID를 가져와요.
- AutoScalingRunnerSet 컨트롤러는 Runner ScaleSet Listener 리소스를 만들기 전에 API를 한 번 더 호출해서 GitHub Actions 서비스에서 러너 스케일 세트를 가져오거나 만들어요.
- AutoScalingListener 컨트롤러가 Runner ScaleSet Listener 포드를 배포해요. 이 포드에서 리스너 애플리케이션이 GitHub Actions 서비스에 연결해 인증하고 HTTPS 롱 폴(long poll) 연결을 설정해요. 리스너는 GitHub Actions 서비스에서
Job Available메시지를 받을 때까지 대기 상태로 있어요. - 리포지토리에서 워크플로 실행이 트리거되면 GitHub Actions 서비스는
runs-on키가 러너 스케일 세트의 이름 또는 러너 스케일 세트·자체 호스팅 러너의 라벨과 일치하는 러너나 러너 스케일 세트에 개별 작업 실행을 전달해요. - Runner ScaleSet Listener가
Job Available메시지를 받으면 원하는 수(count)까지 확장할 수 있는지 확인해요. 가능하면 Runner ScaleSet Listener가 메시지를 확인(acknowledge)해요. - Runner ScaleSet Listener는 서비스 계정(Service Account)과 그 계정에 바인딩된 Role을 사용해 Kubernetes API를 통해 HTTPS 호출로 Ephemeral RunnerSet 리소스에 원하는 복제본 수를 패치해요.
- Ephemeral RunnerSet이 새 러너를 만들려고 시도하고, EphemeralRunner 컨트롤러가 이 러너들을 등록하기 위해 JIT(Just-in-Time) 구성 토큰을 요청해요. 컨트롤러는 러너 포드를 만들려고 시도해요. 포드 상태가
failed이면 컨트롤러는 최대 5번까지 재시도해요. 24시간 후에도 어떤 러너도 작업을 수락하지 않으면 GitHub Actions 서비스가 작업을 할당 해제해요. - 러너 포드가 생성되면 포드 안의 러너 애플리케이션이 JIT 구성 토큰을 사용해 GitHub Actions 서비스에 스스로를 등록해요. 그런 다음 실행해야 할 작업 세부 정보를 받기 위해 HTTPS 롱 폴 연결을 하나 더 설정해요.
- GitHub Actions 서비스가 러너 등록을 확인하고 작업 실행 세부 정보를 전달해요.
- 작업 실행이 진행되는 동안 러너는 로그와 작업 실행 상태를 계속 GitHub Actions 서비스에 전달해요.
- 러너가 작업을 성공적으로 완료하면 EphemeralRunner 컨트롤러가 GitHub Actions 서비스에 러너를 삭제할 수 있는지 확인해요. 삭제할 수 있다면 Ephemeral RunnerSet이 러너를 삭제해요.
Actions Runner Controller 구성 요소
ARC는 여러 리소스로 구성되며, 그중 일부는 ARC를 위해 특별히 만들어져요. ARC 배포는 이러한 리소스를 Kubernetes 클러스터에 적용해요. 적용되면 자체 호스팅 러너 컨테이너를 포함하는 포드 집합이 생성돼요. ARC를 사용하면 GitHub은 이 러너 컨테이너를 자체 호스팅 러너로 취급하고 필요에 따라 작업을 할당할 수 있어요.
ARC가 배포하는 각 리소스에는 다음과 같이 구성된 이름이 주어져요:
- 설치 이름(installation name): Helm 차트를 설치할 때 지정하는 설치 이름이에요.
- 리소스 식별 접미사(resource identification suffix): 리소스 유형을 식별하는 문자열이에요. 이 값은 구성할 수 없어요.
[!NOTE] Kubernetes 버전마다 리소스 이름의 길이 제한이 달라요. 리소스 이름의 길이 제한은 설치 이름 길이와 리소스 식별 접미사 길이를 더해 계산돼요. 리소스 이름이 예약된 길이보다 길면 오류가 발생해요.
gha-runner-scale-set-controller가 배포하는 리소스
| 템플릿 | 리소스 종류 | 이름 | 예약 길이 | 설명 | 참고 |
|---|---|---|---|---|---|
deployment.yaml |
Deployment | INSTALLATION_NAME-gha-rs-controller | 18 | controller-manager를 실행하는 리소스 | 이 리소스가 만드는 포드에는 ReplicaSet 접미사와 Pod 접미사가 붙어요. |
serviceaccount.yaml |
ServiceAccount | INSTALLATION_NAME-gha-rs-controller | 18 | values.yaml에서 serviceAccount.create가 true로 설정된 경우 생성됨 |
이름은 values.yaml에서 커스터마이즈할 수 있어요 |
manager_cluster_role.yaml |
ClusterRole | INSTALLATION_NAME-gha-rs-controller | 18 | 컨트롤러 매니저용 ClusterRole | flags.watchSingleNamespace 값이 비어 있으면 생성돼요. |
manager_cluster_role_binding.yaml |
ClusterRoleBinding | INSTALLATION_NAME-gha-rs-controller | 18 | 컨트롤러 매니저용 ClusterRoleBinding | flags.watchSingleNamespace 값이 비어 있으면 생성돼요. |
manager_single_namespace_controller_role.yaml |
Role | INSTALLATION_NAME-gha-rs-controller-single-namespace | 35 | 컨트롤러 매니저용 Role | flags.watchSingleNamespace 값이 설정된 경우 생성돼요. |
manager_single_namespace_controller_role_binding.yaml |
RoleBinding | INSTALLATION_NAME-gha-rs-controller-single-namespace | 35 | 컨트롤러 매니저용 RoleBinding | flags.watchSingleNamespace 값이 설정된 경우 생성돼요. |
manager_single_namespace_watch_role.yaml |
Role | INSTALLATION_NAME-gha-rs-controller-single-namespace-watch | 41 | 구성된 네임스페이스용 컨트롤러 매니저 Role | flags.watchSingleNamespace 값이 설정된 경우 생성돼요. |
manager_single_namespace_watch_role_binding.yaml |
RoleBinding | INSTALLATION_NAME-gha-rs-controller-single-namespace-watch | 41 | 구성된 네임스페이스용 컨트롤러 매니저 RoleBinding | flags.watchSingleNamespace 값이 설정된 경우 생성돼요. |
manager_listener_role.yaml |
Role | INSTALLATION_NAME-gha-rs-controller-listener | 26 | 리스너용 Role | 항상 생성돼요. |
manager_listener_role_binding.yaml |
RoleBinding | INSTALLATION_NAME-gha-rs-controller-listener | 26 | 리스너용 RoleBinding | 항상 생성되며, serviceaccount.yaml으로 만들어지거나 values.yaml로 구성된 서비스 계정에 리스너 역할을 바인딩해요. |
gha-runner-scale-set이 배포하는 리소스
| 템플릿 | 리소스 종류 | 이름 | 예약 길이 | 설명 | 참고 |
|---|---|---|---|---|---|
autoscalingrunnerset.yaml |
AutoscalingRunnerSet | INSTALLATION_NAME | 0 | 스케일 세트와 함께 동작하는 최상위 리소스 | 이름은 최대 45자로 제한돼요. |
no_permission_service_account.yaml |
ServiceAccount | INSTALLATION_NAME-gha-rs-no-permission | 21 | 러너 컨테이너에 마운트되는 서비스 계정 | 컨테이너 모드가 "kubernetes"가 아니고 template.spec.serviceAccountName이 지정되지 않은 경우 생성돼요. |
githubsecret.yaml |
Secret | INSTALLATION_NAME-gha-rs-github-secret | 20 | GitHub API에 인증하는 데 필요한 값을 담은 Secret | githubConfigSecret이 객체인 경우 생성돼요. 문자열이 제공되면 이 secret은 생성되지 않아요. |
manager_role.yaml |
Role | INSTALLATION_NAME-gha-rs-manager | 15 | 자동 확장 러너 세트의 네임스페이스에서 리소스에 대해 reconcile하도록 매니저에게 부여되는 Role | 항상 생성돼요. |
manager_role_binding.yaml |
RoleBinding | INSTALLATION_NAME-gha-rs-manager | 15 | manager_role을 매니저 서비스 계정에 바인딩. | 항상 생성돼요. |
kube_mode_role.yaml |
Role | INSTALLATION_NAME-gha-rs-kube-mode | 17 | 훅(hook)에 필요한 권한을 제공하는 Role | 컨테이너 모드가 "kubernetes"로 설정되고 template.spec.serviceAccount가 제공되지 않으면 생성돼요. |
kube_mode_serviceaccount.yaml |
ServiceAccount | INSTALLATION_NAME-gha-rs-kube-mode | 17 | 러너 포드에 바인딩된 서비스 계정. | 컨테이너 모드가 "kubernetes"로 설정되고 template.spec.serviceAccount가 제공되지 않으면 생성돼요. |
사용자 지정 리소스(Custom resources) 소개
ARC는 여러 사용자 지정 리소스 정의(CRD, custom resource definitions)로 구성돼요. 사용자 지정 리소스에 대한 자세한 내용은 Kubernetes 문서의 사용자 지정 리소스를 참고하세요. ARC에 사용되는 사용자 지정 리소스 정의 목록은 다음 API 스키마 정의에서 찾을 수 있어요.
사용자 지정 리소스는 Kubernetes API의 확장이므로 기본 Kubernetes 설치에는 없어요. ARC를 사용하려면 이 사용자 지정 리소스들을 설치해야 해요. 사용자 지정 리소스 설치에 대한 자세한 내용은 Actions Runner Controller 시작하기를 참고하세요.
사용자 지정 리소스가 설치되면 ARC를 Kubernetes 클러스터에 배포할 수 있어요. ARC 배포에 대한 자세한 내용은 Actions Runner Controller로 러너 스케일 세트 배포하기를 참고하세요.
러너 컨테이너 이미지 소개
GitHub은 최소 러너 컨테이너 이미지(minimal runner container image)를 유지 관리해요. 러너 바이너리 릴리스마다 새 이미지가 게시돼요. 가장 최근 이미지에는 러너 바이너리 버전과 latest가 태그로 붙어요.
이 이미지에는 컨테이너 런타임과 러너 바이너리에 꼭 필요한 최소한의 패키지만 들어 있어요. 추가 소프트웨어를 설치하려면 자체 러너 이미지를 만들 수 있어요. ARC의 러너 이미지를 베이스로 사용하거나 해당 설정 액션을 사용할 수 있어요. 예를 들어 Java용 actions/setup-java, Node용 actions/setup-node가 있어요.
ARC 러너 이미지의 정의는 이 Dockerfile에서 찾을 수 있어요. 현재 기본 이미지를 보려면 러너 이미지 Dockerfile의 FROM 줄을 확인하고, 그 태그를 dotnet/dotnet-docker 리포지토리에서 찾아보세요.
예를 들어 러너 이미지 Dockerfile의 FROM 줄이 mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy AS build라면 기본 이미지를 https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/8.0/jammy/amd64/Dockerfile에서 찾을 수 있어요.
자체 러너 이미지 만들기
요구사항에 맞는 자체 러너 이미지를 만들 수 있어요. 러너 이미지는 다음 조건을 충족해야 해요.
-
자체 호스팅 러너 애플리케이션을 실행할 수 있는 기본 이미지를 사용하세요. 자체 호스팅 러너 관리하기를 참고하세요.
-
러너 바이너리(runner binary)는
/home/runner/아래에 두고/home/runner/run.sh로 시작해야 해요. -
Kubernetes 모드를 사용한다면 러너 컨테이너 훅(runner container hooks)을
/home/runner/k8s아래에 두어야 해요.
다음 예시 Dockerfile을 사용해 자체 러너 이미지 만들기를 시작할 수 있어요.
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0 as build
# Replace value with the latest runner release version
# source: https://github.com/actions/runner/releases
# ex: 2.303.0
ARG RUNNER_VERSION=""
ARG RUNNER_ARCH="x64"
# Replace value with the latest runner-container-hooks release version
# source: https://github.com/actions/runner-container-hooks/releases
# ex: 0.3.1
ARG RUNNER_CONTAINER_HOOKS_VERSION=""
ENV DEBIAN_FRONTEND=noninteractive
ENV RUNNER_MANUALLY_TRAP_SIG=1
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
RUN apt update -y && apt install curl unzip -y
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
&& groupadd docker --gid 123 \
&& usermod -aG sudo runner \
&& usermod -aG docker runner \
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \
&& echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers
WORKDIR /home/runner
RUN curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./runner.tar.gz \
&& rm runner.tar.gz
RUN curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
&& unzip ./runner-container-hooks.zip -d ./k8s \
&& rm runner-container-hooks.zip
USER runner
ARC 러너 이미지에 설치된 소프트웨어
ARC 러너 이미지에는 다음 소프트웨어가 함께 제공돼요:
자세한 내용은 Actions 리포지토리의 ARC 러너 이미지 Dockerfile을 참고하세요.
자산과 릴리스
ARC는 두 개의 Helm 차트와 하나의 컨테이너 이미지로 릴리스돼요. Helm 차트는 OCI(Open Container Initiative) 패키지로만 게시돼요. ARC는 GitHub Pages를 통한 tarball이나 Helm 리포지토리는 제공하지 않아요.
ARC의 최신 Helm 차트와 컨테이너 이미지 릴리스는 GitHub Packages에서 찾을 수 있어요:
gha-runner-scale-set-controllerHelm 차트gha-runner-scale-setHelm 차트gha-runner-scale-set-controller컨테이너 이미지
지원되는 러너 이미지는 별도의 컨테이너 이미지로 릴리스되며, GitHub Packages의 actions-runner에서 찾을 수 있어요.
법적 고지
일부 내용은 Apache-2.0 라이선스에 따라 https://github.com/actions/actions-runner-controller/에서 각색됐어요:
Copyright 2019 Moto Ishizawa
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
다음 단계
ARC가 처음이라면 Actions Runner Controller 시작하기를 참고해 기초를 직접 해보세요.
ARC로 워크플로를 실행할 준비가 되면 워크플로에서 Actions Runner Controller 러너 사용하기를 참고하세요.
러너 스케일 세트의 설치 이름을 사용하거나 values.yaml 파일에서 runnerScaleSetName 필드의 값을 runs-on 대상으로 정의할 수 있어요. 스케일 세트에 여러 라벨을 할당해 더 유연한 작업 라우팅을 활성화할 수도 있어요. 러너 스케일 세트의 라벨을 구성하려면 values.yaml 파일에서 runnerScaleSetLabels 값을 설정하세요. 워크플로에서 자체 호스팅 러너 사용하기를 참고하세요.
필요에 따라 러너를 정적으로 또는 동적으로 확장할 수 있어요. Actions Runner Controller로 러너 스케일 세트 배포하기를 참고하세요.