午前2時のトラブル:df -hが99%を指したとき
深夜、電話のベルが激しく鳴り響きました。目をこすりながらシステムを確認すると、本番サーバーで500エラーが多発。SSHのレスポンスも亀のように遅くなっています。df -hコマンドを叩くと、/var/lib/dockerパーティションが99%で真っ赤に表示されていました。犯人はデータベースでもアプリケーションのログでもなく、Dockerそのものでした。
数ヶ月間CI/CDを回し続けた結果、何百もの古いイメージと「孤立した」ボリュームが、密かに150GBものディスク容量を食いつぶしていたのです。もしあなたも同じ状況に陥っているなら、安全かつプロフェッショナルな方法でシステムを「大掃除」していきましょう。
なぜDockerはこれほどまでに容量を「食う」のか?
Dockerは、明示的に削除命令を出さない限り、あらゆるものを保持しようとします。docker buildを実行するたびに新しいレイヤーが作成されます. ビルドに失敗したり、新しいバージョンに更新したりすると、古いレイヤーはdangling images(名前もタグもないイメージ)となり、幽霊のようにストレージを占拠し続けます。
また、停止したコンテナ(Exited)も状態を保持するためにスペースを消費します。最も厄介なのがボリューム(Volumes)です。コンテナを削除しても、実際のデータが含まれるボリュームは自動的には消えず、年月とともに蓄積されていきます。
ステップ1:容量を占有している「犯人」を特定する
闇雲に削除してはいけません。まずはDockerがどれだけの計算リソースを使用しているか、以下のコマンドで確認しましょう:
docker system df
以前、私が対応したサーバーでの実際の出力結果です:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 5 12.5GB 10.2GB (81%)
Containers 15 2 1.2GB 1.1GB (91%)
Local Volumes 40 10 25GB 15GB (60%)
Build Cache 102 0 5.4GB 5.4GB
RECLAIMABLEの列に注目してください。ここが「取り戻せる」容量です。この例では、30GB以上のゴミを即座に解放できることがわかります。
ステップ2:停止したコンテナを一掃する
テスト用にコンテナを動かしてそのまま放置してしまうことがよくあります。これらのコンテナは動いていなくてもディスクを消費します。アクティブでないすべてのコンテナを削除するには、以下を使用します:
docker container prune
慎重を期すなら、一時停止中のタスクに影響を与えないよう、24時間以上前に停止したコンテナのみを削除するようにフィルタリングします:
docker container prune --filter "until=24h"
ステップ3:不要なDockerイメージを処理する
イメージは通常、最もディスクを消費する要素です。Docker Imageの最適化を考える上で、2つのタイプを区別する必要があります:
- Dangling images: タグのないイメージ。古いバージョンに上書きビルドした際に発生します。
- Unused images: タグはあるが、どのコンテナからも参照されていないイメージ。
danglingイメージを素早く削除するには:
docker image prune
すべての未使用イメージ(pullしただけでrunしていないものも含む)を掃除するには、-aフラグを使います。本番環境での私の経験上、安全のために常に時間フィルタを併用することをお勧めします:
docker image prune -a --filter "until=72h"
ステップ4:「ブラックホール」化したボリュームを解決する
ボリュームにはデータベースやアップロードファイルなどの重要なデータが含まれています。Dockerは非常に慎重なため、ボリュームを自動的に削除することはありません。どのコンテナにも紐付いていないボリュームはdangling volumesと呼ばれます。
削除を決定する前に、孤立したボリュームのリストを確認しましょう:
docker volume ls -f dangling=true
そのデータに価値がないと確信できたら、クリーンアップを実行します:
docker volume prune
警告:実行前に必ずデータのバックアップを取ってください。データベースのボリュームを誤って削除すると、取り返しのつかない惨事になります。
最終兵器:Docker System Prune
すべてを一発で綺麗にしたいですか? Dockerには以下の「一括削除」コマンドが用意されています:
docker system prune
このコマンドは、停止したコンテナ、未使用のネットワーク、danglingイメージをすべて削除します。ただし、デフォルトではボリュームは削除されません。ボリュームや古いイメージまで徹底的に大掃除するには、以下を使用します:
docker system prune -a --volumes
ステージング環境では、私は毎週このコマンドを実行しています。わずか5秒でディスク容量の40%を取り戻せたこともあります。
サーバーを常に「清潔」に保つための運用ルール
サーバーが赤信号を出してから掃除を始めるのはやめましょう。以下の4つの黄金律を適用してください:
--rmフラグを活用する: テストやデバッグのために一時的にコンテナを実行するときは、終了時に自動削除されるよう--rmを付けます。docker run --rm alpine echo "自動クリーンアップ"- CI/CDに組み込む: デプロイスクリプトの最後に
docker image pruneステップを追加し、新しいバージョンが稼働した直後に古いイメージを削除します。 - ログローテーションの設定: Dockerのログは数十GBに膨れ上がることがあります。
/etc/docker/daemon.jsonでログサイズを制限しましょう:"log-driver": "json-file", "log-opts": {"max-size": "10m", "max-file": "3"} - Cronjobの設定: 稼働率に極端に厳しくないサーバーであれば、週末に定期的に
docker system pruneを実行するように設定します。
これらの実践的な経験が、皆さんのDocker管理の効率化に役立つことを願っています。ディスクフルによるアラートに叩き起こされることなく、安眠できることを祈っています!
