T-CREATOR

GitHub Actions ランナーのオートスケール運用:Kubernetes/actions-runner-controller 実践

GitHub Actions ランナーのオートスケール運用:Kubernetes/actions-runner-controller 実践

GitHub Actions のワークフローを実行する際、GitHub が提供するホストランナーだけでは性能やコストの面で課題に直面することがあります。特に大規模な開発チームでは、セルフホストランナーを Kubernetes 上で運用し、必要に応じて自動でスケールさせる仕組みが求められるでしょう。

本記事では、Kubernetes 上で GitHub Actions ランナーをオートスケール運用するための実践的な方法を、actions-runner-controller(ARC)を使って詳しく解説していきます。実際の設定例やトラブルシューティングまで含めて、すぐに実践できる内容をお届けしますね。

背景

GitHub Actions とセルフホストランナーの関係性

GitHub Actions は、CI/CD パイプラインを自動化するための強力なプラットフォームです。ワークフローを実行するためには「ランナー」と呼ばれる実行環境が必要になります。

GitHub が提供する標準のホストランナーは、Linux、Windows、macOS など複数の環境が用意されており、すぐに使い始められるのが魅力です。しかし、実際の開発現場では以下のようなニーズが生まれてきます。

セルフホストランナーを導入することで、自社のインフラ上でワークフローを実行でき、より柔軟な環境設定やコスト最適化が可能になるのです。

Kubernetes による運用の利点

Kubernetes は、コンテナオーケストレーションのデファクトスタンダードとして広く採用されています。GitHub Actions のセルフホストランナーを Kubernetes 上で運用することで、以下のメリットが得られるでしょう。

#項目説明
1リソース効率化ノードプールを共有し、他のワークロードと統合管理できる
2自動復旧Pod の異常時に自動で再起動し、可用性を向上させる
3スケーラビリティHPA や VPA による柔軟なスケーリングが可能
4宣言的管理YAML マニフェストで設定を管理し、GitOps と連携できる
5マルチテナントNamespace による論理的な分離で複数チームに対応

図の意図:GitHub Actions ワークフローがどのように Kubernetes クラスタ上のランナーで実行されるかを示します。

mermaidflowchart TB
    dev["開発者"] -->|push/PR| gh["GitHub<br/>リポジトリ"]
    gh -->|webhook| ghapi["GitHub Actions<br/>API"]
    ghapi -->|ジョブ割り当て| runner1["Runner Pod 1"]
    ghapi -->|ジョブ割り当て| runner2["Runner Pod 2"]
    ghapi -->|ジョブ割り当て| runner3["Runner Pod 3"]

    subgraph k8s["Kubernetes クラスタ"]
        runner1
        runner2
        runner3
    end

    runner1 -->|結果報告| ghapi
    runner2 -->|結果報告| ghapi
    runner3 -->|結果報告| ghapi
    ghapi -->|ステータス更新| gh
    gh -->|通知| dev

この図が示すように、開発者がコードをプッシュすると、GitHub Actions API がジョブを Kubernetes クラスタ上のランナー Pod に割り当て、実行結果を GitHub に返す流れとなります。

actions-runner-controller の登場

actions-runner-controller(ARC)は、Kubernetes 上で GitHub Actions のセルフホストランナーを管理するための Kubernetes Operator です。GitHub 社の公式サポートを受けており、エンタープライズ環境でも安心して利用できますね。

ARC は以下の機能を提供しています。

  • 自動登録:ランナーを GitHub リポジトリ/Organization に自動登録
  • オートスケール:ワークフローのキュー状況に応じて Pod 数を調整
  • ライフサイクル管理:ジョブ実行後のクリーンアップと再利用
  • マルチテナント対応:複数のリポジトリや Organization を一元管理

課題

ホストランナーの制限事項

GitHub が提供するホストランナーには、いくつかの制約が存在します。実際の開発現場では、これらの制限に直面することが少なくありません。

実行時間の制限

パブリックリポジトリでは 1 ジョブあたり最大 6 時間、プライベートリポジトリでは月間の実行時間に上限があります。大規模なビルドやテストを実行する場合、この制限がボトルネックになることがあるでしょう。

