dockerでタグを打ってないイメージを削除する対処療法的なスクリプトを書いてみた

# はじめに

私はまだdockerのイメージ管理の仕組みをよく理解しておらず、試行錯誤して対処療法的にスクリプト書いてみただけですので、あまり期待せずに読んでください。

[最速Docker研究会(DockerのTipsを20個上げていくぜ編) - Happy New World](http://d.hatena.ne.jp/mainyaa/20140203/p1)の「3. docker build時には必ずタグを付ける。」を実践していると、試行錯誤中に何度も同じタグでイメージをビルドするので、古いイメージはタグが外れた状態になっています。

```shell-session
$ docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
hnakamur/nginx-lua         latest              79e74886d6a9        31 hours ago        527.6 MB
<none>                     <none>              64b4fa0cdd27        32 hours ago        525 MB
<none>                     <none>              5a2b9b2294c3        32 hours ago        525 MB
<none>                     <none>              a12c2c15bbfd        32 hours ago        525 MB
(…略…)
```

タグのついてないイメージをまとめて消したいなーと思って調べてみたところ、[Dockerで不要になったコンテナやイメージを削除する - @znz blog](http://blog.n-z.jp/blog/2013-12-24-docker-rm.html)という記事を見つけました。（←注：blogまでをリンクにしたいのですがエスケープ方法がわからず）

でも実際やってみると

```shell-session
$ docker rmi $(docker images | awk '/^<none>/ { print $3 }')
Error: image_delete: Conflict, 64b4fa0cdd27 wasn't deleted
Error: image_delete: Conflict, 5a2b9b2294c3 wasn't deleted
(…略…)
2014/03/08 18:26:04 Error: failed to remove one or more images
```

となって1つも消えませんでした。

# 先にコンテナを消す必要がある

ググってみると[`docker rmi` doesn't remove image · Issue #3549 · dotcloud/docker](https://github.com/dotcloud/docker/issues/3549#issuecomment-32046324)というコメントを発見。イメージを使用中のコンテナがあるから消せない、使用中のコンテナを調べるには```docker ps -a```を使えば良いということが判りました。

```docker ps -a```の出力はこんな感じです。2列目にイメージIDがあって1列目がコンテナIDになっています。

```shell-session:
$ docker ps -a
CONTAINER ID        IMAGE                             COMMAND                CREATED             STATUS              PORTS                    NAMES
d3142ccc6b65        e359b0142e7c                      /bin/sh -c #(nop) AD   32 hours ago        Exit 0                                       loving_mclean
cfc1c1e8865c        7088bb60ddab                      /bin/sh -c #(nop) CM   32 hours ago        Exit 0                                       focused_newton
bd4a1d1d5d21        b4488990d8fb                      /bin/sh -c #(nop) EX   32 hours ago        Exit 0                                       insane_fermi
(…略…)
```

そこでこんなbashスクリプトを作ってみました。

```sh:docker_rm_containers_for_images_without_tags.sh
#!/bin/bash
untagged_images=`docker images | awk '/^<none>/ { print $3 }'`
for image in $untagged_images; do
  containers=`docker ps -a | awk '$2 == "'$image'" { print $1 }'`
  if [ -n "$containers" ]; then
    docker rm $containers
  fi
  docker rmi $image
done
```

# しかしイマイチ問題あり

喜び勇んで試してみました。

```shell-session
$ ~/bin/docker_rm_containers_for_images_without_tags.sh
5430335f83e2
Deleted: 64b4fa0cdd27371ab83af797658b52b8d1bce792c51bff59eb567440ecc33b47
9adc1e994683
Deleted: 5a2b9b2294c3c81338c5b3d2e35f7e950aa74837b28264fd62b869a09c3d32bd
599543770f46
Deleted: a12c2c15bbfd950b9173c6c7af9735063fc4531e6f7527288cd996bfbe1a5682
(…略…)
```

お、順調に消されてるねと思い、実行も正常に終了したので、再度docker imagesを実行してみると、まだまだ残っているではありませんか。何個か減って入るのですが、上でDeletedと出た数よりはかなり少ないです。

上のスクリプトを実行してはdocker imagesで確認すると少しずつ減って行き、最後にはTAGが```<none>```のイメージは無くなりました。

ということでdocker imagesでTAGが```<none>```のイメージがある場合は繰り返し実行するようにしてみました。

```sh:docker_rm_containers_for_images_without_tags.sh
#!/bin/bash
while :; do
  untagged_images=`docker images | awk '/^<none>/ { print $3 }'`
  if [ -z "$untagged_images" ]; then
    exit 0
  fi
  for image in $untagged_images; do
    containers=`docker ps -a | awk '$2 == "'$image'" { print $1 }'`
    if [ -n "$containers" ]; then
      docker rm $containers
    fi
    docker rmi $image
  done
done
```

とりあえずの目的は達したので、一旦これでよしとします。ライセンスはMITです。

# 別のエラーも出たけど再現できず

この記事を書きながら試していると以下の様なエラーが出た時が一度だけありました。

```
Error: container_delete: Impossible to remove a running container, please stop it first
2014/03/08 19:20:29 Error: failed to remove one or more containers
Error: image_delete: Conflict, 79e74886d6a9 wasn't deleted
2014/03/08 19:20:29 Error: failed to remove one or more images
Error: container_delete: Impossible to remove a running container, please stop it first
2014/03/08 19:20:28 Error: failed to remove one or more containers
Error: image_delete: Conflict, 79e74886d6a9 wasn't deleted
2014/03/08 19:20:28 Error: failed to remove one or more images
(…略…)
```

docker runしたまま同じタグのイメージを何回か作ってdocker_rm_containers_for_images_without_tags.shを実行した時に発生しました。

docker psでコンテナIDを調べてdocker stop ${コンテナID}で止めてからdocker_rm_containers_for_images_without_tags.shを実行すると大丈夫でした。

その後、再現を試みようとdocker runしたままdocker build -tで同じタグのイメージを何回か作ってdocker_rm_containers_for_images_without_tags.shを実行してみたのですが、再現しません。

別のパターンとして以下のようにNo such imagesが出るケースが発生しましたが、これは実害は無いので気にしないことにします。

```
$ ~/bin/docker_rm_containers_for_images_without_tags.sh
Deleted: 8746e95203a6273be11188f43af1a1e10219b587ceff60be60c7791c5744a17e
Deleted: e07e561873cd7a4feca3ff68d36d6bc1e91773600870cd3e4cc1219fb43b5208
Error: image_delete: No such image: e07e561873cd
2014/03/08 19:27:21 Error: failed to remove one or more images
42b755c2809a
Deleted: 777e310d5345300d6949e6ed513d93cb96886eccff86109053ae9dd6979e7207
55e8d9b3705a
(…略…)
```