{{< youtube id="s23QvNz2WuY?si=L5HNCesomlIeqzfN" title="Running Github self hosted runner with EKS Auto" >}}
*2025年4月5日、私は EKS AutoでGithub Actions Self Hosted Runnersの運営方法 についてライブ配信を行いました。AWS Heroesと *ジョーンズ・ ザカライア・ノエル*と一緒に。
免責事項: 🐶 ビーグルは被害を受けていません。少し苛立ったかもしれませんが、無事です。
結果の「{Performance, Speed, Cost}」は驚くべきだけでなく、完璧で、 エンタープライズレベルでこのソリューションを採用するに十分な可能性を秘めました。このソリューションはAWSに依存しないだけでなく、このブログで得た知識はAzure(AKS)、Google(GKE)、あるいは自社のベアメタルサーバー上でK8を運用する場合にも拡張可能です。
すぐに解決策を試したい方は、 こちらのリポジトリをフォローしてください
これは少し長くなりますので、コーヒーを手に取り、くつろいで、最適な開発者のポジション™に座っていることを確認してください。
- 建築
- なぜこの解決策を選ぶのか
- K8でのセルフホストランナーコンセプト
- テラフォームコードのウォークスルー
- この解のテスト方法
- Githubの大型ホストランナーとEKS Auto上のランニングランナーの比較
- ソリューションアーキテクトの視点から
Architecture
なぜこの解決策なのか
私は Colorkrew でシニアDevOpsエンジニアとして働いており、多くの製品と開発ワークフローをサポートするために多くのGitHubリポジトリがあります。
製品ポートフォリオを拡大し始めるにつれ、CI/CDパイプラインもより複雑で同時進行かつ頻繁になり、より多くの計算能力と、最終的にはより堅牢なインフラ層の必要性が高まり、成長するニーズを支えるようになりました。
デフォルトの無料マシン(ランナーと呼ばれる)でGithubアクションを実行するのは遅くなり、最初の解決策はGitHubが提供する有料の大規模ホストランナーを使うか、Kubernetesのようなインフラ上でランナーを動かすことでした。
そこで「パフォーマンス、速度、コストの面で両方のソリューションを比較する」ことを始め、これがGitHubのセルフホストランナーをEKS Auto上で動かすきっかけとなりました。
## K8
Runners: ワークフローで定義されたジョブを実行するマシン(サーバーまたは仮想環境)です。管理する場合、Self Hosted runner、またはGitHub Hosted runnerとして呼び出されます。Runnerは一時的な性質を持っています。
ランナースケールセット: これは、同一な性質を持つ論理的なランナーのグループと考えてください。つまり、特定のグループ下のすべてのランナーは同じ構成を持つということです。リポジトリ、組織、エンタープライズレベルでインストール可能です。
もし異種セットアップ、つまり異なるCI/CDジョブごとにランナーの異なる構成を望むなら、複数のランナースケールセットが必要です。
ランナースケールセットで知っておくべきもう一つの重要な点は、常に最小・最大ランナー数を設定できることです。
ランナースケールセットの名前: ランナースケールセットは名前でアドレス指定できるので覚えておいてください。なぜなら、GHAの「runs on:」プロパティでそのランナースケールセットの名前を指定する必要があるからです。
- エンドポイント: ARCは「api.github.com」と「pipelines.actions.githubusercontent.com」の2つのエンドポイントと通信します。組織のファイアウォール、プロキシ、NATゲートウェイなどが、上記のエンドポイントをARCコントローラーとして許可するように設定されていることを確認してください。
- ARCコントローラー: 2つのエレメント/ポッドを搭載。
*「コントローラーマネージャー」:最初にオンラインになるポッド。これはクラスター内の異なるリソースを管理する異なるコントローラーです。重要なのは、「AutoScalingListener」コントローラーがリスナーポッドを管理しているということです。
- リソースの作成と、望ましいカウントと状態に一致させる責任を負います。
- 「Runner ScaleSet Listener」:スケーリングニーズに関する意思決定を管理します。ランナーの数を決定する責任があります。各リスナーは自分のポッドを持っており、ランナースケールセットごとにリスナーポッドが1つあります。ランナースケールセットが2つある場合は、コントローラーマネージャーのような同じ名前空間に2つのリスナーポッドを置くか、異なる名前空間(設定可能)に設定可能です。
自分の類推😋🫣で説明しやすくしたほうがいいと思いました
アクションランナーコントローラー(ARC )は、スマートで自動化されたコーヒーショップのマネージャーのような存在で、来店する顧客数(ワークフロー)を監視し、必要に応じてバリスタ(ランナー)を即座に採用または解雇します。
一日中バリスタが待機する代わりに、ARCはお客様が到着した時のみ一時的なバリスタ(Kubernetesのコンテナ)を立ち上げ、作業が終わると解雇します。これによりシステムは迅速かつ効率的、かつコスト効率的です。*
*ランナースケールセット*を使え**ば、*店舗の忙しさに応じて、同時に何人のバリスタを配置したいかのルールを決められ、残りはARCが対応します。
詳細なエンドツーエンドのワークフローについてはこちらでご覧いただけます
GitHubのTerraformコードウォークスルービュー
Amazon EKSでGitHubアクションのセルフホストランナーの自動スケーリング設定
はじめに
このウォークスルーでは、Amazon EKS上でGitHub Actions Runner Controller(ARC)を設定し、ワークフローの需要に応じてセルフホストランナーを自動的にスケールさせます。
プロジェクト構造
実装の構成は以下の通りです:
eks-auto-self-hosted-runners/
├── README.md
├── 建築/
├── commit_log.txt
├── 台本/
└── テラフォーミング/
├── ベース/
└── モジュール/
├── アーク/
├── eks/
├── karpenter_config/
└── VPC/
1. ルートディレクトリ - メインのREADMEおよびアーキテクチャ図を含む
2. スクリプト/ - クリーンアップやパフォーマンステスト用のユーティリティスクリプトを含みます
3. terraform/ - 主要なインフラストラクチャコード
base/ - Terraform展開の入口
モジュール/- 再利用可能なテラフォームモジュール:
arc/ - アクションランナーコントローラの設定
eks/ - EKSクラスタ構成
karpenter_config/ - ノードの自動スケーリング設定
VPC/ - ネットワークインフラ構成
アーキテクチャ概要
私たちのソリューションは以下のコンポーネントを使用します:
- Amazon EKS Auto:Karpenterを用いてランナーインフラをホストし、ランナーのコンピュート向けにオンデマンドでノードをプロビジョニングするマネージドKubernetesサービス
- GitHub Actions Runner Controller(ARC):セルフホストランナーを管理するKubernetesコントローラー
- Terraform:すべてのコンポーネントを展開・管理するためのInfrastructure as Codeツール
このアーキテクチャにより、GitHub Actionsのワークフローはランナーを動的にリクエストでき、EKSクラスターでオンデマンドでプロビジョニングされ、不要な時は自動的に縮小されます。
ステップ1:インフラの構築
VPC構成
まずパブリックサブネットとプライベートサブネットでVPCを作成します。VPC構成は10.0.0.0/16のCIDRブロックを使用し、サブネットは2つの可用性ゾーンに分散しています。その
プライベートサブネットにはEKSノードが配置され、パブリックサブネットはNATゲートウェイやロードバランサーに使用されます。
terraform/base/vpc.tf の設定はVPCモジュールを参照し、Kubernetes統合に必要なすべてのネットワークコンポーネントを設定し、適切なタグ付けで対応します。
EKSクラスター構成
次に、 terraform/modules/eksで定義されたEKSモジュールを使ってEKSクラスターを作成します。私たちのクラスターはKubernetesバージョン1.31を実行し、実行用のシステムノードグループを含んでいます
必須のクラスターサービス。
terraform/base/eks.tf ファイルはクラスタをパブリックエンドポイントアクセスで設定し、ワーカーノードをプライベートサブネットに配置してセキュリティを強化します。
ステップ2:EKS AutoのプリインストールKarpenterを自動スケーリングに設定する
EKS AutoにはKarpenterがプリインストールされています。Karpenterを活用して、GHAランナーのコンピュート向けに、希望するEc2タイプ、容量、構成からEc2スポットインスタンスのプロビジョニングと自動スケーリングを行います。
私たちのKarpenter設定の terraform/base/karpenter_config.tf では、コスト効率のためにm7aインスタンスタイプとスポット価格を使用しています。統合ポリシーは「WhenEmpty」に設定され、5分間のタイムアウトがあります。これはノードが不要になったときに削除されることを意味します。
主な構成パラメータは以下の通りです:
・インスタンスタイプ:8CPUを搭載したm7aファミリー
• 容量タイプ:コスト削減のためのスポットインスタンス
• ストレージ容量:300GB、5000 IOPS
• 可用性ゾーン:US-east-1aおよびUS-east-1b
ステップ3:アクションランナーコントローラー(ARC)の展開
現在、terraform/modules/arcで定義されたARCモジュールを使ってGitHub Actions Runner Controllerを展開しています。モジュールはterraform/base/arc.tfで参照され、設定パラメータは locals.tf から得られています。
ARCの展開は主に2つのコンポーネントで構成されています。
- コントローラー:ランナーポッドのライフサイクル管理
- ランナー集合:ランナーの構成を定義する
コントローラー展開
コントローラーは公式GitHub Actions Runner ControllerリポジトリのHelm chartを使ってデプロイされます。構成はterraform/modules/arc/controller.tfで定義され、helm/controller_values.yamlの値を使います。
ランナーセット構成
私たちは2種類のランナーセットを展開しています:
- スタンダードランナー:一般的なワークフロージョブ用
- Docker-in-Docker(DinD)ランナー:Dockerイメージを構築するジョブ用
- また、「Kubernetesモード」と呼ばれる別のタイプのランナーセットもあり**、組織がDockerをスーパーユーザーコンテキストで実行できない場合に使用すべきです。例えば、DinDランナーがKubernetesモードを使う場合**に備えます(このブログでは扱っていません)
ランナーセットはterraform/modules/arc/runner_sets.tfで定義され、それぞれhelm/arc_listener_values.yamlとhelm/arc_listener_values_dind.yamlの値を使います。
注意:コントローラポッドとランナースケールセットポッドは信頼性のためにオンデマンドEC2インスタンスに展開するように設定し、エフェマルランナーポッドはスポットインスタンスを実行するように設定することが非常に重要です。
# オンデマンドNodeのコントローラー設定
nodeSelector:
karpenter.sh/nodepool:システム
耐性:
- キー:「CriticalAddonsOnly」
オペレーター:「存在する」
# オンデマンドノードのリスナー設定
リスナーテンプレート:
スペック:
nodeSelector:
karpenter.sh/nodepool:システム
耐性:
- キー:「CriticalAddonsOnly」
オペレーター:「存在する」
ステップ4:GitHub認証設定
ARCはGitHubアプリを使ってGitHubと認証します。認証情報はKubernetesの秘密に保存され、ランナーコントローラーがGitHubと認証するために使います。
認証を設定するには:
- 必要な権限を持つGitHubアプリを作成する
- アプリの秘密鍵を生成する
- アプリのID、インストールID、秘密鍵をterraform/modules/arc/secrets(**作成を忘れずにgitignored)**ディレクトリに保存します
- terraform/modules/arc/secrets.tf ファイルはこれらの認証情報でKubernetesシークレットを作成します
ステップ5:名前空間管理
ARCコンポーネント専用の名前空間を作成します:
- アークシステム:コントローラコンポーネント用
- アークランナー:ランナーポッド用
これらの名前空間はterraform/modules/arc/namespaces.tfで定義されています。
ステップ6:清掃処理
リソースの適切なクリーンアップを確保するために、スクリプト/cleanup-finalizers.sh にクリーンアップスクリプトを組み込み、Kubernetesリソースからフィニライザーを削除しています。このスクリプトはTerraformの破壊プロセス中に呼び出され、リソースが適切にクリーンアップされていることを確認します。
スクリプトは以下のような様々なリソースタイプを扱います:
• AutoscalingRunnerSet
• エフェメラルランナーセット
• オートスケーリングリスナー
• サービスアカウント
・ロールバインディング
・役割
仕組み
- GitHub Actionsのワークフローが実行されると、特定のラベルを持つランナーを要求します
- ARCコントローラがこの要求を検出し、EKSクラスター内にランナーポッドを作成します
- 必要に応じて、Karpenterはランナーポッドをホストするための新しいEC2インスタンスをプロビジョニングします
- ランナーはGitHubに登録し、ワークフロージョブを実行します
- 作業完了後、ランナーポッドは終了します
- ランナーが不要になった場合、カーペンターは未使用ノードを統合・削除します
このアプローチの利点
- コスト効率: ランナーは必要な時のみプロビジョニングされ、アイドル時には自動的に縮小されます
- 柔軟性: カスタムランナー環境は特定のワークフロー要件を満たすために定義可能です
- スケーラビリティ: システムは多数の同時処理ワークフローを扱えます
- セキュリティ: ランナーは定義されたセキュリティコンテキストを持つ隔離されたKubernetesポッド内で動作します
- 信頼性: 故障したランナーは自動的に交換され、ワークフローの信頼性を確保します
この解のテスト方法
異なる タイプのGHA を3つ作成し、異なるシナリオをテストしました。
簡単なテスト
最初のタイプは単純なGHAですが、注目すべき重要な点は「アークランナーセット」ラベルを使用する ランオン パラメータです。
最初のワークフローを実行すると約1分かかります。なぜなら『Karpenter』がEc2インスタンスをプロビジョニングしているからです。
一度プロビジョニングされ、Ec2インスタンスがすでに存在しているため再度ワークフローを実行すると、アクションは即座に実行完了します。
Karpenterは、少なくとも5分間使われていなければノードを削除します。
もしレイテンシに敏感な動作をすぐに実行する必要があるなら、 runner scale setの設定にminRunners>0を設定します
同時ジョブテスト
このGHAでは 、5つの同時ジョブを実行しており、それぞれ1分間ずつプッシュまたは手動でトリガーされています。
DinDの職業試験
時には、redisのようなコンテナでマイクロサービスを実行し、e2eテストを行いたい場合もあります。
そこにDocker、Inside Docker、いわゆるGHAが必要です。
ここで重要な点はランオン パラメータ で、これは特にdindワークフロー向けに異なるランナーセットを配置しています
このワークフローでは、ビジーボックスコンテナがメインジョブを実行し、それがredisのサービスコンテナと通信できます。
Githubの大規模ホストランナーとEKS Autoのランニングランナー
パフォーマンスとスピード
8コアCPUと私たちのソリューションの性能と速度を比較してみました。
自動コミットスクリプトを使って10分間スリープマトリックスGHAを実行し、45秒ごとにすべてのコミットが発生し、EKS AutoソリューションとGithubの大規模ランナーの両方で同時進行のジョブ状況を実質的にシミュレートしましたが、結果は断然私たちのソリューションに有利でした
当社のソリューションは安定したパフォーマンスを持ち、実行時間は1分8秒にとどまります。
価格
更新 [2025年4月21日] :先ほどEKSの自動ノード管理価格でミスをしましたが、訂正後に当社のソリューションでさらに安くなっています
これは少し難しく、100%正確な比較ではないかもしれませんが、それでも70〜80%の正確さと見なすことができます。
30日間の月を1日あたり1時間の同時CIワークロード(12ジョブが並行して実行)と仮定します。私たちのソリューションとGithubのセルフホストランナーのコストを計算してみましょう
私たちの解法<
Githubの大型ランナー用
また、Github Teams/Enterpriseのサブスクリプションも有料です。おそらくTeamの10人チーム向けの安価な方だと思います
EKSでm7a.2xlargeスポットノードを使ったセルフホストは月額約 170.38ドル、同じGitHubの8コア大規模ホストランナーは 月額731.20ドルなので 、私のEKS Autoでのソリューションは76.7%の大幅な節約を実現しています。*
注: EKSソリューションにGithub Teamのソリューション(例えば40ドル上乗せ、つまり170+40=月210ドル)を加えても、それでも72%の大幅な節約になります
仮に1時間ではなく、1日あたり2時間の同時CIワークロード(12ジョブが並列で動作)だとしましょう
注記: ネットワークコンポーネントのコスト、例えば「NATゲートウェイ」をまだ追加していませんが、合計してもGitHubの大規模ランナーの方が安くなります:D
ソリューションアーキテクトの視点から
Amazon EKS AutoとGitHub Actions Runner Controllerを組み合わせることで、AWS Well-Architected Frameworkに沿ったソリューションを作り上げました。
運用の卓越性:
• Terraformを通じたコードとしてのインフラストラクチャは一貫した展開を保証します
・自動スケーリングランナーにより手動のキャパシティ管理が不要
・部品のクリーンな分離により保守性が向上します
セキュリティ:
• スコープ付きアクセスによるGitHubアプリ認証
• EKSセキュリティグループおよびIAMロールは最小権限を強制します
・プライベートサブネットは攻撃対象を削減します
信頼性:
• マルチAZ展開による高可用性確保
• ゼロからの自動スケーリングにより、手動介入なしに様々な作業負荷に対応
・EKS AutoのKarpenterはインテリジェントノードプロビジョニングを提供し、必要な時にリソースが利用可能であることを保証します
パフォーマンス効率:
• オンデマンドスケーリングにより、リソースが必要な時のみ使用されます
・スポットインスタンスはコストを削減しつつパフォーマンスを維持する
・カスタマイズ可能なインスタンスタイプにより、特定のワークロード要件に最適化が可能
• Docker 中の Docker サポートにより、最小限のオーバーヘッドでコンテナベースのワークフローが可能になります
コスト最適化:
• ワークフローが稼働していない場合のコストを削減するスケール・トゥ・ゼロ能力
・スポットインスタンスはオンデマンドインスタンスと比べて最大90%の大幅なコスト削減を提供します
・カーペンターの「WhenEmpty」ポリシーによる資源統合
持続可能性:
・自動スケーリングによる効率的な資源利用により、環境への影響が最小限に抑えられます
・スケール・トゥ・ゼロ能力により、アイドル時のエネルギー消費が削減されます
・稼働資源の削減、エネルギー消費の低減
このソリューションは、組織がGitHub Actionsワークフローを運用しつつ、インフラを完全にコントロールできるスケーラブルでコスト効率の高いプラットフォームを提供します。このアーキテクチャは、小規模な開発チームからエンタープライズレベルの展開まで容易にスケールでき、変化するワークフロー要件に適応しつつ、セキュリティやパフォーマンスを損なうことはありません。
EKSのようなAWSマネージドサービスを活用し、Terraformを通じてインフラをコードとして実装することで、運用上のオーバーヘッドを削減しつつ、必要な柔軟性を提供します
現代のCI/CDパイプラインのために。その結果、チームがインフラ管理よりも価値の提供に集中できる、堅牢で効率的なプラットフォームが誕生しました。
ザックスの番組『Talking AWS』をYouTubeでフォローするか、AWSに関する知識を共有したい場合は彼らに連絡してください。
この解決策について質問があれば、LinkedInやXで私に連絡してください。
星開発財団推進
🚀 Stellar Dev Diaries シリーズ:エピソード1がライブ配信中!
ゼロからWeb3スタートアップを築くには何が必要か考えたことはありますか?Stellar Dev Diariesシリーズでは、Stellar Networkを基盤にした開発者チームが、ハッカソン勝利から資金調達とメインネットでのローンチまでの旅路を追います。
続きを読む****