カスタマイズの難しさ

特定のツールやライブラリがプリインストールされていない場合、毎回のワークフロー実行時にインストール作業が必要になります。これは実行時間の増加とコストの増大につながりますね。

セキュリティとコンプライアンス

プライベートな Docker レジストリや内部 API へのアクセスが必要な場合、ホストランナーからは接続できないケースがあります。企業のセキュリティポリシーによっては、外部環境でのコード実行が許可されないこともあるでしょう。

セルフホストランナーの運用課題

セルフホストランナーを導入すれば上記の制限は解消できますが、今度は運用面での新たな課題が生まれます。

図の意図:セルフホストランナーを手動運用する際の課題を示します。

mermaidflowchart LR
    job["ワークフロー<br/>ジョブ"] -->|待機| queue["ジョブキュー"]
    queue -->|実行要求| check{ランナー<br/>空きあり?}
    check -->|Yes| exec["実行"]
    check -->|No| wait["待機状態"]
    wait -->|タイムアウト| fail["失敗"]

    style wait fill:#ffcccc
    style fail fill:#ff6666

スケーリングの難しさ

固定数のランナーを用意すると、ピーク時にはリソース不足、閑散時には無駄なコストが発生します。手動でのスケーリングは運用負荷が高く、現実的ではありません。

メンテナンスの負担

ランナーのバージョンアップ、セキュリティパッチの適用、環境のクリーンアップなど、継続的なメンテナンス作業が必要です。複数のランナーを個別に管理するのは非効率的ですね。

リソース管理の複雑さ

CPU、メモリ、ディスク容量などのリソース配分を適切に行わないと、ジョブの失敗やノード全体のパフォーマンス低下を招きます。特に複数のワークフローが並行実行される環境では、リソース競合が発生しやすくなるでしょう。

以下の表に、主な運用課題をまとめました。

#課題カテゴリ具体的な問題影響
1スケーラビリティ手動でのランナー数調整が必要開発速度の低下、コスト増
2可用性ランナー障害時の自動復旧なしワークフロー失敗率の上昇
3セキュリティ使用済みランナーのクリーンアップ漏れ情報漏洩リスク
4運用効率バージョン管理やパッチ適用の手間運用コストの増大
5可視性ランナーの状態監視が困難トラブルシューティングの遅延

解決策

actions-runner-controller による統合管理

これらの課題を解決するのが、actions-runner-controller(ARC)です。ARC は Kubernetes の宣言的な管理の仕組みを活用し、GitHub Actions ランナーのライフサイクル全体を自動化してくれます。

Custom Resource Definition(CRD)による管理

ARC は Kubernetes の CRD を利用して、ランナーの設定を YAML マニフェストで定義できるようにします。これにより、インフラのコード化(Infrastructure as Code)が実現し、バージョン管理や変更履歴の追跡が容易になりますね。

Webhook ベースのオートスケール

GitHub からの Webhook を受信して、リアルタイムにワークフローのキュー状況を把握します。待機中のジョブ数に応じて、自動的にランナー Pod を増減させることができるのです。

図の意図:ARC がどのように GitHub Actions と連携してオートスケールを実現するかを示します。

mermaidflowchart TB
    gh["GitHub Actions"] -->|webhook| arc["ARC<br/>Controller"]
    arc -->|監視| hpa["HorizontalRunner<br/>Autoscaler"]
    hpa -->|スケール指示| deployment["RunnerDeployment"]
    deployment -->|Pod作成/削除| pods["Runner Pods"]

    subgraph k8s["Kubernetes クラスタ"]
        arc
        hpa
        deployment
        pods
    end

    pods -->|ジョブ取得| gh
    pods -->|結果送信| gh

    style arc fill:#e1f5ff
    style hpa fill:#fff4e1
    style deployment fill:#e8f5e8

主要コンポーネントの役割

