ある月曜の朝、Jenkins画面を開いたら、妙に読み込みが遅かったです。
「あれ、今日はなんか重たいな」と思いながらReplayボタンを押すと、ビルドが走り始めたものの、しばらくして fatal: write error: Bad file descriptor というエラーで止まってしまいました。Gitのクローンに失敗しています。普段なら数秒で終わるはずの処理が、転送速度が77KB/s → 51KB/sとじわじわ下がっていき、最終的にタイムアウト。
504 Gateway Time-outも頻発します。ALB経由でJenkinsにアクセスしているのですが、60秒待ってもレスポンスが返ってきません。
「これは何かがおかしい」
そう思ったときから、約3時間の調査が始まりました。
最初の仮説:ネットワークか、一時的な問題か?
エラーログを見ると、Gitのクローン処理でI/Oエラーが出ています。最初に思い浮かんだのは「ネットワークの一時的な問題では?」という仮説でした。転送速度が徐々に低下していることから、接続が不安定になっているのかもしれません。
しかし、よく考えると違います。
エラーログをもう一度見直すと、pipeline-groovy-lib プラグインがShared Libraryを取得中に失敗しています。これはController側で実行される処理です。Jenkins全体が重いということは、Controller側のリソースが圧迫されている可能性が高いです。
「なるほど、Controller側の問題かもしれない」
ここで方向転換しました。CloudWatchのメトリクスを確認することにしました。
CloudWatchメトリクスを読み解く
まずはEC2インスタンスのメトリクスから確認しました。
- CPUUtilization: 通常0-5%、たまに30%のスパイクがある程度
- Network In/Out: 同様に、たまにスパイクがありますがおおむね平常

CPU、ネットワークには目立った異常はありません。
次にディスクのメトリクスを見ます。
- VolumeAvgWriteLatency(書き込みレイテンシ): 通常0.7秒程度で推移
- 01/24頃に1.4秒程度のスパイクはあるが、その後は落ち着いている
- VolumeAvgReadLatency(読み込みレイテンシ): ほぼ0秒で安定

一瞬、「01/24のスパイクが怪しい」と思いましたが、よく見ると現在は落ち着いています。これだけでは説明がつきません。
「ディスクI/Oの問題なのは間違いないが、EBSのメトリクスでは決定的な証拠が見つからない...」
EBSか、EFSか ― 見えない容疑者
ただ、ここで一つ疑問が浮かびました。
「待てよ、このJenkins、EBSじゃなくてEFS使ってるんだった」
念のためEBSのメトリクスも確認してみましたが、特に問題はなさそうでした。一方、EFSのメトリクスを開いてみると――
- スループット利用率: 00:00〜03:00頃に100%に達するスパイクが頻発
- IOPS: メタデータ操作(緑のグラフ)が支配的
- ストレージバイト数: 00:00頃から増加傾向(14GB → 17GB程度)



