Jenkinsのパフォーマンスとスケーラビリティ:最適な最適化パスの選択

Jenkinsのパフォーマンスチューニングとスケーラビリティ計画の重要な違いをマスターしましょう。個々のビルドの遅さか、インフラの容量不足か、ボトルネックを診断する方法を学びます。このガイドでは、エグゼキュータの最適化、ビルドキャッシュの活用、ワークロードの効果的な分散に関する実践的な戦略を提供し、CI/CDシステムを高速かつ成長に備えたものにします。

Jenkinsのパフォーマンスとスケーラビリティ:最適な最適化パスの選択

Jenkinsが遅いと感じたとき、最初の質問は「Jenkinsを大きくするにはどうすればいいか?」ではありません。「どのような遅さが見られるのか?」です。10分のビルドと空のキューを持つチームは、高速なビルドが50のジョブの後ろで待機しているチームとは異なる問題を抱えています。一方はパフォーマンスの改善が必要で、もう一方はより多くの使用可能な容量が必要です。多くのJenkinsの障害は、これら二つの問題が混同されることで発生します。

私はJenkinsのパフォーマンスを、単一の作業単位(チェックアウト、依存関係の復元、コンパイル、テスト、パッケージ化、アーカイブ、公開)の速度と考えています。Jenkinsのスケーラビリティは、より多くのチーム、リポジトリ、プルリクエスト、スケジュールされたジョブが同時に到着したときに、システムがその作業を継続できる能力です。通常は両方が必要ですが、同じ順序で修正するわけではありません。

基本概念の定義

しばしば混同されますが、パフォーマンスとスケーラビリティは負荷下でのシステム動作の異なる側面に対処します。間違った指標に焦点を当てると、無駄な努力と持続的なボトルネックにつながる可能性があります。

Jenkinsのパフォーマンス:速度と効率性

Jenkinsにおけるパフォーマンスは、単一のタスクまたは少数のタスクがどれだけ迅速に完了できるかに関係します。ビルド期間、ステップ実行時間、Jenkinsコントローラ(マスター)の応答性などの指標で測定されます。

  • 目標: レイテンシを削減し、既存のリソースを有効活用する。
  • 重点領域: 個々のビルドステップの最適化、ネットワークオーバーヘッドの最小化、エグゼキュータスレッドの効率的な使用の確保。

Jenkinsのスケーラビリティ:増加する負荷への対応

スケーラビリティは、リソースを追加することで増加する作業量を処理するシステムの能力を指します。スケーラブルなシステムは、同時ビルドの数、ユーザー数、またはパイプラインの複雑さが増加しても、許容可能なパフォーマンスレベルを維持します。

  • 目標: コントローラを次のボトルネックにすることなく、スループットと容量を増加させる。
  • 重点領域: 複数のエージェントへの負荷分散、堅牢なクラウドプロビジョニングの実装、分散ワークロードを管理する中央コントローラの容量管理。

パフォーマンスチューニングを優先すべき時

パフォーマンスチューニングは、リソース使用率が低い場合でも高レイテンシが観察される場合、または個々のビルドが過去の基準と比較して時間がかかりすぎる場合に、即時の最適化パスとなります。これは通常、ビルドプロセス自体の非効率性を示しています。

パフォーマンスのボトルネックの診断

Jenkins環境に十分なエグゼキュータがあるにもかかわらず、ビルドが頻繁に停止したり、予想よりもはるかに時間がかかる場合は、パフォーマンスチューニングに焦点を当ててください。一般的な症状は次のとおりです。

  • 特定のGitクローン操作が数秒ではなく数分かかる。
  • Groovyスクリプトの実行時間が予期せず急増する。
  • コントローラまたはエージェントマシンでのディスクI/Oの飽和。

実践可能なパフォーマンス戦略

  1. ビルドステップの最適化: Jenkinsfileのステージを見直す。冗長なコマンドが実行されていないか?ローカルキャッシュが依存関係の解決(例:Maven/Gradleキャッシュ)を大幅に高速化できるか?
  2. ビルドキャッシュの活用: ビルド成果物やダウンロードした依存関係を実行間でキャッシュする戦略を実装する。これにより、コストのかかるネットワーク操作や変更されていないモジュールのコンパイル時間を回避できます。
  3. エグゼキュータスレッドの最適化: エージェントあたりのエグゼキュータ数がリソース(CPU/RAM)に適切に一致していることを確認する。エグゼキュータが多すぎるとコンテキストスイッチのオーバーヘッドが発生し、パフォーマンスが低下します。