#コンポーネント役割
1Controller ManagerCRD リソースの監視と調整ループの実行
2RunnerDeploymentランナー Pod のテンプレートと複製数の管理
3RunnerSetステートフルなランナーの管理(永続ボリューム対応)
4HorizontalRunnerAutoscalerメトリクスベースでの自動スケーリング
5Webhook ServerGitHub からの Webhook 受信とスケール判定

主要な設定リソース

ARC を使用する際に理解しておくべき主要なリソースタイプを紹介します。

RunnerDeployment リソース

最も基本的なリソースで、ステートレスなランナー群を管理します。Kubernetes の Deployment と同様の概念で、指定した複製数の Runner Pod を維持してくれますね。

HorizontalRunnerAutoscaler リソース

RunnerDeployment と組み合わせて使用し、ワークフローのキュー状況に基づいて自動的にランナー数を調整します。最小・最大レプリカ数を指定でき、急激なスケールアウトやコスト超過を防げるでしょう。

認証方式の選択

ARC は複数の認証方式をサポートしています。

  • Personal Access Token(PAT):個人アカウントベースの認証
  • GitHub App:Organization レベルでの管理に適した方式
  • GitHub Enterprise Server:オンプレミス環境向け

本番環境では、セキュリティと管理性の観点から GitHub App による認証が推奨されます。

スケーリング戦略

ARC は複数のスケーリング戦略を提供しており、ワークフローの特性に応じて選択できます。

パーセンテージベーススケーリング

現在の実行中ジョブ数に対する割合で、追加するランナー数を決定します。安定したトラフィックパターンを持つ環境に適していますね。

Webhook ドリブンスケーリング

GitHub からの workflow_job Webhook をリアルタイムに受信し、即座にスケールアウトします。レスポンスタイムを最小化したい場合に有効な戦略です。

スケジュールベーススケーリング

時間帯や曜日に応じて、事前にランナー数を調整します。定期的なバッチ処理やピーク時間が予測可能な場合に便利でしょう。

具体例

環境構築の前提条件

実際に ARC を導入する手順を見ていきましょう。以下の環境が整っていることを前提とします。

#項目要件
1Kubernetes クラスタv1.24 以上(推奨:v1.28 以上)
2kubectlクラスタへのアクセス権限を持つ設定済み CLI
3Helmv3.8 以上
4GitHub アカウントOrganization の管理者権限
5cert-managerWebhook 用の証明書管理(オプション)

GitHub App の作成

まず、ARC が GitHub API にアクセスするための GitHub App を作成します。この方法が最もセキュアで、Organization レベルでの管理に適しています。

GitHub App の登録手順

  1. GitHub Organization の Settings を開く
  2. Developer settings → GitHub Apps → New GitHub App をクリック
  3. 必要な情報を入力

以下の permissions が必要になります。

yaml# Repository permissions
actions: read
administration: read/write
checks: read
metadata: read

# Organization permissions
self_hosted_runners: read/write

Webhook の設定

GitHub App には Webhook URL を設定し、workflow_job イベントを購読するようにします。この設定により、ジョブの状態変化をリアルタイムに検知できるようになりますね。

textWebhook URL: https://your-arc-webhook.example.com/webhook
Webhook secret: <安全なランダム文字列>
Subscribe to events:
  - Workflow job (workflow_job)

App の秘密鍵とインストール

GitHub App を作成したら、秘密鍵(Private Key)を生成してダウンロードします。この鍵は後ほど Kubernetes Secret として登録することになります。

作成した App を Organization にインストールし、アクセスを許可するリポジトリを選択しましょう。

Helm による ARC のインストール

Helm チャートを使用して、ARC を Kubernetes クラスタにデプロイします。まずは Helm リポジトリの追加から始めますね。

bash# ARC の Helm リポジトリを追加
helm repo add actions-runner-controller \
  https://actions-runner-controller.github.io/actions-runner-controller

# リポジトリ情報を更新
helm repo update

Namespace の作成

ARC 専用の Namespace を作成し、リソースを論理的に分離します。

bash# actions-runner-system という Namespace を作成
kubectl create namespace actions-runner-system

GitHub App の認証情報を Secret に登録

