こんにちは、テクマトリックスの酒井です。

弊社では CI/CD 環境の構築を数多くご提案しています。少し前までは Jenkins を利用するご提案がほとんどでしたが、最近は GitHub Actions など他の CI/CD ツールを利用するご提案も増えてきました。 そのようなご提案の検証において、複数のワークフローを同時に実行できる自己ホストランナーとして GitHub Actions Runner Controller(以下、「ARC」)を構築してみました。 また運用中にトラブルが発生したことがあり、その対策としてメトリクスを計測・監視する仕組みも導入しています。

この記事では、 ARC の導入と利用状況を可視化する手順について詳しく説明します。

背景

GitHub Actions のワークフローでは一つ以上のジョブを定義し、ジョブはランナーと呼ばれるマシン上で実行されます。 ランナーは GitHub がホストするランナーと自己ホストランナーの2種類があります。 GitHub がホストするランナーは都合により利用できなかったため、今回は自己ホストランナーを用意します。

ランナーとして利用可能なマシンは1台だけありました。 単純にこのマシンにランナーアプリケーションをインストールすることでワークフローを実行できますが、ランナーは同時に一つのジョブのみ実行可能なため、複数の担当者が同時にワークフローを実行すると待ち時間が増えます。かと言ってマシンを増やすことも、担当者にランナーを追加することを頼むことも難しい状況でした。 そこで、1つのインストールで同時に複数のワークフローを実行できる ARC を導入しました。 ARC はこの状況下でワークフローの実行待ちを削減する良い選択肢だと考えました。

GitHub のドキュメントから ARC の説明を引用します。

ARC を使うと、リポジトリ、組織、またはエンタープライズで実行中のワークフローの数に基づいて自動的にスケーリングされるランナー スケール セットを作成できます。 制御されたランナーは一時的でコンテナーに基づく可能性があるため、新しいランナー インスタンスを迅速かつクリーンにスケールアップまたはスケールダウンすることができます。

(最終閲覧日: 2025/11/25)

またランナーの構築後、ワークフローを実行できなくなったことがありました。このような問題を防止するため、ランナーの実行状況を監視する仕組みも構築します。

環境

GitHubは、 GitHub Enterprise Cloud を利用します。

ワークフローを実行するランナーは、手元の PC にて実行します。 Minikube を利用して実験用の仮想マシン(VM)と Kubernetes クラスターを作成し、このクラスターに ARC をインストールし、 GitHub の Organization にランナースケールセットを追加します。これにより、 GitHub の Organization に含まれるリポジトリでワークフローが実行されると、ランナースケールセットにより一時的なランナーポッドが作成され、そのランナーでワークフロー内のジョブが実行されます。ただし、今回追加するランナーセットが意図しないところから利用されないよう、 GitHub の Organization にランナーグループを作成して利用可能なリポジトリを制限します。

またランナーの監視のため、 Prometheus を利用してランナーセットおよびランナーコントローラーのメトリクスを収集し、Grafanaを利用して可視化します。

図にすると以下のようになります。

構成図

構築手順

準備

Windows 11 Pro のマシンにて、 Hyper-V を有効にして、 Minikube, kubectl, Helm をインストールします。詳しくは過去の記事の「準備」の節を参照してください。なお今回利用したツールのバージョンは次の通りです。

> minikube version
minikube version: v1.35.0
commit: dd5d320e41b5451cdf3c01891bc4e13d189586ed-dirty
> kubectl version
Client Version: v1.32.2
Kustomize Version: v5.5.0
Server Version: v1.32.0
> helm version
version.BuildInfo{Version:"v3.19.0", GitCommit:"3d8990f0836691f0229297773f3524598f46bda6", GitTreeState:"clean", GoVersion:"go1.24.7"}

リポジトリの作成

GitHub の Organization にテスト用のリポジトリを作成します。手順の最後でこのリポジトリにワークフローを追加して実行します。

ランナーグループの作成

これから追加するランナーを利用可能なリポジトリを制限するために、 GitHub の Organizations にランナーグループを作成します。

  1. GitHubにログインし、ページ右上の自分のアイコン > Organizations を選択します。
  2. Organizations から目的の Organization を探し、その右側の Settings を選択します。
  3. 左側のサイドバーから Actions > Runner groups の順に選択します。
  4. New runner group を選択します。
  5. パラメーターを適切に入力または選択します。
    • Group name にランナーグループ名を入力します。例えば my-runner-set
    • Repository access にて、テスト用のリポジトリを選択します。
    • Workflow access は All workflows のままにしておきます。
  6. Create group を選択します。