例:エグゼキュータ数の調整

8コアの単一エージェントが10のエグゼキュータで過負荷になっている場合、過度のコンテキストスイッチによりパフォーマンスが低下します。数を6に減らすと、各プロセスがより多くの専用リソースを取得できるため、平均ビルド時間が改善される可能性があります。

# Jenkinsのグローバルツール設定またはエージェント設定での設定例
Number of executors: 6  # 物理リソースに最適化

スケーラビリティを優先すべき時

スケーラビリティは、高い同時実行性によりシステムがリソース制約を受けている場合、または開発チームやパイプラインのボリュームが大幅に成長すると予想される場合に、主要な関心事になります。現在のインフラが10の同時ビルドを処理できるが、来四半期には50をサポートする必要がある場合、スケーラビリティが必要です。

スケーラビリティのボトルネックの診断

スケーラビリティに焦点を当てる必要がある症状には次のものがあります。

  • ピーク時以外でもビルドキューが長い。
  • JenkinsコントローラのCPUまたはメモリが、ビルド管理で常に100%近くになっている。
  • コントローラが空き容量を報告しているにもかかわらず、利用可能なスロットがないためにエージェントがアイドル状態になっている。

実践可能なスケーラビリティ戦略

  1. 分散ビルド(エージェントモデル): Jenkinsのスケーラビリティの基本原則は、ワークロードを中央コントローラから専用のビルドエージェントに移すことです。
    • エージェントが正しく設定され、簡単に追加または削除できることを確認します。
  2. クラウドネイティブなスケーラビリティ(動的プロビジョニング): CloudBees KubernetesプラグインEC2プラグインなどのツールを活用して、ビルドキューが増加したときにオンデマンドでエージェントを動的に起動し、アイドル時に終了します。これは最も効果的な長期的なスケーリングソリューションです。
  3. コントローラリソースの割り当て: コントローラが単にキュー、スケジューリング、レポートの管理でボトルネックになっている場合は、十分な専用CPUと十分なRAMを確保します。メモリ使用量が多いのは、実行中のジョブが多すぎるか、過去のデータ保持が多すぎることが原因であることがよくあります。

例:クラウドエージェントの設定(概念)

EC2プラグインを使用して、キュー深度が特定のしきい値に達したときに新しいEC2インスタンスを起動する方法をJenkinsに指示するテンプレートを定義し、容量が需要に一致するようにします。

// エージェント割り当てを示す簡略化されたJenkinsfileスニペット
pipeline {
    agent {
        kubernetes {
            label 'k8s-build-pod'
            inheritFrom 'default-pod-template'
        }
    }
    stages { ... }
}

相互作用:スケーラブルなシステム内のパフォーマンス

パフォーマンスの低いビルドはエグゼキュータを長時間占有し、システムの効果的なスケーリングを妨げます。

ベストプラクティス: スケーリングする前に、常にベースラインのパフォーマンス効率を目指してください。非効率なシステムをスケーリングすると、より多くの遅いマシンにお金を払うことになります。

シナリオ 主な焦点 理由
ビルドが一貫して遅い;キューが短い。 パフォーマンス ビルドプロセス自体の非効率性が遅延の原因。
ビルドキューが絶えず増加している;エージェントが最大限に使用されている。 スケーラビリティ システムに同時リクエストを処理する容量がない。
ビルド時間は許容範囲内だが、コントローラが遅い。 スケーラビリティ/コントローラの健全性 コントローラが実行ではなく、メタデータの管理とスケジューリングで過負荷になっている。

両方のパスにおけるリソース管理のベストプラクティス

効果的なリソース管理は、パフォーマンスとスケーラビリティの両方の取り組みを支えます。

  • 監視: エグゼキュータの使用率、キュー時間、コントローラのJVMヒープ使用量を追跡するために、堅牢な監視(例:Prometheus/Grafana)を実装します。適切なデータは、より多くのエグゼキュータ(スケーラビリティ)が必要か、より高速なビルド(パフォーマンス)が必要かを示します。
  • ガベージコレクション: JenkinsコントローラのJava仮想マシン(JVM)設定を定期的に確認し、調整します。過度のガベージコレクションポーズは、知覚されるパフォーマンスを著しく低下させます。
  • パイプラインのクリーンアップ: 古いビルド成果物とログを積極的にクリーンアップします。過度のディスク使用はI/O操作を遅くし、すべてのビルドのパフォーマンスに影響を与えます。

