先に要点
- ビルドキャッシュの掃除を定期実行しているのに容量が減らない場合、そのコマンドが毎回 0B しか消していないことがあります。上限を指定する方式は、今の使用量が上限を超えていなければ何もしません。それが正しい動作です。
- 筆者が実際に測ると、上限を使用量より上に置いたときの削除量は 0B、下に置いたときは 629.2MB でした。ただし残ったのは指定した 400MB ではなく 169.5MB です。上限は目標値ではありません。
-aは「全部消す」という意味ではありません。実測では-aを付けなくてもキャッシュは全部消えました。現在のヘルプにも「内部・フロントエンドのイメージを含める」と書かれています。- そして公式ドキュメントの一部が実機と食い違っています。現在は存在しないオプションが載っているページがあります。オプションの意味は、必ず自分の版のヘルプで確認してください。
ディスクが埋まったのでビルドキャッシュを消し、再発しないように上限を決めて定期実行に入れる。よくある対応です。
問題は、その定期実行が本当に効いているかを確かめないまま「恒久策」と呼んでしまうことにあります。この種の掃除は、何も消さなくてもエラーになりません。ログには毎回「削除 0B」と残るだけです。この記事では、各オプションが実際に何をするのかを測った結果と、確かめ方をまとめます。
測った環境と結果
Docker 29.7.2(Docker Desktop)で、ユーザーの既存キャッシュに触れないよう専用のビルダーを作って実験しました。作り方は後半に書きます。約798.6MB のキャッシュを毎回同じ条件で作り直しています。
| 指定したオプション | 開始時の使用量 | 削除された量 | 残った量 |
|---|---|---|---|
--max-used-space 900MB |
798.6MB | 0B | 798.6MB |
--max-used-space 400MB |
798.6MB | 629.2MB | 169.5MB |
--filter until=24h |
798.6MB | 0B | 798.6MB |
--filter until=1s |
798.6MB | 798.6MB | 0B |
-f(-a なし) |
798.6MB | 798.6MB | 0B |
-af |
0B | 0B | 0B |
ここから読み取れることが3つあります。
上限は「目標値」ではない
1行目は、上限を現在の使用量より上に置いた場合です。削除量は 0B。使用量が上限を超えていないので、削るものがありません。これは不具合ではなく、指定どおりの動作です。
問題になるのは、この状態が何日続いても同じログしか出ないことです。「掃除は毎日動いている」「エラーも出ていない」という2つの事実だけを見ていると、上限が一度も効いていないことに気づけません。
2行目はもっと意外でした。上限を 400MB に指定したのに、残ったのは 169.5MB です。指定より 230MB ほど下回っています。
理由は、削除の単位がキャッシュの1件ずつだからです。実際に消えたのは 262.2MB と 367MB の2件で、合わせて 629.2MB。400MB に近づけるために一部だけ削る、という動きはしません。1件消しては上限を下回ったか確認し、下回った時点で止まります。
上限を「このくらい残ってほしい量」のつもりで設定すると、実際にはそれより大きく削られることがあります。逆に大きな1件が残っていると、思ったより削れないこともあります。上限は残量の保証ではなく、削除を始める引き金です。
-a は「全部消す」ではない
5行目が3つ目の発見です。-a を付けずに実行しただけで、798.6MB が全部消えました。その後に -a を付けて実行しても、追加で消えるものはありません。
現在のヘルプを読むと理由が分かります。
-a, --all Include internal/frontend images
つまり -a は内部処理やフロントエンドのイメージを対象に加えるオプションです。「ためらわずに全部消す」という意味ではありません。
これは覚え方として重要です。「-a を付けないと全部は消えない」という前提で組んだ掃除は、前提が間違っています。逆に「-a は危ないから付けない」という判断も、想定しているほどの差を生みません。
公式ドキュメントが実機と食い違っている
ここが今回いちばん実用的な発見でした。同じコマンドについて、参照するページによって説明が違います。
まず、実機で確認できること。
docker builder prune --help
出力の1行目は次のようになります。
Usage: docker buildx prune
つまり現在の docker builder prune は、実体が docker buildx prune です。そのうえで、公式ドキュメントの状態を並べると次のようになります。
| 見た場所 | --all の説明 |
載っているオプション |
|---|---|---|
| 実機のヘルプ | 内部・フロントエンドのイメージを含める | --max-used-space / --min-free-space / --reserved-space |
docker buildx prune のリファレンス |
同上 | 同上 |
docker builder prune のリファレンス |
使われていないビルドキャッシュを全て削除する | --keep-storage |
最後の行が問題です。--keep-storage は実機のヘルプに存在しません。そして --all の説明も、実機が言っていることと違います。
コマンドの挙動を検索して調べると、上位に出るのが古い方のページであることがあります。オプションの意味を判断の根拠にするなら、自分が使っている版のヘルプを読むのが最短で確実です。ドキュメントの記述と食い違ったときは、実機のヘルプを優先してください。
自分の環境で安全に試す
この手の検証で困るのは、試すこと自体が手元のキャッシュを消してしまう点です。実験のために普段の開発が遅くなるのは避けたいところです。
解決策として、専用のビルダーを作れば、既存のキャッシュから完全に隔離して試せます。今回の測定もこの方法で行い、実験の前後で既存のキャッシュは変化していないことを確認しています。
# 専用のビルダーを作る(既存のキャッシュとは別物になる)
docker buildx create --name prunetest --driver docker-container --bootstrap
# 以後、すべての操作に --builder prunetest を付ける
docker buildx build --builder prunetest -f Dockerfile .
docker buildx du --builder prunetest
docker buildx prune --builder prunetest -f --max-used-space 400MB
# 終わったら片付ける
docker buildx rm prunetest
失うもの・戻し方を先に確認しておきます。専用ビルダーを消して失うのは、そのビルダーで作ったキャッシュだけです。既存のビルダー、イメージ、コンテナには影響しません。もう一度作れば同じ状態から始められます。逆に --builder を付け忘れると普段のキャッシュが対象になるので、そこだけ注意してください。
使用量の内訳を見る
削除の判断が何を基準にしているかを確かめるには、内訳を見ます。
docker buildx du --verbose
1件ごとに、識別子、削除できるか、共有されているか、サイズ、説明が並びます。最後に合計が出ます。
この「共有されているか」は、複数の場所から参照されているキャッシュを表します。ここが大きい環境では、上限指定が期待どおりに働くかどうかを別途確かめた方がよいと考えています。今回の測定環境では共有分が実質ゼロだったため、共有分が多いときの挙動までは確認できていません。確認できていないことは、確認できていないと書いておきます。
自分の環境で確かめるなら、手順は同じです。専用ビルダーで内訳を作ってから上限を指定し、削除量が合計と内訳のどちらを基準に決まったかを見ます。
「恒久策」と呼ぶ前に測る
ここまでの内容は、結局1つのことに集約されます。掃除を入れたら、効いていることを測る。
具体的には次の3つで足ります。
- 削除量をログに残す。出力を捨てずに記録します
- 翌日にそのログを1回だけ見る。0B が並んでいたら、上限が一度も効いていません
- 使用量を定期的に記録する。掃除の後で頭打ちになっているかを見ます
3番目が本命です。削除量が 0B でも問題ない場合はあります。使用量がそもそも上限に届いていないだけだからです。本当に見たいのは「使用量が頭打ちになっているか」であって、削除量そのものではありません。
エラーが出ないものほど危ない
掃除、通知、同期のように「やらなくてもエラーにならない」処理は、止まっていても気づけません。動いた証拠ではなく、効果が出た証拠を記録します。
設定した日に確認は終わらない
設定した直後は条件が整っていないことが多く、その場では判断できません。翌日か翌週にもう一度見る予定まで含めて、はじめて対策になります。
時間で絞る方が事故が小さい
直近のキャッシュを残したいなら、上限ではなく古さで絞る方が結果を予測しやすくなります。残る量は読めませんが、残るものの性質は決められます。
よくある質問
削除量が 0B なのは異常ですか
異常とは限りません。使用量が上限に届いていなければ 0B が正しい動作です。判断材料になるのは使用量の推移の方で、使用量が増え続けているのに 0B が並んでいるなら、上限が実態に対して高すぎます。
上限と時間での絞り込みはどちらがよいですか
残したいものが決まっているなら時間での絞り込みが向いています。直近のビルドが速いままになるためです。上限は、ディスクの空きを一定に保ちたい場合に向きます。両方を同時に指定すると、時間の条件を満たしたものの中から上限に達するまで削るという動きになるので、組み合わせても構いません。
キャッシュを全部消すと何が起きますか
次のビルドが遅くなります。壊れるものはありません。依存の取得やコンパイルをやり直すぶんだけ時間が延びるので、影響は「時間」だけだと考えて差し支えありません。ただし外部から取得する処理が含まれる場合は、ネットワークの状態に左右されます。急いでいるときに全部消すのは避けた方が無難です。
常駐の設定で上限を決める方法もありますか
あります。ただしコマンドで指定する場合と同じ判定になる前提で考えてください。コマンド側で期待どおりに動かなかった指定が、常駐の設定に移しただけで動くようになるとは限りません。どちらで設定するにせよ、効いているかを測る手順は変わりません。
まとめ
ビルドキャッシュの掃除は、何も消さなくても成功として終わります。だから入れただけでは対策になりません。
- 上限を現在の使用量より上に置けば、削除量は 0B。これは正しい動作
- 上限は目標値ではない。実測では 400MB 指定で 169.5MB まで落ちた
-aは「全部消す」ではなく「内部・フロントエンドのイメージを含める」。実測では-aなしで全部消えた- 公式ドキュメントの一部が実機と食い違っている。存在しないオプションが載っているページがある。判断は自分の版のヘルプで
- 試すときは専用のビルダーを作れば、普段のキャッシュを壊さずに測れる
そして最後に1つ。効いていることを測るまで、それは恒久策ではありません。設定した日ではなく、翌日にもう一度見る。それだけで、この種の見落としはほぼ防げます。