新しいランナーグループの設定

Kubernetes クラスターの作成

Minikube を利用して、 Hyper-V の VM と Kubernetes クラスターを作成します。 Windows Powershell にて次のコマンドを実行します。 minikube コマンドのオプションはホストマシンの環境に合わせて変更してください。

minikube start `
 --driver=hyperv `
 --cpus=4 `
 --memory=8g `
 --disk-size=30g `
 --docker-opt default-address-pool=base=172.80.0.0/16,size=24 `
 --docker-opt dns="内部DNSサーバーのIPアドレス" `
 --addons ingress

GitHub Actions Runner Controllerのインストール

GitHub のドキュメントに従ってインストールしますが、メトリクスを収集するために追加の設定が2つ必要です。一つは ARC のメトリクス出力を有効化する設定、もう一つは Prometheus がメトリクスを出力する Kubernetes ポッドを特定するためのアノテーションの追加です。 arc.yaml ファイルを次の内容で作成します。

# メトリクスを有効化
metrics:
  controllerManagerAddr: ":8080"
  listenerAddr: ":8080"
  listenerEndpoint: "/metrics"

# Prometheusでスクレーピングする設定
podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/path: /metrics
  prometheus.io/port: "8080"

続いて、 Helm を利用して Kubernetes クラスターに GitHub Actions Runner Controller をインストールします。

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

GitHub Actions ランナースケールセットのデプロイ

こちらも同様に GitHub のドキュメントに従ってデプロイしますが、やはりメトリクスを収集するために追加の設定を行います。

GitHub ランナースケールセットのデプロイに先立って、ランナースケールセットが GitHub にアクセスする際の認証情報を作成します。認証情報としてパーソナルアクセストークンまたは GitHub App が利用できます。今回は検証のため簡単に作成できるパーソナルアクセストークンを作成します。

  1. GitHubにログインし、ページ右上の自分のアイコン > Settings を選択します。
  2. 左側のサイドバーから Developer Settings を選択します。
  3. 左側のサイドバーから Personal access tokens > Fine-grained tokens の順に選択します。
  4. Generate new token を選択します。 New fine-grained personal access token のページが表示されます。
  5. Token nameResource ownerExpiration を適切に入力または選択します。
  6. Repository access にて Only select repositories を選択し、ランナーを利用するリポジトリを選択します。
  7. Permissions にて、 Organizations を選択し、権限を追加します。必要な権限は、 Administration (Read-only) と Self-hosted runner (Read and write) です。
  8. Generate token を選択します。
  9. 確認ダイアログが表示されるので、 Generate token を選択します。
  10. 生成されたパーソナルアクセストークンをコピーします。
パーソナルアクセストークンの権限設定

次に、 GitHub ランナースケールセットの設定を記述します。 arc-runner-set.yaml ファイルを次の内容で作成します。 githubConfigUrl や githubConfigSecret.github_token の値は変更してください。

# ランナーを構成するリポジトリや組織のURL
githubConfigUrl: "https://github.com/myorg"

# GitHub APIの認証に使用する情報
githubConfigSecret:
  github_token: "GitHub パーソナルアクセストークン"

# ランナーの最大数
maxRunners: 5

# ランナーグループ
runnerGroup: "my-runner-set"

listenerTemplate:
  metadata:
    annotations:
      # Prometheusでスクレーピングする設定
      prometheus.io/scrape: "true"
      prometheus.io/path: /metrics
      prometheus.io/port: "8080"
  spec:
    containers: []

続いて、 Helm を利用して Kubernetes クラスターに GitHub Actions ランナースケールセットをデプロイします。

$INSTALLATION_NAME="my-runner-set"
$NAMESPACE="arc-runners"
helm install "${INSTALLATION_NAME}" `
    --namespace "${NAMESPACE}" `
    --create-namespace `
    --values arc-runner-set.yaml `
    oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set

正常にインストールされると、 GitHub のリポジトリの Settings > Actions > Runners に INSTALLATION_NAME で指定した名前のリスナーが登録されます。

GitHub のリポジトリにランナースケールセットが登録されている様子

これでワークフローを実行する準備が整いました。

Prometheusのインストール

今度は監視と可視化の仕組みを構築していきます。メトリクスを集約するための Prometheus と、 Prometheus Node Exporter をインストールします。 Prometheus Node Exporter は、 Kubernetes ノードの CPU 使用率やディスク使用率などのメトリクスを収集するためにできるため、 Prometheus Node Exporter からメトリクスを収集するための設定も行います。まずは prometheus.yaml ファイルを次の内容で作成します。

prometheus-node-exporter:
  # Prometheus Node Exporterもインストールする
  enabled: true
  podAnnotations:
    # Prometheusでスクレーピングする設定
    prometheus.io/scrape: "true"
    prometheus.io/path: /metrics
    prometheus.io/port: "9100"

続いて Prometheus と Prometheus Node Exporter をインストールします。

$NAMESPACE="prometheus"
helm install prometheus oci://ghcr.io/prometheus-community/charts/prometheus `
    --namespace "${NAMESPACE}" `
    --create-namespace `
    --values prometheus.yaml