実践的なトリアージの手順

単一の遅いジョブから始めて、キュー時間、エグゼキュータ時間、ビルド後時間の3つの数値を書き留めてください。キュー時間は、エグゼキュータがジョブを取得するまでの待機時間です。エグゼキュータ時間は、実際のパイプラインが実行された時間です。ビルド後時間は、メインステージが終了した後に行われるクリーンアップ、アーカイブ、レポート公開、通知作業です。Jenkinsはこれらの一部をビルドページとステージビューで公開しますが、明確な状況を把握するには、ログ、Pipeline Stage Viewプラグイン、Blue Ocean履歴、または外部メトリクスが必要になる場合があります。

キュー時間がほぼゼロでエグゼキュータ時間が長い場合は、まだエージェントを追加しないでください。Jenkinsfileを開き、繰り返されるセットアップ作業を探してください。実行のたびにMavenワールド全体をダウンロードするJavaサービスは、Jenkinsの容量問題ではありません。コールドキャッシュからすべてのブランチに対してnpm installを実行するNode.jsプロジェクトは、別のコントローラでは修正されません。依存関係レイヤーを無効にするCOPY . .が依存関係インストールの前に発生するDockerビルドは、ビルド設計の問題です。これらを最初に修正してください。

キュー時間が長く、エグゼキュータ時間が妥当な場合は、ラベルごとにエグゼキュータの可用性を確認してください。これは、Jenkinsの容量が実際には1つのグローバルプールではないため重要です。多くのアイドル状態のLinuxエージェントがある一方で、windows-signingラベルには1つのビジーマシンしかない場合があります。多数の汎用エグゼキュータがある一方で、すべてのデプロイジョブが同じロックされた環境を待っている場合があります。有用な質問は「エグゼキュータはいくつあるか?」ではなく、「このキューに入れられた作業に対して互換性のあるエグゼキュータはいくつ存在するか?」です。

キュー時間とエグゼキュータ時間の両方が長い場合は、最もボリュームの多いジョブのパフォーマンスを最初に処理してください。1日200回実行され、実行ごとに4分を無駄にするパイプラインは、週1回のリリースジョブが20分を無駄にするよりもはるかに多くの容量を消費します。最も声の大きいチームではなく、総エグゼキュータ時間でジョブを並べ替えてください。

間違った問題を解決している兆候

よくある間違いは、過負荷のエージェントにエグゼキュータを追加することです。これにより、キューが縮小するためダッシュボードが数分間は良く見えるかもしれませんが、多くの場合、すべてのビルドが遅くなります。4コアのマシンでの4つのCPU負荷の高いテストジョブは問題ないかもしれません。同じマシンでの8つのCPU負荷の高いテストジョブは、CPU、メモリ、ディスクをめぐる競合に多くの時間を費やし、有用な作業を行う時間が減る可能性があります。エグゼキュータ数を増やす前に、ロードアベレージ、仮想マシンのCPUスティール時間、ディスク待機、スワップアクティビティを監視してください。

もう1つの間違いは、起動コストを確認せずにすべてをKubernetesエージェントに移行することです。エフェメラルエージェントは、ビルドがバースト的で分離が重要な場合に優れています。すべてのビルドが大きなイメージのプル、ツールのインストール、依存関係キャッシュのウォームアップに数分を費やす場合、それほど快適ではありません。その場合は、プリビルドされたエージェントイメージ、ローカルレジストリ、ノードレベルのイメージキャッシュ、または最もビジーなラベル用の少数のウォームエージェントプールが必要になる場合があります。

コントローラのチューニングも誤解されます。Jenkins UIが遅いからといって、必ずしもコントローラにより大きなヒープが必要とは限りません。大きなビルド履歴の読み込み、大きなテストレポートのレンダリング、多くのジョブのインデックス作成、または高価なプラグインの処理でビジー状態になっている可能性があります。ガベージコレクションが問題であれば、より多くのメモリが役立つ可能性がありますが、コントローラで重い作業を行うプラグインや、誰も使用しない何千ものブランチを作成するジョブレイアウトを修正することはできません。

作業の順序付け方

小規模なJenkinsインスタンスの場合、エグゼキュータ時間で上位10のジョブから始めます。それぞれについて、不要なチェックアウトを削除し、エージェントに依存関係をキャッシュし、テスト選択をより意図的にし、可能な場合は高価なレポート生成をコントローラから移動します。また、すべてのジョブが本当に同じ大きな成果物を永久にアーカイブする必要があるかどうかを確認します。成果物の保持はめったに華やかではありませんが、ディスク、バックアップ時間、UIの応答性、復元時間に影響します。