ダウンロードした秘密鍵を Kubernetes Secret として登録します。

bash# GitHub App の秘密鍵を Secret に登録
kubectl create secret generic controller-manager \
  -n actions-runner-system \
  --from-literal=github_app_id=123456 \
  --from-literal=github_app_installation_id=78901234 \
  --from-file=github_app_private_key=path/to/private-key.pem

ここで、github_app_id は GitHub App の ID、github_app_installation_id は Organization にインストールした際に割り振られた ID です。これらは GitHub の App 設定ページから確認できますね。

ARC Controller のインストール

values.yaml ファイルを作成し、必要な設定をカスタマイズします。

yaml# values.yaml
authSecret:
  enabled: true
  create: false
  name: 'controller-manager'

# GitHub Webhook の設定
githubWebhookServer:
  enabled: true
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http

# リソース制限の設定
resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 200m
    memory: 256Mi

次に、この values.yaml を使用して Helm チャートをインストールします。

bash# ARC Controller をインストール
helm install actions-runner-controller \
  actions-runner-controller/actions-runner-controller \
  -n actions-runner-system \
  -f values.yaml \
  --wait

インストールが完了したら、Pod が正常に起動しているか確認しましょう。

bash# ARC Controller の状態確認
kubectl get pods -n actions-runner-system

# ログを確認してエラーがないかチェック
kubectl logs -n actions-runner-system \
  -l app.kubernetes.io/name=actions-runner-controller

RunnerDeployment の設定

ARC がインストールできたら、実際にランナーをデプロイする設定を作成します。まずはシンプルな RunnerDeployment から始めますね。

yaml# runner-deployment.yaml
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: example-runner
  namespace: actions-runner-system
spec:
  # レプリカ数(HPA を使う場合は指定不要)
  replicas: 1

  template:
    spec:
      # Organization レベルでランナーを登録
      organization: your-organization

      # ランナーグループの指定(オプション)
      runnerGroup: default

この設定では、your-organization という Organization に対してランナーを登録します。リポジトリ単位で登録する場合は、repository: owner​/​repo-name という形式で指定できますね。

ランナーのラベル設定

ワークフローから特定のランナーを指定できるよう、ラベルを設定します。

yaml# runner-deployment.yaml(ラベル設定を追加)
spec:
  template:
    spec:
      organization: your-organization

      # カスタムラベルの設定
      labels:
        - self-hosted
        - linux
        - x64
        - kubernetes

ワークフロー側では、runs-on フィールドでこれらのラベルを指定できます。

yaml# .github/workflows/example.yml
jobs:
  build:
    runs-on: [self-hosted, kubernetes]
    steps:
      - uses: actions/checkout@v4
      - run: echo "Running on Kubernetes!"

Docker イメージのカスタマイズ

デフォルトのランナーイメージには基本的なツールしか含まれていません。プロジェクトに必要なツールをプリインストールしたカスタムイメージを使用することで、ワークフローの実行時間を短縮できるでしょう。

yamlspec:
  template:
    spec:
      organization: your-organization
      labels:
        - self-hosted
        - kubernetes
        - nodejs

      # カスタム Docker イメージの指定
      image: ghcr.io/your-org/custom-runner:latest
      imagePullPolicy: Always

      # プライベートレジストリ用の認証
      imagePullSecrets:
        - name: ghcr-secret

カスタムイメージの Dockerfile 例を示します。

dockerfile# Dockerfile
FROM ghcr.io/actions/actions-runner:latest

# 必要なツールをインストール
USER root

RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    git \
    && rm -rf /var/lib/apt/lists/*

この Dockerfile では、actions-runner の公式イメージをベースに、追加のビルドツールをインストールしています。

Node.js などの特定のランタイムを追加する場合は、以下のように記述します。

dockerfile# Node.js のインストール
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get install -y nodejs \
    && npm install -g yarn

USER runner

オートスケール設定

RunnerDeployment だけでは固定数のランナーしか起動しません。HorizontalRunnerAutoscaler リソースを追加して、動的なスケーリングを実現しましょう。

yaml# runner-hpa.yaml
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
  name: example-runner-autoscaler
  namespace: actions-runner-system
spec:
  # スケール対象の RunnerDeployment
  scaleTargetRef:
    kind: RunnerDeployment
    name: example-runner

  # 最小・最大レプリカ数
  minReplicas: 1
  maxReplicas: 10

この設定により、ランナー数は 1 から 10 の範囲で自動調整されます。最小レプリカ数を 1 以上にすることで、ジョブの初回実行時の待機時間を短縮できますね。

Webhook ベースのスケーリング設定

より高度なスケーリングには、GitHub からの Webhook を活用します。

yamlspec:
  scaleTargetRef:
    kind: RunnerDeployment
    name: example-runner

  minReplicas: 1
  maxReplicas: 10

  # Webhook ベースのスケーリング
  scaleUpTriggers:
    - githubEvent:
        workflowJob: {}
      amount: 1
      duration: '5m'

  scaleDownDelaySecondsAfterScaleOut: 300

この設定では、workflow_job イベントを受信するたびに 1 つのランナーを追加し、5 分間その状態を維持します。スケールアウト後、300 秒(5 分)経過してから段階的にスケールダウンを開始する仕組みですね。

メトリクスベースのスケーリング

ジョブキューの長さに応じてスケールする設定も可能です。

yamlspec:
  scaleTargetRef:
    kind: RunnerDeployment
    name: example-runner

  minReplicas: 2
  maxReplicas: 20

  # メトリクスベースのスケーリング
  metrics:
    - type: TotalNumberOfQueuedAndInProgressWorkflowRuns
      repositoryNames:
        - your-organization/repo1
        - your-organization/repo2

この設定では、指定したリポジトリのキュー中および実行中のワークフロー数に基づいてスケールします。待機中のジョブが増えると、自動的にランナーが追加されるでしょう。

リソース制限の設定

各ランナー Pod に適切なリソース制限を設定することで、Kubernetes クラスタ全体の安定性を保てます。

yaml# runner-deployment.yaml(リソース設定を追加)
spec:
  template:
    spec:
      organization: your-organization

      # Pod レベルのリソース設定
      resources:
        limits:
          cpu: '4'
          memory: '8Gi'
          ephemeral-storage: '20Gi'
        requests:
          cpu: '1'
          memory: '2Gi'
          ephemeral-storage: '10Gi'

ここでは、各ランナーが最大 4 コア、8GB メモリ、20GB のエフェメラルストレージを使用でき、最低でも 1 コア、2GB メモリが保証されます。

ボリュームマウントの設定

Docker-in-Docker(DinD)を使用してコンテナビルドを行う場合、適切なボリューム設定が必要です。

yamlspec:
  template:
    spec:
      organization: your-organization

      # DinD を有効化
      dockerEnabled: true
      dockerdWithinRunnerContainer: true

      # ボリュームマウント
      volumeMounts:
        - name: work
          mountPath: /home/runner/_work

      volumes:
        - name: work
          emptyDir: {}

この設定により、ワークディレクトリが emptyDir ボリュームとしてマウントされ、ジョブ実行時のディスク I/O パフォーマンスが向上しますね。

実際のデプロイと動作確認

ここまで作成した YAML マニフェストを適用して、実際にランナーをデプロイしましょう。

bash# RunnerDeployment を適用
kubectl apply -f runner-deployment.yaml

# HorizontalRunnerAutoscaler を適用
kubectl apply -f runner-hpa.yaml

デプロイ後、ランナーの状態を確認します。

bash# RunnerDeployment の状態確認
kubectl get runnerdeployments -n actions-runner-system

# Runner Pod の状態確認
kubectl get runners -n actions-runner-system

# Pod の詳細を確認
kubectl get pods -n actions-runner-system \
  -l app.kubernetes.io/name=example-runner

図の意図:リソース適用からランナーが GitHub に登録されるまでの流れを示します。

mermaidsequenceDiagram
    participant User as 管理者
    participant K8s as Kubernetes API
    participant ARC as ARC Controller
    participant Pod as Runner Pod
    participant GH as GitHub API

    User->>K8s: kubectl apply<br/>RunnerDeployment
    K8s->>ARC: リソース作成イベント
    ARC->>K8s: Pod 作成リクエスト
    K8s->>Pod: Pod 起動
    Pod->>GH: ランナー登録API
    GH-->>Pod: 登録トークン
    Pod->>GH: ランナー認証
    GH-->>User: ランナーがオンライン

この図から、管理者が YAML を適用してから、実際に GitHub にランナーが登録されるまでの一連の流れが理解できますね。

GitHub UI での確認

GitHub の Organization 設定ページで、ランナーが正常に登録されているか確認できます。

  1. Organization の Settings を開く
  2. Actions → Runners メニューに移動
  3. Self-hosted runners セクションにランナーが表示される

ランナーのステータスが「Idle」になっていれば、ジョブを受け付ける準備ができています。

テストワークフローの実行

簡単なワークフローを実行して、セルフホストランナーが正常に動作するか確認しましょう。

yaml# .github/workflows/test-runner.yml
name: Test Self-Hosted Runner

on:
  workflow_dispatch:

jobs:
  test:
    runs-on: [self-hosted, kubernetes]
    steps:
      - name: Echo hostname
        run: echo "Running on $(hostname)"

      - name: Check resources
        run: |
          echo "CPU cores: $(nproc)"
          echo "Memory: $(free -h | grep Mem | awk '{print $2}')"
          echo "Disk space: $(df -h / | tail -1 | awk '{print $4}')"

このワークフローを手動実行(workflow_dispatch)し、ログに Pod 名やリソース情報が表示されれば成功です。

トラブルシューティング

実際の運用では、さまざまな問題に遭遇することがあります。代表的なエラーとその解決方法を紹介しますね。

エラー 1: ランナーが GitHub に登録されない

textError: POST https://api.github.com/orgs/your-org/actions/runners/registration-token: 401 Unauthorized

このエラーは、GitHub App の認証情報が正しくないか、権限が不足していることを示しています。

解決手順

  1. GitHub App の秘密鍵が正しく Secret に登録されているか確認
  2. GitHub App ID と Installation ID が正しいか検証
  3. GitHub App に必要な permissions が付与されているか確認
bash# Secret の内容を確認(値は表示されない)
kubectl describe secret controller-manager -n actions-runner-system

# ARC Controller のログでエラー詳細を確認
kubectl logs -n actions-runner-system \
  -l app.kubernetes.io/name=actions-runner-controller \
  --tail=100

エラー 2: Pod が ImagePullBackOff 状態

textError: Failed to pull image "ghcr.io/your-org/custom-runner:latest":
rpc error: code = Unknown desc = failed to pull and unpack image:
failed to resolve reference: unauthorized

プライベートコンテナレジストリへの認証に失敗しています。

解決手順

まず、コンテナレジストリへの認証情報を含む Secret を作成します。

bash# GitHub Container Registry(GHCR)用の Secret 作成
kubectl create secret docker-registry ghcr-secret \
  -n actions-runner-system \
  --docker-server=ghcr.io \
  --docker-username=your-username \
  --docker-password=your-token \
  --docker-email=your-email@example.com

次に、RunnerDeployment で imagePullSecrets を指定します。

yamlspec:
  template:
    spec:
      imagePullSecrets:
        - name: ghcr-secret

エラー 3: スケールアウトが機能しない

Webhook を設定したのに、ジョブが実行待ちになっているにもかかわらずランナーが増えないケースがあります。

解決手順

Webhook Server が正常に動作しているか確認します。

bash# Webhook Server の Pod を確認
kubectl get pods -n actions-runner-system \
  -l app.kubernetes.io/component=webhook-server

# Webhook Server のログを確認
kubectl logs -n actions-runner-system \
  -l app.kubernetes.io/component=webhook-server \
  --tail=50

GitHub 側の Webhook 設定も確認しましょう。

  1. GitHub App の Settings を開く
  2. Webhook セクションで Recent Deliveries を確認
  3. Response が 200 OK でない場合は、URL や Secret が正しいか検証

エラー 4: ジョブ実行後にランナーがクリーンアップされない

使用済みのランナー Pod が残り続け、リソースを消費し続けることがあります。

解決手順

RunnerDeployment にクリーンアップポリシーを設定します。

yamlspec:
  template:
    spec:
      # ジョブ実行後に Pod を削除
      ephemeral: true

      # タイムアウト設定
      workVolumeClaimTemplate:
        storageClassName: standard
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi

ephemeral: true を設定することで、ジョブ完了後に自動的に Pod が削除され、次のジョブには新しい Pod が起動されますね。

監視とメトリクス収集

ARC の運用状態を可視化するために、Prometheus と Grafana を使った監視を設定しましょう。

Prometheus ServiceMonitor の作成

ARC は Prometheus メトリクスをエクスポートします。ServiceMonitor リソースを作成して、メトリクスを収集する設定を行います。

yaml# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: actions-runner-controller
  namespace: actions-runner-system
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: actions-runner-controller
  endpoints:
    - port: metrics
      interval: 30s

この設定により、30 秒ごとに ARC のメトリクスが収集されます。

主要なメトリクス

ARC が提供する重要なメトリクスをまとめました。

#メトリクス名説明
1runner_pods_total現在稼働中のランナー Pod 数
2runner_jobs_queuedGitHub のジョブキューに待機中のジョブ数
3runner_jobs_running実行中のジョブ数
4runner_reconciliation_duration_secondsコントローラーの調整ループ実行時間
5runner_deployment_spec_replicasRunnerDeployment で指定されたレプリカ数

これらのメトリクスを Grafana でダッシュボード化すると、スケーリングの状況やリソース使用率が一目で把握できるようになりますね。

アラート設定例

Prometheus のアラートルールを設定して、異常を早期検知できるようにします。

yaml# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: arc-alerts
  namespace: actions-runner-system
spec:
  groups:
    - name: actions-runner-controller
      interval: 30s
      rules:
        - alert: RunnerJobQueueTooLong
          expr: runner_jobs_queued > 10
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: 'ジョブキューが長時間滞留'
            description: '{{ $value }}個のジョブが5分以上待機しています'

このアラートは、10 個以上のジョブが 5 分間キューに滞留した場合に発火し、スケールアップが追いついていない可能性を通知してくれます。

まとめ

本記事では、Kubernetes 上で GitHub Actions のセルフホストランナーをオートスケール運用する方法を、actions-runner-controller(ARC)を使って実践的に解説してきました。

GitHub が提供するホストランナーの制限を克服し、自社のインフラ上で柔軟かつコスト効率の良い CI/CD 環境を構築できることがお分かりいただけたのではないでしょうか。

ARC を導入することで得られる主なメリットをまとめると、以下のようになります。

運用面での改善

  • ワークフローのキュー状況に応じた自動スケーリングによる待機時間の削減
  • Kubernetes の宣言的な管理による設定の標準化とバージョン管理
  • Pod ベースのクリーンな実行環境による セキュリティリスクの低減

コスト面での最適化

  • 必要な時だけランナーを起動することでクラウドリソースの効率的活用
  • カスタムイメージの使用によるワークフロー実行時間の短縮
  • 既存の Kubernetes クラスタを活用した追加インフラ投資の削減

開発生産性の向上

  • プライベートリソースへのアクセスによる開発フローの改善
  • チーム固有のツールをプリインストールした環境の提供
  • ビルド時間の短縮によるフィードバックループの高速化

実際の導入にあたっては、まず小規模な RunnerDeployment から始めて、段階的にオートスケール機能を追加していくアプローチがおすすめです。運用を通じて得られたメトリクスを分析し、スケーリング戦略を最適化していくことで、より効率的な CI/CD 環境が実現できるでしょう。

GitHub Actions と Kubernetes を組み合わせることで、モダンな開発ワークフローを支える強固な基盤を構築できます。ぜひ本記事の内容を参考に、皆さんの環境でも実践してみてくださいね。

関連リンク