Jenkins Executor最適化マスターガイド:ビルドを高速化する

Jenkins Executorの設定をマスターしてCI/CDパフォーマンスを最適化しましょう。このエキスパートガイドでは、CPUとI/Oの制約に基づいて最適なExecutor数を計算し、ビルド待ち時間を削減し、エージェントスループットを最大化する方法を解説します。Pipelineの並列処理の活用、静的エージェントと動的エージェントの管理、キュー長やI/O待ちなどの主要メトリクスを使ったボトルネック特定など、重要な設定戦略を学びます。これらの実践的な手順を実装して、より高速なビルドと効率的なJenkins環境を実現しましょう。

Jenkins Executor最適化マスターガイド:ビルドを高速化する

Jenkins Executorの最適化は、実際には小さな単位でのキャパシティプランニングです。Executorとは、Jenkinsがノード上で作業を実行できるスロットのことです。スロットが少なすぎるとジョブがキューで待機し、多すぎるとすべてのビルドがCPU、メモリ、ディスク、ネットワーク、そして時には同じ依存関係キャッシュを奪い合うことになります。

目標は「より多くのExecutor」ではありません。目標は、個々のビルドの信頼性を損なうことなく、総フィードバック時間を短縮することです。

コントローラーのExecutorはゼロに設定

最新のJenkinsインストールのほとんどでは、コントローラーはワークのスケジュール、UIの提供、ジョブ設定の保存、エージェントの調整を行うべきです。コードのコンパイルやテストスイートの実行は行うべきではありません。

特別な管理ジョブをそこで実行する必要がある場合を除き、コントローラーのExecutorは0に設定してください。コントローラーでビルドが実行されると、UIが応答しなくなり、キューのスケジューリングが遅延し、プラグインの問題の診断が難しくなります。コントローラーが不安定になると、Jenkinsを使用するすべてのチームに影響が及びます。

ビルド作業は、明確なラベルを持つエージェントに移動してください:

linux && docker
linux && maven
windows && visualstudio
large-memory

ラベルはExecutor最適化の一部です。なぜなら、linux && dockerを待つジョブは、アイドル状態のWindows Executorが存在しても関係ないからです。

普遍的な公式ではなく、ワークロードタイプから始める

CPU負荷の高いビルドの場合、物理または仮想CPUコア数に近い値から始めます。C++コンパイルや大規模なJavaテストスイートを実行する8コアのビルドVMは、6〜8個のExecutorから始め、測定結果に基づいて増減させます。

I/O負荷の高いビルドの場合、ジョブがネットワークダウンロード、アーティファクトアップロード、テストサービスの待機に時間を費やすため、CPUコア数よりも多くのExecutorを実行できる場合があります。依存関係の多い8コアエージェントは、10〜12個のExecutorをうまく処理できるかもしれません。しかし、ディスクが遅いかメモリが不足している場合、6個でもパフォーマンスが低下する可能性があります。

メモリが実際の制限となることがよくあります。各ビルドが2GBのRAMを使用し、エージェントが16GBの場合、8個のExecutorではOS、Dockerデーモン、言語ランタイム、ブラウザテスト、ファイルシステムキャッシュのための余裕がなくなります。その場合、8個よりも4〜5個のExecutorの方が、マシンがスワッピングを回避できるため高速になる可能性があります。

以下のようなワークシートを使用してください:

エージェントRAM: 32 GB
OSとデーモン用に予約: 4 GB
ビルドに使用可能: 28 GB
一般的なビルドのピーク: 3 GB
開始Executor数: 8または9、その後負荷をかけて検証

数値は完璧である必要はありません。実際のビルドを観察した後に調整できるよう、明確にしておく必要があります。

キューの理由を監視する

Jenkinsのビルドキューは、作業がなぜ待機しているかを教えてくれます。「次の使用可能なExecutorを待機中」は「ラベルを持つノードがありません」とは異なります。前者はキャパシティの圧迫を示唆し、後者はラベルまたはエージェントプロビジョニングの問題を示唆します。

開発者がJenkinsが遅いと不満を言うときは、以下を確認してください:

  • ラベルごとのキュー長
  • 平均キュー待機時間
  • エージェントのオンライン/オフラインの変動
  • ロックされたリソースを待ってスタックしているビルド
  • 予想以上に多くのExecutorスロットを消費している並列パイプラインステージ

10個の並列ブランチを持つ単一のパイプラインは、10個のExecutorスロットを消費する可能性があります。テストマトリックスではそれがまさに必要な場合もありますが、小規模なJenkinsインストールでは他のすべてのジョブを枯渇させる可能性もあります。

使い捨てエージェントには1 Executorを使用

Kubernetesエージェントや多くのクラウド作成エージェントの場合、ポッドまたはインスタンスごとに1 Executorが通常最もクリーンなモデルです。ポッドが分離の単位です。より多くの並列処理が必要な場合は、無関係なビルドを同じ使い捨てワークスペースに詰め込む代わりに、より多くのポッドを作成します。

このモデルでは、リソースリクエストが重要になります:

resources:
  requests:
    cpu: "2"
    memory: "4Gi"
  limits:
    memory: "6Gi"

リクエストが低すぎると、Kubernetesは1つのノードに多くのJenkinsエージェントを詰め込みすぎる可能性があります。Jenkinsは使用可能なExecutorを認識しますが、クラスターノードは過負荷になります。制限が厳しすぎると、アプリケーションの問題のように見えるメモリエラーでビルドが失敗します。

静的VMエージェントの場合、複数のExecutorでも問題ありません。ただし、ワークスペースレイアウト、キャッシュディレクトリ、ツールインストールは、同時ジョブ向けに設計してください。

ノイズの多いジョブをスロットルする

