自宅サーバーの空き容量をDockerに食われた:どこが太っているか調べて安全に消す手順

Photo: Marta Branco / Pexels
先に結論です。Docker がディスクを食っているときは、docker system df で種類ごとの量を見てから、「消しても作り直せるもの」から順に消すのが安全です。順番は、ビルドキャッシュ → 使っていないイメージ → 停止中のコンテナ → ログ。ボリュームは中身を確かめてから最後に1つずつ消します。/var/lib/docker の中のファイルを rm で直接消すのはやめておきます。
再発を防ぐには、コンテナログに上限を付けるのが効きます。Docker の既定のログ(json-file)はローテーションされないため、ログを多く出すコンテナがあるとディスクを使い切る原因になると公式ドキュメントでも説明されています。
まずどこが太っているかを調べる
最初に df -h で、どのパーティションが埋まっているかを見ます。Docker のデータは既定で /var/lib/docker に置かれるので、多くの場合はルート(/)が埋まっています。続いて、Docker の中身を種類ごとに確認します。
docker system df
Images(イメージ)、Containers(コンテナ)、Local Volumes(ボリューム)、Build Cache(ビルドキャッシュ)ごとに、SIZE(使用量)と RECLAIMABLE(使われていないので消せる見込みの量)が出ます。RECLAIMABLE が大きい行から片付けるのが近道です。
内訳は docker system df -v で、イメージ・コンテナ・ボリュームごとに見られます。イメージの SIZE はほかのイメージと共有している部分(SHARED SIZE)を含むので、足し上げると実際の使用量より大きくなる点に注意してください。
ただし、docker system df にはコンテナのログが出てきません。ログも含めて見るなら du を使います。
sudo du -h -d1 /var/lib/docker | sort -h
sudo du -sh /var/lib/containerd
containers が大きければログ、volumes が大きければボリュームのデータ、overlay2 や buildkit が大きければイメージやビルドキャッシュが原因です。
なお、Docker Engine 29 以降を新しく入れた環境では、イメージの保存先が containerd image store になるのが既定で、イメージは /var/lib/containerd 側に置かれるとされています。どちらかは docker info -f '{{ .DriverStatus }}' で確認でき、io.containerd.snapshotter.v1 と出れば containerd 側です。どちらでも、消すときは Docker のコマンドを使う点は変わりません。
消しても作り直せるものから消す
次の3つは、消しても困ることがほとんどありません。
docker builder prune # 使われていないビルドキャッシュ
docker image prune # タグの外れた古いイメージ
docker container prune # 停止しているコンテナ
docker compose pull でイメージを更新すると、古いイメージはタグが外れた状態(dangling)で残ります。更新を繰り返している自宅サーバーでは、ここがかなりの量になっていることがあります。
もう一歩進めるなら docker image prune -a です。どのコンテナにも使われていないイメージをすべて消します。Docker Hub などから取ってきたイメージは次の起動時に取り直せますが、自分でビルドしただけのイメージや、配布が終わったイメージは戻せないので、docker system df -v で一覧を見てから実行します。
docker container prune にも注意点があります。一時的に止めているサービスのコンテナも消えます。Compose で管理しているなら docker compose up -d で作り直せますが、docker run で手作業で作ったコンテナは、起動オプションを控えていないと再現できません。
これらをまとめて実行するのが docker system prune です。停止中のコンテナ、使われていないネットワーク、タグの外れたイメージ、使われていないビルドキャッシュを消し、-a を付けると使われていないイメージも対象になります。確認のメッセージに何が消えるかが出るので、読んでから y を押します。
ログが原因なら:切り詰めて上限を設定する
containers が大きかった場合は、どのコンテナのログかを探します。
sudo sh -c 'du -h /var/lib/docker/containers/*/*-json.log' | sort -h | tail -5
ファイル名の先頭がコンテナ ID です。急いで空きを作るなら、ログの中身を空にするやり方が一般的に使われています。
sudo truncate -s 0 "$(docker inspect -f '{{.LogPath}}' コンテナ名)"
そのコンテナの過去のログは消えます。ファイルを rm で消すと、Docker が開いたままのため容量がすぐには戻らないことがあるので、truncate を使います。
再発防止は /etc/docker/daemon.json で行います。公式ドキュメントでは、既定でローテーションする local ドライバーが勧められています。既定では1ファイル 20MB を5世代までで、コンテナあたり約 100MB に収まります。
{
"log-driver": "local"
}
json-file のまま使いたいなら、"log-opts": {"max-size": "10m", "max-file": "3"} を足す方法もあります。すでに daemon.json がある場合は、上書きせずに項目を追記してください。
設定後は sudo systemctl restart docker で反映します。このときコンテナも一度止まるので、家族が使っていない時間に行います。また、既存のコンテナは新しい設定を自動では使いません。docker compose up -d --force-recreate で作り直し、docker inspect -f '{{.HostConfig.LogConfig.Type}}' コンテナ名 で local になったかを確認します。
ボリュームは最後に、中身を確かめてから
ボリュームには、データベースや写真、パスワードの保管庫など、消したら戻らないデータが入っています。
docker volume prune と docker system prune --volumes が既定で消すのは、名前の付いていない「匿名ボリューム」のうち使われていないものだけです。名前付きボリュームは docker volume prune -a を付けたときに消えます。危ないのは、docker compose down でコンテナを消した直後です。その間はボリュームが「どのコンテナにも使われていない」扱いになり、-a を付けると消えてしまいます。
消すときは、1つずつ確かめます。
docker volume ls -f dangling=true # どのコンテナにも使われていないボリューム
sudo ls /var/lib/docker/volumes/ボリューム名/_data # 中身を確認
docker volume rm ボリューム名
使っていないサービスのものだと確信できたものだけを消し、迷うものは残します。
それでも足りないなら、ディスク自体を増やす段階です。ミニPCならシステム用の NVMe SSD を大きいものに換えるか、空いているスロットに増設して Docker のデータを移します。daemon.json の data-root で保存先を変えられますが、containerd image store を使っている場合、イメージは data-root の対象外とされているので、移す前に確認しておきます。
まとめ
- まず
docker system dfとduで、イメージ・ビルドキャッシュ・ログ・ボリュームのどれが太っているかを見る - 消すのはビルドキャッシュ → 使っていないイメージ → 停止中のコンテナの順。
-a付きは一覧を見てから - ログが原因なら
truncateで空にし、daemon.json でlocalドライバーにしてコンテナを作り直す - ボリュームは最後。
docker compose downの直後にprune -aをしない /var/lib/dockerの中をrmで直接消さない
私は、自宅サーバーで Docker を使うなら、最初にログの上限を設定しておき、月に1回 docker system df を見る習慣をつけておくのが、一番手間の少ない対策だと考えています。
運営者が作った Excel テンプレートを BOOTH で配布しています。IT 資産管理台帳(無料 Lite 版あり) / IT 資格の学習管理シート