Grafana

Prometheus で収集したメトリクスを可視化するために Grafana をインストールします。 PC からウェブブラウザで Grafana にアクセスするために、まずは minikube ip コマンドを実行して VM の IP アドレスを取得します。続いて grafana.yaml ファイルを次の内容で作成します。 <VMのIPアドレス> は、取得した VM の IP アドレスに置き換えます。

# Grafana サーバーの設定
grafana.ini:
  server:
    domain: "<VMのIPアドレス>.nip.io"
    root_url: "%(protocol)s://%(domain)s/grafana"
    serve_from_sub_path: true

# インストール済みのPrometheusを参照するための設定
datasources:
  datasource.yaml:
    apiVersion: 1
    datasources:
      - name: Prometheus
        type: prometheus
        url: http://prometheus-server.prometheus.svc.cluster.local
        isDefault: true

# ブラウザでGrafanaにアクセスするための設定
ingress:
  enabled: true
  hosts:
    - "<VMのIPアドレス>.nip.io"
  path: "/grafana"

そして、 Helm を利用して Grafana をインストールします。

$NAMESPACE="grafana"
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update grafana
helm install grafana grafana/grafana `
    --namespace "${NAMESPACE}" `
    --create-namespace `
    --values grafana.yaml

続けて Grafana にログインするためのパスワードを取得します。

$EncodedText = kubectl get secret --namespace grafana grafana -o jsonpath="{.data.admin-password}"
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($EncodedText))

ウェブブラウザで http://<VMのIPアドレス>.nip.io/grafana/ にアクセスするとログインページが表示されます。ユーザー名に admin 、パスワードに先ほど取得したパスワードを入力してログインします。

ダッシュボードの作成

ARC には Grafana でメトリクスを可視化するダッシュボードのサンプルがあるのでそのまま使います。

  1. ダッシュボードのサンプル の JSON をコピーします。
  2. Grafana のページ右上の  > Import dashboard の順に選択します。
  3. Import via dashboard JSON model に、コピーしたJSONを貼り付けます。
  4. Load を選択します。
  5. prometheus に Prometheus (default) を選択します。
  6. Import を選択します。

これでダッシュボードができました。

ARC ダッシュボード

試す

テスト用のリポジトリに .github/workflows/github-actions-demo.yml ファイルをプッシュします。ファイルの内容は以下の通りです。

name: My Runner Set Demo
on: [push, workflow_dispatch]
jobs:
  Explore-GitHub-Actions:
    runs-on: my-runner-set
    steps:
      - name: リポジトリをチェックアウト
        uses: actions/checkout@v5
      - name: リポジトリの中のファイル一覧を表示
        run: ls
      - name: ダッシュボードで実行中の様子を観察するため待機
        run: sleep 300

上記のファイルを GitHub のリポジトリにプッシュするとワークフローが実行されます。ワークフローのジョブが実行待ちになると一時的なランナーが起動し、起動が完了するとジョブが実行されます。リポジトリの Actions タブ > My Runner Set Demo に移動し、 Run workflow > Run workflow を何回か選択していくつか実行してみます。 Grafana のダッシュボード上で実行中のジョブ数に応じたランナーが実行されている様子を確認できます。

リポジトリに一時的なランナーが追加されている
複数のワークフローを実行中のダッシュボードの表示

考察とまとめ

GitHub Actions Runner Controller を利用して、ワークフローを実行に応じてランナーを自動的に増減できる Actions Runner Controller と、その実行状況を可視化する仕組みを構築しました。 1台のマシンで複数のワークフローを同時に実行できたり、ランナーに使用するマシンの数やセットアップの労力を削減したりすることができる良い仕組みだと感じました。

この記事を通じて、GitHub Actions のワークフローを実行するランナーを自身で構築し運用する方法を学び、より円滑なCI/CD環境を実現する手助けになれば幸いです。

参考

By tsakai

Jenkins関連のサービスやCloudBees製品を主に担当しています。 Certified CloudBees Jenkins Engineer (CCJE) および CloudBees CI DevOps Associate です。