一部のジョブは、Jenkinsがスケジュールできるだけのコピーを実行すべきではありません。データベース統合テスト、ブラウザテスト、負荷テスト、イメージビルドは、共有システムをすぐに飽和させる可能性があります。

ジョブレベルのスロットリング、ロック可能リソース、またはパイプライン制御を使用してください:

pipeline {
  agent { label 'linux && docker' }
  options {
    disableConcurrentBuilds()
  }
  stages {
    stage('Build Image') {
      steps {
        sh 'docker build -t app:${BUILD_NUMBER} .'
      }
    }
  }
}

共有ステージングデータベースの場合、ロックの方が明確です:

lock('staging-db') {
  sh './run-integration-tests.sh'
}

これにより1つのジョブが待機する可能性がありますが、5つのジョブが同時に失敗してExecutor時間を無駄にするのを防ぎます。

Jenkinsだけでなくエージェントも測定する

Jenkinsはキュー時間とExecutor使用率を教えてくれます。オペレーティングシステムは、Executor数が適切かどうかを教えてくれます。

Linuxエージェントでは、以下を確認してください:

uptime
mpstat 1
iostat -xz 1
free -h
df -h
docker system df

CPU使用率が高くI/O待ちが低い場合は、CPUバウンドの作業を示します。I/O待ちが高い場合は、Executorを追加するとビルドが遅くなる可能性があります。ビルド中のスワップ使用は、Executorを減らすかメモリを増やすべき強いシグナルです。ディスクがほぼ満杯の場合、チェックアウト、アーカイブ、Dockerビルドが遅くなります。

個々のビルド時間も確認してください。キュー時間が1分短縮されても、各ビルドが5分遅くなる場合、Executor数を増やすことはメリットになりません。

小さな変更で調整する

Executor数は徐々に変更してください。エージェントを4から6に変更し、数日間のビジー状態を観察してから決定します。大きなジャンプは回帰の原因を隠してしまいます。

メモを残してください:

2026-05-24: linux-build-03 Executor 4 -> 6
理由: linux && mavenのキューが平均12分
監視: CPU、iowait、Mavenキャッシュロック競合、ビルド時間
ロールバック: p95ビルド時間が予想以上に上昇した場合は4に設定

この短い記録は、2週間後に誰かがエージェントが遅い理由を尋ねたときに役立ちます。

実用的な目標

健全なJenkinsセットアップでは、ピーク期間中にほとんどのエージェントがビジー状態であり、一般的なラベルのキューが短く、スワップがなく、ビルド時間が予測可能で、コントローラービルドがありません。また、Dockerエージェントが不足しても無関係なMavenジョブが待機しないよう、ラベル固有の十分なキャパシティがあります。

Executor最適化は一度きりの設定ではありません。チームが並列ステージを追加したり、大規模なテストスイートに移行したり、Dockerビルドを採用したり、静的VMからKubernetesエージェントに移行したりするときに変化します。キュー時間が目に見えるようになったとき、エージェントがスワッピングを始めたとき、または人々が提案する最も速い修正が「Executorを増やすだけ」であるときに、見直してください。時にはそれが正しいこともあります。しかし、多くの場合、より良い修正は、新しいエージェントプール、より良いラベル、または他の全員に悪影響を与えるジョブの同時実行数を減らすことです。

並列ステージには予算が必要

パイプラインの並列処理は大きなメリットになりますが、Executorをすぐに消費します。4つのJavaバージョンと3つのオペレーティングシステムにわたるマトリックスビルドは、12のブランチを作成する可能性があります。各ブランチが別々のエージェントで実行される場合、その1つのビルドだけで、デプロイメントステージが開始される前に12個のExecutorを消費する可能性があります。

これは、チームが計画している場合は許容範囲です。単一のプルリクエストがリリースビルドを枯渇させる場合は問題です。大規模なファンアウトジョブには制限を設けてください:

options {
  parallelsAlwaysFailFast()
}

高コストのブランチを適切なプールに送るラベルを使用し、メインブランチでは完全なマトリックスを実行し、プルリクエストではより小さなマトリックスを実行することを検討してください。目標は、どこでも最大の並列処理ではなく、重要な場所での迅速なフィードバックです。

インタラクティブとバッチの期待値を分離する

すべてのJenkinsジョブが同じキューターゲットに値するわけではありません。本番ホットフィックスビルド、プルリクエスト検証ジョブ、夜間セキュリティスキャン、週次クリーンアップジョブはすべてJenkinsで実行できますが、同じように競合するべきではありません。

ラベル、クワイアット期間、スロットル、スケジュールウィンドウを使用して分離できます。負荷の高い夜間ジョブは、インタラクティブなPRトラフィックが少ないときに実行する必要があります。長時間実行される負荷テストは、専用のエージェントを持つ必要があります。リリースジョブは、予約済みキャパシティまたは通常のブランチジョブが使用できないラベルを持つ価値があるかもしれません。

これは政治というよりも信頼性の問題です。すべてのワークロードが1つのExecutorプールを共有する場合、最もノイズの多いワークロードが全員のエクスペリエンスを決定します。

ドキュメント化すべきこと

エージェントプールごとに、小さな記録を残してください:

ラベル: linux && docker
エージェントタイプ: 静的VM
エージェントあたりのExecutor数: 4
主要ワークロード: Dockerイメージビルド、統合テスト
既知の制限: ディスクI/OとDockerレイヤー増加
クリーンアップ: 夜間docker prune、ビルド後のワークスペースクリーンアップ
所有者: プラットフォームチーム

この記録により、将来の調整がはるかに容易になります。キュー時間が増加した場合、同じタイプのエージェントを追加するか、ワークロードを新しいプールに分割するか、競合を引き起こしているジョブの同時実行数を減らすかを決定できます。