#はじめに
これも『Docker/Kubernetes 実践コンテナ開発入門』読書会で出てきたのですが、「溜まっていく不要なコンテナやイメージを全消しするコマンドってないのかな」という疑問。それに答えられるコマンドがあったのでそれに関してまとめてみます。
#pruneコマンド
以下はPrune unused Docker objectsに書かれている内容ほぼそのままですが、多少例を交えて書いてみます。
様々なDockerオブジェクトをprune(枝刈り)するということですが、 そもそも日本人はpruneという言葉にあまり馴染みがない人が多いように思います。私もその一人ですが、唯一知っている例として、
$ find . -name .git -prune -o -print
というようなのがあります。find
コマンドでたまに使われる用法ですが、「その前の条件に当てはまるものは検索対象から除外」というオプションですね。上記の例だと「名前が.gitであるものは検索対象から外し、そうでなければ(-o
)プリントアウトする(-print
)」ということで、つまりは今のディレクトリ以下の.gitディレクトリを除いた全てのファイルを表示するコマンドになります。
やや脱線しましたが、Dockerではいくつかのオブジェクトに対してprune(枝刈り)する機能が提供されています。
##イメージの断捨離
まずはイメージから。Dockerで以下のようにタグ付けしてビルドすることはよくあると思います。
$ docker build . -t myimage:latest
ただこれを繰り返すと前のビルドで作られたイメージが名無しで積まれていくことになります。docker-composeを使ってビルドした場合も、明示的にタグ付けしてなくてもイメージに自動でタグが付くので同様です。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
myimage latest 0663708e2fe9 8 seconds ago 101MB
<none> <none> 0ef42d3b2d90 48 seconds ago 85.6MB
<none> <none> 6de6344e5c7e About a minute ago 59.3MB
<none> <none> f6852a322079 5 minutes ago 20.7MB
そんな時に、docker image prune
を叩いてみると、「danglingイメージを全部消しちゃうけど良い?」という確認がでて、それにy
と答えると、最新のビルドだけ残してキレイに消してくれる!
$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:6de6344e5c7e0174e61e60850fd2b8141d45c25130a1d4721277bf50d587665b
deleted: sha256:2cd97da5bb5dffe5636663e29d8cc1a0ce466cffc0a7ccc711874e279b81a7b2
deleted: sha256:f6852a32207912f722f8f48f7a8f2e7ff19af7e0ec898b1568b4448eb88083b9
deleted: sha256:5fd80e022f1ae979431fc5ffc5c79fcd4ba17cf3599b438c9945e61aa3262f5f
deleted: sha256:0ef42d3b2d90f849ea528387cc431e102b8f4a359da4d01e1bb2f4fe376e8226
deleted: sha256:fd285edd6b4ad162dce41bd15d0127c0cf52dada43af4631776b7e515cabde96
Total reclaimed space: 152.3MB
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
myimage latest 0663708e2fe9 41 minutes ago 101MB
"dangling"というのは「ぶらぶらしている、宙ぶらりんな」という意味ですが、ここでは
- タグ付けされていない、かつ
- 現存しているコンテナから参照されていない(動いているか止まっているかは不問)
という条件を満たすもので、要するに消しちゃっても影響なさそうなイメージを自動的に消してくれるというスグレモノです。ちなみに、どのイメージが消されちゃうかを事前に知りたければ以下のコマンドで確認できます。
$ docker image ls --filter dangling=true
そして、docker image prune
にはオプションがいくつかあります。
#####-a
-all
タグが付いていてもコンテナから使われていないイメージは全て消去します。なので、可動しているコンテナがない状態だと全てのイメージが消えちゃいます。
#####-f
--force
実行時に「消しちゃうけど大丈夫?」という確認をスキップするためのオプションです。
#####--filter
消去するイメージを選択する追加の条件を指定できます。
指定には2つあります。一つはuntil
で、絶対時間で「この時刻よりも前のもの」あるいは相対時間で「何秒・何分・何時間前のもの」という指定ができます。例えば以下のような形になります。
$ docker image prune --filter until=2019-01-25 # 2019年1月25日以前に作成されたイメージを消す
$ docker image prune --filter until=10m # 10分以上前に作成されたイメージを消す
もう一つはラベルを指定するやり方で、各々のイメージを作成時にDockerfileの中でLABELコマンドで付加したラベルを検索条件とします。例えば、
$ docker image prune --filter label=maintainer # "maintainer"ラベルが設定されているイメージを消去
$ docker image prune --filter label=maintainer=maint@example.com # "maintainer"ラベルがmaint@example.comに設定されているイメージを消去
更に、ラベル指定の場合はlabel
の後ろに!
をつけることにより、「条件に当てはまらないイメージを消去」という指定もできます。
$ docker image prune --filter label!=maintainer # "maintainer"ラベルが設定されていないイメージを消去
$ docker image prune --filter label!=maintainer=maint@example.com # "maintainer"ラベルがmaint@example.comに設定されていないイメージを消去
なおこのfilterオプションでは、どのファイルが消去の対象になるのかの事前確認ができず、ちょっと困っています。label
はdocker image ls --filter
でチェックできるのですが、label!
だとかuntil
は確認する方法を見つけられていません。実際に消去の実行をしない--dry-run
みたいなオプションがあれば良いのになと思ったりします。
##コンテナの断捨離
次にコンテナの整理について。コンテナも気がつくと不要なものが溜まっていたりします。特に、docker container ls
としての何も出てこないので安心していると、実行済みのコンテナがたんまり残っていたりします。確認するには -a
オプションを使います。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5802c2477245 alpine "ls" 11 seconds ago Exited (0) 10 seconds ago awesome_hellman
247e211d6b59 alpine "ls" 45 seconds ago Exited (0) 44 seconds ago blissful_mclean
daa39f115422 alpine "ls" 47 seconds ago Exited (0) 46 seconds ago cranky_lamport
実行の終わったコンテナでもdocker restart
で再度起動できるためデフォルトでは自動で消えてくれないです。もし停止と同時にコンテナを消去したければ --rm
オプションを付けてdocker run
すれば良いですが、それでもビルドに失敗したときなどにコンテナが残るため自然と溜まっていってしまいます。
そんな時にdocker container prune
を実行すると、imageの時と同様に本当に消すかどうかを聞かれ、y
と答えると綺麗サッパリ消してくれます。対象は「停止中」のコンテナ。
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
be1381d7199a6dcf1083c4ef9792ae78e04044743a6c6e1ce3cd517dc22479ab
b9733c0160d16858ba2ef5ee877a23c3249e5313787debdb2c51e5863fdb2d31
f71351f2a878ab343c594675bb4cdff9966220a6d69fbb4d65e22205246525f1
4938b15ff8da0909eef220ce5254647e829fb6257a8ea8cbc9cd8361125f419b
5802c2477245b4f40fa6321a8780fbaac2d194e732b0813f58e305a2a9b444d2
247e211d6b59ce9bc1dbbd0c132d5877e81340c1b9e65d2eff1cf768bd03ebe7
daa39f1154227503b8c0da00153113d25c6305975b8801fbfa5aa317059398e7
Total reclaimed space: 3.831MB
そして、このコマンドにもオプションがいくつかあります。
#####-f
--force
これはdocker image prune
と同様で、実行時に「消しちゃうけど大丈夫?」という確認をスキップするためのオプションです。
#####--filter
消去するコンテナを選択する追加の条件を指定できます。指定方法もimageと同じでuntil
とlabel
。ラベルは基本は元のイメージのものを引き継ぎますが、docker run
で実行する時に上書きもできるのでその点は要注意かもしれません。
##ボリュームの断捨離
ボリュームも気をつけていないと溜まっていってしまうものの一つです。docker volume create
コマンドで明示的に作ったり、あるいは docker run -v <desitination_path>
やDockerfile内のVOLUMEコマンドで無名のボリュームを作ったりしますが、それはコンテナを消去しても自動的には消えません (run --rm
を使った場合に一部例外あり)。
docker volume ls
をすると今現在システムで抱えているボリュームのリストが出てきます。
$ docker volume ls
DRIVER VOLUME NAME
local 0f181d792f4313abb670110c0ee079910fa3ca776463b515093a4fea4219dcc9
local 1d383f8ab7ec848c9e8e7969969f88a92d46d20592e7f3aa6ddb590feab2fb55
local 2c3afd63e16ecbb33bc54e8e7545ee1be5d5568236203dd69c5eeb38e98f9c72
...
ここでdocker volume prune
をしてあげると、使われていない(現存するコンテナから参照されていない)ボリュームはサクッといなくなります。
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
...
Total reclaimed space: 1.528GB
私は1.5GBものスペースを無駄に保持していたようです (^^;
他のpruneコマンド同様に、docker volume prune
も -f/--force
と--filter
オプションが使えます。使い方は一緒なので説明は割愛させていただきます。
##ネットワークの断捨離
上記のイメージ、コンテナ、ボリュームに比べると溜まりにくいしそもそもデータ量もそれほどないので使う機会は少ないかも知れませんが、docker network create
で明示的に作成したものは自動では消えないのでルーティングテーブルをシンプルに保ちたい方は定期的にdocker network prune
をやると良いかも知れません。
docker-compose up
で複数コンテナを立ち上げたときには自動でデフォルトのbridgeネットワークが作られますが、docker-compose down
するとそのネットワークは自動削除されるのでホントに出番が少なさそう(一方、自動で作られたボリュームは残り続けます…)。
基本は現存するコンテナから参照されていないネットワークが削除されますが、デフォルトで作成されている bridge
、host
、none
は消えずに残るようです。
##まとめて断捨離
これまで、個別にpruneするコマンドを紹介してきましたが、実はまとめてキレイにしてくれるコマンドも存在します。それが、docker system prune
。これをやると、
- 停止中のコンテナ
- どのコンテナからも使われていないネットワーク
- 宙ぶらりんな(タグがなくどのコンテナからも参照されていない)イメージ
- ビルドキャッシュ
を全て消してくれます。最後のはビルドの速度を早めるために持っている中間結果を破棄するもので、ビルド時に--no-cache
をつけるとそれを破棄した状態からビルドをはじめてくれますが、当然ビルドが終わった後にはキャッシュが残るわけで、キャッシュだけを削除するというコマンドは今まで無かったように思います。
さらに、--volumes
オプションをつけて起動すると
- どのコンテナからも使われていないボリューム
も合わせて消してくれます。また、これにも-f/--force
オプションがあるので「実行するか一々確認しなくても良いよ」という男気のある方は是非ともご活用ください(笑)。
なお、個別にpruneしていくのも良いのですが、コンテナ以外のイメージ、ボリューム、ネットワークはコンテナから参照されていることを消す条件にしているので、先に不要なコンテナが消えていないと消せません。そういった順序関係を気にしたくなかったらdocker system prune
で一気にやってしまうのも手かなと思います。ただし、必要なモノを消してしまう可能性もあるのであくまでも自己責任でお願いします。
#まとめ
pruneコマンドに関してまとめてみました。書き始めたときにはすごく短いエントリになるかと思っていたら意外と長くなりました(^^;
ただ、書きながらボリュームやネットワークに関して自分はあまりわかっていなかったと再認識し、そういう意味でも書いた意味があったかなと思います。