Open6

philips-labs の GitHub Actions Self-hosted Runner の Terraform モジュールの README を読む

gkzgkz

Motivation

This module creates the AWS infrastructure to host action runners on spot instances. It provides lambda modules to orchestrate the life cycle of the action runners.

  • ランナーは Spot Instance 上でホストしている
  • Spot Instance のスケールアップ/ダウンはLambdaで制御

なぜ、Lambda を選んだのか?

  • AWS, GitHub に最小限のアクセスで小さなコンポーネントが作成できるため
  • Repository レベルで動作し、Organization レベルまでスケールする、最小限のコストでスケーラブルなセットアップを提供できるため

Kubernetes を選ばなかった理由は?

With this setup, we stay quite close to the current GitHub approach.

同モジュールが描くランナーの構成は、GitHub で採用されているランナーの構成と近しい

gkzgkz

Overview

処理の流れ以前に必要な設定

# 略
jobs:

  build:
    name: Build
    runs-on: self-hosted

処理の流れ

    1. check_run あるいは workflow_job イベントが発生してから SQS へメッセージを送信する
    1. SQS のメッセージを listenしている "scale up runner" lambda が Spot Instance を起動する
    1. "scale up runner" lambda は a registration token を GitHub にリクエストする
    1. Spot Instance は launch template をベースに作られてから、いよいよワークフローが走る
    1. ランナーのスケールダウンの仕組み
    1. Downloading the GitHub Action Runner distribution が10分強遅いことがあることとその対処法
    1. シークレットや権限のお話

1) check_run あるいは workflow_job イベントが発生してから SQS へメッセージを送信する

  • check_run あるいは workflow_job イベントが発生したことを、GitHub App が検知
  • イベントを検知したGitHub App は Webhook を API Gateway 経由で Lambda へ送信
  • GitHub App から Webhook を受け取った Lambda は SQS へメッセージを送信

2) SQS のメッセージを listenしている "scale up runner" lambda が Spot Instance を起動する

  • "scale up runner" lambda は SQS からのメッセージを受け取る
  • Spot Instance を起動するところの Lamba による処理。既存のランナーによってビルドが始まっていたり、ランナーの最大数に到達していたら、 Spot Instance を起動させないといったロジックを組み込むこともできる

3) "scale up runner" lambda は a registration token を GitHub にリクエストする

  • このトークンは後にランナーが自分自身を登録するために必要
    • 登録されると、Action > Runner の画面に出る?
    • agent というのは、ランナーのエージェントのことと理解

4) Spot Instance は launch template をベースに作られてから、いよいよワークフローが走る

  • launch template はインスタンスの仕様を定義したり、user-data script を提供する

5) ランナーのスケールダウンの仕組み

  • ランナーをスケールダウンさせるかどうかは、全てのランナーに対して指定した分単位の間隔で busy であるかチェックし、busy でなければ GitHub(の Actions > Runner の登録)からそのランナーは削除され、Spot Instance も Terminate される

6) Downloading the GitHub Action Runner distribution が10分強遅いことがあることとその対処法

  • ランナーのバイナリデータを S3 からダウンロードすることで、ダウンロード処理が遅くならないようにしている

7) シークレットや権限のお話

  • シークレットや private keys は SSM Parameter Store で管理
  • 必要な権限
    • GitHub App から API GW へ向けて workflow_job イベントを通知するところ
    • Lambda が Spot Instance をスケールアップ、ダウンさせたりタグを付与するところ

調べたいこと

check_runworkflow_job の違い

  • workflow_job : (preferred option) create a webhook on enterprise, org or app level. Select this option for ephemeral runners. (企業、組織、またはアプリレベルでWebhookを作成します。 エフェメラルランナーの場合は、このオプションを選択してください)
  • check_run : create a webhook on enterprise, org, repo or app level. When using the app option, the app needs to be installed to repo's are using the self-hosted runners. (エンタープライズ、組織、リポジトリ、またはアプリレベルでWebhookを作成します。 アプリオプションを使用する場合、レポがセルフホストランナーを使用するようにアプリをインストールする必要があります。)

https://github.com/philips-labs/terraform-aws-github-runner/blob/c5e3c21a5c963b083ca3756a53c3e55a408c144c/modules/webhook/lambdas/webhook/src/webhook/handler.ts#L10

https://github.com/philips-labs/terraform-aws-github-runner/blob/c5e3c21a5c963b083ca3756a53c3e55a408c144c/modules/webhook/lambdas/webhook/src/webhook/handler.ts#L65-L78

gkzgkz

Major configuration options

  • Org vs Repo level
  • Checkrun(Default) vs Workflow job event
    • Workflow job event: runner_enable_workflow_job_labels_check = true
  • Linux(Default) vs Windows
  • Re-use(Default) vs Ephemeral.
  • Once idle they will be removed from the pool

  • GitHub Cloud vs GitHub Enterprise Server (GHES)
  • Spot vs on-demand

スケールダウンさせるタイムアウト時間の初期値は 60 秒
https://github.com/philips-labs/terraform-aws-github-runner/blob/7cd2524ed0dba38849ac1e0e477cffda24bf21a3/variables.tf#L114-L118

gkzgkz

スケールダウン(ランナーの起動インスタンスを落とす間隔)

  • scale_down_schedule_expression で指定
  • 採用されている Cron のようなスケジューリング記法は Amazon EventBridge で指定されているもの?(あるいは一般的な書き方なのか?)以下の場合、1分間隔。

https://github.com/philips-labs/terraform-aws-github-runner/blob/24bee359ecbd29af658308a9a7dce079bda3f661/examples/ephemeral/main.tf#L55-L56

  • 一箇所だけ ? が採用されている理由

You can't use * in both the Day-of-month and Day-of-week fields. If you use it in one, you must use ? in the other.

月初日と週初日の両方のフィールドで*を使用することはできません。片方で使用する場合は、もう片方で「?」を使用しなければなりません。(DeepLより)

参考: