一覧に戻る
    JenkinsがじわじわGitクローンできなくなっていった話 ― EFSメタデータIOPSとの闘い
    SRE
    PRこの記事には広告が含まれています

    JenkinsがじわじわGitクローンできなくなっていった話 ― EFSメタデータIOPSとの闘い

    17 分で読める

    ある月曜の朝、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使用率のグラフ - 通常0-5%で推移し、たまに30%前後のスパイクがある程度

    CPU、ネットワークには目立った異常はありません。

    次にディスクのメトリクスを見ます。

    • VolumeAvgWriteLatency(書き込みレイテンシ): 通常0.7秒程度で推移
      • 01/24頃に1.4秒程度のスパイクはあるが、その後は落ち着いている
    • VolumeAvgReadLatency(読み込みレイテンシ): ほぼ0秒で安定

    ディスク読み書きレイテンシのグラフ - 書き込みは0.7秒程度、読み込みはほぼ0秒で安定

    一瞬、「01/24のスパイクが怪しい」と思いましたが、よく見ると現在は落ち着いています。これだけでは説明がつきません。

    「ディスクI/Oの問題なのは間違いないが、EBSのメトリクスでは決定的な証拠が見つからない...」


    EBSか、EFSか ― 見えない容疑者

    ただ、ここで一つ疑問が浮かびました。

    「待てよ、このJenkins、EBSじゃなくてEFS使ってるんだった」

    念のためEBSのメトリクスも確認してみましたが、特に問題はなさそうでした。一方、EFSのメトリクスを開いてみると――

    • スループット利用率: 00:00〜03:00頃に100%に達するスパイクが頻発
    • IOPS: メタデータ操作(緑のグラフ)が支配的
    • ストレージバイト数: 00:00頃から増加傾向(14GB → 17GB程度)

    EFSスループット利用率のグラフ - 00:00〜03:00頃に100%に達するスパイクが頻発している

    EFSタイプ別IOPSのグラフ - メタデータ操作(緑)が支配的で、データ操作(青・オレンジ)は比較的少ない

    EFSストレージバイト数のグラフ - 合計(オレンジ線)が00:00頃から増加傾向

    「これだ」

    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のスループットモード変更には制限があり、すぐには設定できないことがわかりました。翌日に設定変更することにしました。

    なぜプロビジョンドスループットを選んだか。

    1. 安定した性能 → メタデータIOPSのスパイクに対して予測可能な性能
    2. 調査中も安心 → findやduを実行してもスループット保証
    3. 即効性 → バーストモードのクレジット回復を待つ必要がない

    この判断が正しかったかどうかは、翌日の設定変更後に確認することになります。

    ただし、これはあくまで応急処置です。根本原因は解決していません。


    真犯人の発見: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

    tmppack*という一時ファイルが大量に残っていました。

    各ファイル100-300MB。今日(Jan 27)のタイムスタンプが多数ありました。

    「これか」


    何が起きていたのか

    整理すると、こういうことでした。

    1. Pipeline Shared Libraryのチェックアウト時
    • JenkinsがShared Libraryをgit cloneします
    • Gitがpackファイルを作成する際に一時ファイル(tmp_pack_*)を生成します
    • EFSのIOPS制限でタイムアウト
    • 一時ファイルが削除されずに残ります
    1. 毎回のビルドで同じ現象
    • 毎日23:12頃に実行されるビルドで発生
    • 各ビルドに200-300MBのゴミが残ります
    • これが数十ビルド分蓄積 = 約15GB
    1. 悪循環
    EFS遅い → Git失敗 → ゴミ蓄積 → さらにEFS遅い

    なるほど、だから今日急激に症状が表面化したわけです。


    対処と残タスク

    原因が特定できたことで、緊急度は下がりました。そこで、まずは再発防止策として定期クリーンアップジョブの作成に着手しました。

    実施した対応

    定期クリーンアップジョブの作成

    • 1日以上経過したtmp_pack_*を自動削除するジョブをセットアップ
    • 今後同じ問題が発生しないようにする仕組みを構築

    残タスク

    原因が判明し、再発防止策を講じたことで一旦は落ち着きましたが、以下のタスクが残っています。

    1. 一時ファイルの削除
    systemctl stop jenkins
    find /mnt/efs/jenkins -name "tmp_pack_*" -type f -delete
    systemctl start jenkins
    • 既存の約15GBのゴミファイルをクリーンアップ
    1. 監視アラートの設定
    • EFSスループット利用率が75%を超えたらアラート
    • 早期発見のための仕組み

    今回の調査を通じて、いくつか気づいたことがありました。

    気づき1: 容量だけ見ていても見えない問題がある

    「容量が少ないから問題ない」と思っていましたが、実際には小さいファイルの大量蓄積が性能劣化の原因でした。容量以上に、ファイル数・メタデータ操作の頻度が重要なんだと実感しました。

    気づき2: バーストモードは予測しづらい負荷に弱い

    EFSのバーストモードは、クレジットを使い切ると性能が低下します。今回のように「いつの間にか」蓄積される問題だと、いつクレジットが枯渇するか予測しにくいです。

    気づき3: 調査中も運用を継続できる余地を残しておく

    プロビジョンドスループットへの変更判断は、調査中もJenkinsを安定稼働させるための保険でした。「調査が長引くかもしれない」という前提で先手を打っておくことの大切さを感じました。


    振り返り

    最初は「ネットワークの一時的な問題だろう」と思っていました。

    でも実際には、ネットワークでもディスク容量でもなく、メタデータIOPS、しかもGitの一時ファイルという予想外のところに原因がありました。

    仮説を立てては検証し、違うと分かったら別の仮説に切り替える。メトリクスを読み解きながら、一歩ずつ真相に近づいていく。正直ここで詰まりましたというポイントもありましたが、最終的に原因を特定できたときは「ああ、そういうことか」とすっと理解できました。

    表面的な症状(Gitクローンエラー)の奥に、より深い原因(EFSメタデータIOPS)があって、さらにその奥に真犯人(Git一時ファイルの蓄積)がいる。

    一つ一つ丁寧に仮説を立てて検証していく。その積み重ねが大事なんだなと、改めて感じた調査でした。


    今後の対応

    今回の問題では、EFSの容量が増加していることには気づけましたが、何が根本原因かをすぐに特定できませんでした。

    tmp_pack_削除ジョブは既に作成済みですが、今後同様の問題を早期発見できるように、*EFS使用量の可視化**を進めていく予定です。

    具体的には、定期的にディレクトリ別の使用量を監視し、レポートとして可視化することで、容量の異常な増加を早期に検知できる仕組みを構築します。これにより、問題が表面化する前に対処できるようになります。


    関連書籍

    今回のようなインフラ運用やトラブルシューティングについてさらに学びたい方におすすめの書籍です。

    この記事は役に立ちましたか?

    Coffee cup

    この記事が、何かの整理につながったら

    コーヒー1杯分の応援をもらえると嬉しいです。

    ※ これは応援とは別の話ですが、

    同じようなテーマを自分の文脈で整理したい場合は、 (文章だけだと詰まりやすい人向けに) 思考整理の壁打ちという形で対話の時間も取っています。

    対話の時間について