こんにちは!日々のCI/CDパイプラインの管理、本当にお疲れ様です。
「またあのビルドが遅い……。でも、どのステージがボトルネックなのか、コンソールログを延々とスクロールしてもよく分からない」
そんな絶望感を味わったことはありませんか?数千行もあるJenkinsのログと睨めっこして、「ああ、ここでモジュール解決に時間がかかっているのか、それともテスト並列化のオーバーヘッドなのか?」と頭を悩ませる時間は、エンジニアの創造的なエネルギーをごっそり奪っていきますよね。
今回は、そんなJenkinsのブラックボックスを綺麗に解き明かし、「どのステップで何秒溶かしているか」を秒速で可視化する秘技をお伝えします。
ツールとして登場するのは、次世代の観測性(Observability)の標準であるOpenTelemetry(OTel)です。これを取り入れるだけで、あなたのJenkinsはただの「ジョブ実行マシーン」から、「内部の挙動がすべて透けて見えるガラス張りの高速エンジン」へと生まれ変わります。
これをマスターすれば、毎日のビルド待ちのイライラから解放され、チーム全体の開発体験(DX)が劇的に楽になりますよ。さあ、一緒に扉を開けていきましょう!
—
1. そもそも「OpenTelemetry (OTel)」ってなに?
初心者の方に向けて、まず基本のキからお話ししますね。
OpenTelemetry(通称OTel)とは、システムから「メトリック」「ログ」「トレース(分散トレーシング)」という3種の神器(テレメトリーデータ)を収集し、標準化されたフォーマットで外部に送信するためのオープンソースのフレームワークです。
中でも今回の主役は「分散トレース(Distributed Tracing)」です。
分散トレースは、一つのリクエストや処理が、システムの内部をどのように旅して完了したのかを「一本のタイムライン(ガントチャートのようなもの)」として可視化してくれます。
これをJenkinsに適用するとどうなるか?
- 「Jenkins全体のビルド時間: 15分」という大雑把な数字ではなく、
- 「Gitチェックアウトに30秒 → Mavenの依存関係解決に5分 → 単体テストに8分 → Dockerイメージのビルドに1分30秒」
というふうに、「どこがボトルネックの犯人か」を一目で特定できるようになるのです。
—
2. 全体像の把握:どうやってデータを集めるのか?
今回は、以下のアーキテクチャで構築を進めます。
1. Jenkins(Javaアプリケーション):
Jenkins自体はJavaで動いています。ここに「OpenTelemetry Javaエージェント」をアタッチします。
2. OpenTelemetry Collector:
Jenkinsから送られてきたトレースデータを受け取り、必要に応じて加工してバックエンドにルーティングする中継サーバーです。
3. バックエンド(Jaeger または Grafana Tempo):
送られてきたデータを蓄積し、美しいWeb UIでタイムライン(トレース)として表示してくれます。今回は軽量に試せる Jaeger を例に進めましょう。
—
3. 実践セットアップ:一歩ずつ進める環境構築
それでは、実際に手を動かしていきましょう。今回は最も手軽で確実なDocker環境をベースに進めます。
ステップ 1: Jaeger(可視化バックエンド)の起動
まずは、トレースを受け取って画面に表示してくれるJaegerを立ち上げます。以下の `docker-compose.yml` を用意してください。
version: ‘3.8’
services:
# トレースを可視化するUIバックエンド (Jaeger)
jaeger:
image: jaegertracing/all-in-one:1.53
container_name: jaeger
ports:
- “16686:16686” # Jaeger UIのポート
- “4317:4317” # OTLP gRPCレシーバー
- “4318:4318” # OTLP HTTPレシーバー
# Jenkins (OpenTelemetryエージェントを組み込む)
jenkins:
image: jenkins/jenkins:lts-jdk17
container_name: jenkins
ports:
- “8080:8080”
- “50000:50000”
volumes:
- jenkins_home:/var/jenkins_home
environment:
# JavaエージェントにOpenTelemetryの設定を流し込む環境変数
- JAVA_OPTS=-javaagent:/var/jenkins_home/opentelemetry-javaagent.jar \
-Dotel.service.name=jenkins-ci \
-Dotel.exporter.otlp.endpoint=http://jaeger:4317 \
-Dotel.metrics.exporter=none
links:
- jaeger
volumes:
jenkins_home:
おっと、まだ肝心の `opentelemetry-javaagent.jar` が用意できていませんね。これについては次のステップでダウンロードします。
ステップ 2: OpenTelemetry Javaエージェントの配置
Jenkinsのコンテナが起動する際、あるいは起動後に、JavaエージェントをJenkinsのホームディレクトリに配置する必要があります。
コンテナを立ち上げる前にダウンロードしておくのがスマートです。ターミナルで以下を実行し、ファイルを手に入れておきましょう。
作業ディレクトリを作成
mkdir -p ./jenkins_home
最新のOpenTelemetry Javaエージェントをダウンロード
curl -L -o ./jenkins_home/opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
これで準備は整いました! `docker-compose up -d` でJenkinsとJaegerを起動しましょう。
—
4. 精度高い「Hello World」:最初のトレースを飛ばしてみよう!
さあ、Jenkinsが無事に起動したら(初回起動時のパスワード解除などは通常通り行ってください)、実際にジョブを実行してトレースがJaegerに飛ぶか確認してみましょう。
1. ブラウザで `http://localhost:8080` にアクセスし、Jenkinsにログインします。
2. 「新規ジョブ作成」から、適当なフリースタイル・プロジェクト、またはパイプラインジョブ(例: `otel-test-job`)を作成します。
3. パイプラインの場合は、以下のような簡単なスクリプトを記述して保存し、ビルドを実行してください。
pipeline {
agent any
stages {
stage(‘準備 (Checkout)’) {
steps {
echo ‘コードをチェックアウト中…’
sh ‘sleep 2’ // 意図的に2秒待つ
}
}
stage(‘ビルド (Build)’) {
steps {
echo ‘ビルドを実行中…’
sh ‘sleep 5’ // 意図的に5秒待つ
}
}
stage(‘テスト (Test)’) {
steps {
echo ‘テストを実行中…’
sh ‘sleep 3’ // 意図的に3秒待つ
}
}
}
}
「ビルド実行」ポチッとな!
数秒待つと、ジョブが無事に成功するはずです。さて、いよいよ本番。データが綺麗にトレースされているか確認しに行きましょう。
—
5. ボトルネックを暴く! Jaeger UIの読み解き方
ブラウザで `http://localhost:16686` にアクセスしてください。これがJaegerのダッシュボードです。
1. 左側のメニューにある Service プルダウンから、環境変数で指定した `jenkins-ci` を選択します。
2. Find Traces ボタンをクリックします。
するとどうでしょう!画面右側に、過去に実行したJenkinsジョブのタイムライン(トレース)がズラリと並んでいるはずです。一番上の最新のトレースをクリックしてみてください。
画面いっぱいに美しいガントチャート(分散トレース図)が表示されます。
- 全体の実行時間が視覚的にバーで表現されています。
- バーを展開していくと、`准备 (Checkout)`、`ビルド (Build)`、`テスト (Test)` というステージ単位だけでなく、内部で実行されたシェルコマンド(`sh` ステップ)の細かい実行時間まで階層構造(スパン)として完全に記録されています。
「おや、ビルドステージのここに5秒かかっているな。次のプロジェクトではここをキャッシュしてみよう」といった改善のヒントが、この画面を見るだけで直感的に手に入ります。コンソールログを1行ずつ探す苦行とは、今日でお別れです。
—
6. スペシャリストからの現場の知見(TIPS)
最後に、この構成を実務のプロダクション環境に導入する際に知っておくべき、現場ならではの知見をいくつかシェアしておきます。
- メトリックは別ルートで送るのが吉
今回の設定では `-Dotel.metrics.exporter=none` とし、メトリック(CPU使用率やメモリなど)の送信を一旦オフにしています。プロダクション環境では、トレースはJaegerやTempoへ、メトリックはPrometheusへ、と適切な宛先にルーティング(OpenTelemetry Collectorを活用)するのがベストプラクティスです。
- 機密情報のマスキング(Sanitization)
Jenkinsのビルドパラメータや環境変数には、APIトークンやパスワードが含まれることがあります。OpenTelemetryエージェントはデフォルトで一部の機密情報をマスクしますが、カスタムスクリプト内の機密データがトレースの「Attributes(属性)」として意図せず外部のトレーシング基盤に飛ばないよう、Collector側でフィルタリングルールを挟むことを強く推奨します。
—
まとめ
いかがでしたでしょうか?
JenkinsとOpenTelemetryの統合は、一見すると難しそうに見えますが、Javaエージェントを1つ挟むだけで、これほどまでにリッチで解像度の高い観測性を手に入れることができます。
「感覚」や「ログの山」に頼ったCI/CDのチューニングは、もう終わりです。データに基づいた正確なボトルネックの特定ができるようになると、パイプラインの最適化が驚くほど楽しくなりますよ。
あなたの開発チームのビルドが、今日もストレスなく、マッハで完了することを応援しています!