成長するチームの場合、実際のワークロードニーズに基づいてラベルを定義します:linux-smalllinux-dockerwindowsmacosgpudeploy、または環境に一致するもの。ラベルは制約を記述する必要があり、チーム名ではありません。チームラベルは、遊休容量を生み出す傾向があります。ワークロードラベルを使用すると、エージェントを安全に共有しやすくなります。

大規模な組織の場合、コントローラの健全性をビルド容量から分離します。コントローラは、調整、構成の保存、UIの提供、作業のスケジューリングを行う必要があります。非常に具体的な理由がない限り、アプリケーションのコンパイル、ブラウザテストの実行、Dockerイメージのビルド、大きなレポートの処理を行うべきではありません。たとえその理由があっても、一時的なものであるべきです。

次のステップは動的プロビジョニングです。Kubernetes、EC2、およびその他のクラウドベースのエージェントは、明確なテンプレートを定義し、最大同時実行数を制限し、起動レイテンシを測定する場合にうまく機能します。制限がないと、壊れたジョブが非常に高価なエージェントの嵐を引き起こす可能性があります。起動メトリクスがないと、チームは遅延のほとんどがイメージプル時間である場合に、Jenkinsが遅いビルドの原因だと非難する可能性があります。

変更後に測定すべきこと

1回のラッキーなビルドで最適化を判断しないでください。変更の前後の通常の営業日を比較してください。ビルド期間の中央値、遅いパーセンタイルのビルド期間、ラベル別のキュー時間、エグゼキュータ使用率、失敗したエージェント起動、コントローラのヒープ使用量、ガベージコレクションポーズ、ディスク使用量、成果物の増加を確認してください。単一の数値よりも傾向が重要です。

便利なパターンの1つは、毎週のJenkins容量レビューを作成することです。短くしてください。最もキューが多いラベル、最もエグゼキュータ時間が多いジョブ、最も遅い共通ステージ、およびコントローラの健全性警告を持ち寄ってください。これにより、証拠に基づいて次の変更を選択する方法が得られます。また、Jenkinsのチューニングが、CIシステムがすでに苦痛になった後の年に一度のパニックになるのを防ぎます。

すぐに効果が現れることが多い小さな修正

浅いGitクローンは、ジョブが現在のリビジョンだけを必要とする場合に役立ちますが、普遍的な勝利ではありません。一部のリリースツールはタグまたは履歴を必要とします。浅いクローンが適切な場所で使用し、適切でない場合は例外を文書化してください。

依存関係キャッシュは強力ですが、共有の書き込み可能なキャッシュは破損したり、デバッグが難しいジョブ間の動作を引き起こしたりする可能性があります。ほとんどの言語パッケージマネージャーにはエージェントごとのキャッシュを優先するか、Nexus、Artifactory、パッケージレジストリなどの専用の成果物リポジトリを共有の信頼できる情報源として使用してください。

並列ステージはウォールクロック時間を短縮できますが、エグゼキュータとマシンの負荷を増加させます。テストステージが6つの並列ブランチに分割されている場合、エージェントまたはエージェントプールがスワッピングやディスクI/Oの圧迫なしに実際に6つのブランチを実行できることを確認してください。そうしないと、パイプラインはより洗練されているように見えても、同じ時間またはそれ以降に終了する可能性があります。

ワークスペースのクリーンアップは意図的に行う必要があります。すべてのビルドの前にすべてのワークスペースをクリーンアップすると再現性が向上しますが、キャッシュの利点が損なわれる可能性があります。ワークスペースを決してクリーンアップしないと、セットアップ時間は節約できますが、最終的にはディスクの圧迫と奇妙なビルド汚染が発生します。実用的な妥協案は、失敗したビルドまたは疑わしいビルドの後にクリーンアップし、明示的なキャッシュディレクトリを使用し、古いワークスペースを定期的に期限切れにすることです。

より良い経験則

エグゼキュータが利用可能な状態でビルドが遅い場合は、パイプラインをチューニングしてください。ビルドは高速だがキューで待機する時間が長い場合は、キューに入れられたラベルが必要とする場所に容量を追加してください。UI、キュー処理、またはジョブインデックス作成が遅い場合は、コントローラを保護してチューニングしてください。すべての遅延を同じ種類の遅延として扱うのをやめると、Jenkinsのパフォーマンス作業は容易になります。