「これだ」
EFSがスループット制限に達しています。しかも、データの読み書きではなく、メタデータ操作でIOPSを食いつぶしています。そして、ストレージ容量も増加し続けている。
正直ここで詰まりました。
容量自体は17GB程度で、特別大きいわけではありません。にもかかわらず、スループットが100%に達するスパイクが頻発するのはなぜか。メタデータIOPSとは具体的に何を指しているのか。
メタデータIOPSとは何か
調べてみると、EFSにおける「メタデータ操作」とは以下のようなものを指すようです。
- ファイルのstat(サイズ・タイムスタンプの確認)
- ディレクトリの ls
- ファイルの作成・削除
- パーミッション変更
つまり、小さいファイルを大量に作成・削除・確認する処理がメタデータIOPSを消費します。
Jenkins環境でこれに該当するものは何でしょうか。
- ビルドログ
- ビルド成果物
- Gitリポジトリのキャッシュ
- Shared Libraryのクローン
- fingerprints(成果物の追跡データ)
これらはいずれも、多数の小さいファイルで構成されています。特にGitリポジトリは、.git/objects 配下に膨大な数のファイルを持ちます。
「なるほど、容量の問題じゃなくて、ファイル数の問題か」
容疑者を絞り込む
EFSのストレージ容量が増加傾向にあることから、「何かが蓄積されている」と考えました。
まずは /mnt/efs/jenkins の各ディレクトリのサイズを確認してみました。
du -sh /mnt/efs/jenkins/*
結果:
342M plugins
106M war
332M logs
373M caches
timeout jobs # タイムアウト
174M fingerprints
timeout config-history
jobs ディレクトリでタイムアウト。これは怪しいです。
しかし、ここで気づいたことがあります。
plugins: 342M
war: 106M
logs: 332M
caches: 373M
fingerprints: 174M
合計: 約1.3GB
残り約15.7GBが未発見
EFSの合計容量は17GB程度あるのに、確認できたのは1.3GB程度。どこかに大きなファイルやディレクトリが隠れています。
応急処置:プロビジョンドスループットの設定
調査が長引きそうだったので、ここで一旦判断をしました。
「調査中もJenkinsは動かし続けたい。EFSのスループットを上げておくのが最適だろう」
EFSには以下の2つのスループットモードがあります:
- バースト: ストレージ容量に応じてクレジットを使い切ると性能低下
- プロビジョンド: 固定のスループット値を設定
- Elastic throughput: 需要に応じて自動スケール、使った分だけ課金
当時の設定はバーストモードでしたが、これをプロビジョンドスループット300 MiB/sに変更することにしました。
ただし、EFSのスループットモード変更には制限があり、すぐには設定できないことがわかりました。翌日に設定変更することにしました。
なぜプロビジョンドスループットを選んだか。
- 安定した性能 → メタデータIOPSのスパイクに対して予測可能な性能
- 調査中も安心 → findやduを実行してもスループット保証
- 即効性 → バーストモードのクレジット回復を待つ必要がない
この判断が正しかったかどうかは、翌日の設定変更後に確認することになります。
ただし、これはあくまで応急処置です。根本原因は解決していません。
真犯人の発見:Git一時ファイルの残留
さらに調査を続けました。
大きなファイルを直接探してみることにしました。
find /mnt/efs/jenkins -type f -size +100M 2>/dev/null -ls
すると――
125829120 Jan 27 01:50 /mnt/efs/jenkins/jobs/Seed_Jobs/jobs/0_Seed_Job_Orchestrator/builds/873/libs/.../root/.git/objects/pack/tmp_pack_S3GPJw
122683392 Jan 27 01:50 /mnt/efs/jenkins/jobs/Seed_Jobs/jobs/0_Seed_Job_Orchestrator/builds/872/libs/.../root/.git/objects/pack/tmp_pack_c4EAwd
**tmp_pack_***という一時ファイルが大量に残っていました。
各ファイル100-300MB。今日(Jan 27)のタイムスタンプが多数ありました。
「これか」
何が起きていたのか
整理すると、こういうことでした。
Pipeline Shared Libraryのチェックアウト時
- JenkinsがShared Libraryをgit cloneします
- Gitがpackファイルを作成する際に一時ファイル(tmp_pack_*)を生成します
- EFSのIOPS制限でタイムアウト
- 一時ファイルが削除されずに残ります
毎回のビルドで同じ現象
- 毎日23:12頃に実行されるビルドで発生
- 各ビルドに200-300MBのゴミが残ります
- これが数十ビルド分蓄積 = 約15GB
悪循環
EFS遅い → Git失敗 → ゴミ蓄積 → さらにEFS遅い
なるほど、だから今日急激に症状が表面化したわけです。
対処と残タスク
原因が特定できたことで、緊急度は下がりました。そこで、まずは再発防止策として定期クリーンアップジョブの作成に着手しました。
実施した対応
定期クリーンアップジョブの作成
- 1日以上経過したtmp_pack_*を自動削除するジョブをセットアップ
- 今後同じ問題が発生しないようにする仕組みを構築
残タスク
原因が判明し、再発防止策を講じたことで一旦は落ち着きましたが、以下のタスクが残っています。
一時ファイルの削除
systemctl stop jenkins find /mnt/efs/jenkins -name "tmp_pack_*" -type f -delete systemctl start jenkins- 既存の約15GBのゴミファイルをクリーンアップ
監視アラートの設定
- EFSスループット利用率が75%を超えたらアラート
- 早期発見のための仕組み
今回の調査を通じて、いくつか気づいたことがありました。
気づき1: 容量だけ見ていても見えない問題がある
「容量が少ないから問題ない」と思っていましたが、実際には小さいファイルの大量蓄積が性能劣化の原因でした。容量以上に、ファイル数・メタデータ操作の頻度が重要なんだと実感しました。
気づき2: バーストモードは予測しづらい負荷に弱い
EFSのバーストモードは、クレジットを使い切ると性能が低下します。今回のように「いつの間にか」蓄積される問題だと、いつクレジットが枯渇するか予測しにくいです。
気づき3: 調査中も運用を継続できる余地を残しておく
プロビジョンドスループットへの変更判断は、調査中もJenkinsを安定稼働させるための保険でした。「調査が長引くかもしれない」という前提で先手を打っておくことの大切さを感じました。
振り返り
最初は「ネットワークの一時的な問題だろう」と思っていました。
でも実際には、ネットワークでもディスク容量でもなく、メタデータIOPS、しかもGitの一時ファイルという予想外のところに原因がありました。
仮説を立てては検証し、違うと分かったら別の仮説に切り替える。メトリクスを読み解きながら、一歩ずつ真相に近づいていく。正直ここで詰まりましたというポイントもありましたが、最終的に原因を特定できたときは「ああ、そういうことか」とすっと理解できました。
表面的な症状(Gitクローンエラー)の奥に、より深い原因(EFSメタデータIOPS)があって、さらにその奥に真犯人(Git一時ファイルの蓄積)がいる。
一つ一つ丁寧に仮説を立てて検証していく。その積み重ねが大事なんだなと、改めて感じた調査でした。
今後の対応
今回の問題では、EFSの容量が増加していることには気づけましたが、何が根本原因かをすぐに特定できませんでした。
tmp_pack_*削除ジョブは既に作成済みですが、今後同様の問題を早期発見できるように、EFS使用量の可視化を進めていく予定です。
具体的には、定期的にディレクトリ別の使用量を監視し、レポートとして可視化することで、容量の異常な増加を早期に検知できる仕組みを構築します。これにより、問題が表面化する前に対処できるようになります。
関連書籍
今回のようなインフラ運用やトラブルシューティングについてさらに学びたい方におすすめの書籍です。
[📦 商品リンク: moshimo-book-sre-google]
[📦 商品リンク: moshimo-book-jenkins-jissen]
[📦 商品リンク: moshimo-book-aws-operations]