GitHubで開発を行う際、CI/CDには通常GitHub Actionsを利用することが多い。プライベートリポジトリであっても同様だが、プランによっては無償で利用できるRunnerの上限が月2,000分までという制限がある。
For private repositories, each GitHub account receives a certain amount of free minutes and storage for use with GitHub-hosted runners, depending on the account's plan. Any usage beyond the included amounts is controlled by spending limits.
今回、この制限を超えてしまったリポジトリがあり、代替案を検討したところ、AWSアカウントを利用してCodeBuildをRunnerとして活用する方法を採用することにした。
GitHub ActionsからのSelf-hosted Runner on CodeBuildの利用
GitHub ActionsからCodeBuildをSelf-hosted Runnerとして利用する方法は大きく2つある。
runs-onにCodeBuild上のRunnerを指定し、ワークフロー全体を実行する。- GitHub Actionsの特定のステップとして、aws-codebuild-run-buildアクションを利用しCodeBuild上のプロジェクトを実行する。
前者はGitHub Actionsのワークフロー全体をCodeBuild上で実行する方式であり、後者は一部のステップのみをCodeBuildで実行する方式である。しかし、今回はGitHub Actionsの無償枠を超過しているため、後者の方法ではRunnerを利用できない。そのため、前者の方式を前提に構築を進めた。
AWS環境の構築(Terraform)
AWS環境はTerraformを用いて構築する。必要なリソースは以下の通り。
- CodeBuildプロジェクト
- GitHubと接続するためのCodeConnections
- Webhookの設定
特に注意が必要なのは、CodeBuildとGitHubの関連付けを行わないとWebhookの作成に失敗する点である。そのため、Terraformの適用は2フェーズに分ける必要がある。
1. CodeBuildの構築
CodeBuildの構築はシンプルで、以下のようにTerraformで定義する。
resource "aws_codebuild_project" "github_runner" { name = "github-runner" description = "GitHub Runner for GitHub organization" service_role = aws_iam_role.codebuild.arn build_timeout = "60" # minutes badge_enabled = false project_visibility = "PRIVATE" environment { # see: https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-compute-types.html#environment.types compute_type = "BUILD_GENERAL1_SMALL" # 4 GiB、2 vCPU # see: https://docs.aws.amazon.com/codebuild/latest/userguide/ec2-compute-images.html image = "aws/codebuild/standard:5.0" # Amazon Linux 2023 type = "LINUX_CONTAINER" } logs_config { cloudwatch_logs { status = "ENABLED" group_name = aws_cloudwatch_log_group.codebuild.name } } source { type = "GITHUB" buildspec = var.build_spec_content # optionalなので不要な気もする git_clone_depth = 1 location = var.github_repository_url report_build_status = true } artifacts { type = "NO_ARTIFACTS" } } # 関連リソースは略
2. CodeBuildとGitHubとの関連付け
CodeConnectionsを利用してGitHubとの接続を設定する。これはGitHub Appsを組織やリポジトリに導入することを意味する。
resource "aws_codeconnections_connection" "github_connection" { name = var.connection_name provider_type = "GitHub" }
Terraformを適用すると、AWS管理コンソールの「接続」メニューに保留状態のレコードが作成される。

この「保留中の接続を更新」ボタンを押し、GitHubとのOAuth認証を完了させると、AWS Connector for GitHubがインストールされる。 ちょっとわかりづらい遷移だと思うが、このあたりの操作はエントリがわかりやすい。
3. Webhookの構築
GitHubのPull Request作成などのイベントをトリガーに、CodeBuildがRunnerを起動する。Webhookは以下のTerraformコードで作成可能。

applyしたら上の画像のように、GitHub側にWebhookが構成される。
resource "aws_codebuild_webhook" "github_runner" { project_name = aws_codebuild_project.github_runner.name build_type = "BUILD" filter_group { filter { pattern = "WORKFLOW_JOB_QUEUED" type = "EVENT" } } }
GitHub Actions側
GitHub Actions側では、RunnerとしてCodeBuildを指定する。以下のサンプルは、AWSの公式ドキュメントLabel overrides supported with the CodeBuild-hosted GitHub Actions runnerから引用したものである。
name: Hello World on: [push] jobs: Hello-World-Job: runs-on: - codebuild-myProject-${{ github.run_id }}-${{ github.run_attempt }} - image:${{ matrix.os }} - instance-size:${{ matrix.size }} - fleet:myFleet - buildspec-override:true strategy: matrix: include: - os: arm-3.0 size: small - os: linux-5.0 size: large steps: - run: echo "Hello World!"
runs-onでのRunner指定ルールはcodebuild-<project-name>-${{github.run_id}}-${{github.run_attempt}}というルールになっている。
また、CodeBuildのプロジェクト側にデフォルトのイメージやインスタンスサイズを設定できるが、ワークフロー側でimage やinstance-sizeを上書きすることも可能である。
結果
この設定により、GitHub ActionsのワークフローがCodeBuild上で実行されるようになった。これでプライベートリポジトリのActions実行時間上限を気にせずに済むようになった。