◆ --filter オプションに label があったけど
◆ label は run のタイミングでしか設定できないみたい
◆ 結局保持リストのテキストファイルに含まないをの rm する自作スクリプト

prune で保持したい

特定の OS のデフォルトの設定ファイルをみたい とか 特定バージョンの Node.js で動きを確認したい とかそういう感じで気軽にコンテナを作ってるとコンテナが溜まっていきます

終了時に自動で削除する --rm オプションを docker run で指定すればいいのですが これが結構忘れるものなんです
それに一旦終了するけどもう少しあとで続きから使いたいってこともあったりします
そういうときに --rm をつけて起動してると困るので --rm をつけるのはプログラムを自動で実行する場合だけにして bash を起動するなどインタラクティブに操作する場合はつけないようにしてます

そうなると終了済みコンテナが結構溜まってしまいひとつひとつ rm するのは面倒です
なので頻繁に docker container prune を使ってまとめて削除してます

しかし不便なところもあって prune は停止中なら全部削除です
一部コンテナは長期的に使うので消されると困ります
除外のために一時的にそれらを起動させるのも面倒です

ラベルでフィルター?

テキストファイルに保持したいコンテナの名前を書いておいてそれ以外を削除するようなスクリプトを作ることを考えました

ただ面倒だしそういう仕組みがあったりしないのかとリファレンスを見てみました
https://docs.docker.com/engine/reference/commandline/container_prune/

ヘルプではタイムスタンプの指定しか書かれてなかった --filter オプションで label も指定できるみたいです
label なんてあるのを初めて知りましたが Docker ではイメージやコンテナにラベルをつけることができるみたいです

それなら keep というラベルをつけておいて このラベルを含まないのだけ削除するように --filter 指定すれば良さそうです

……と思ったのですけど コンテナにラベルを付ける方法が見つからず調べると docker run でのみ指定できるようです
ポートやボリュームなどもそうですが 起動時にしか設定できない設定が多いです
起動時点では保持したいかどうかは決まりません
それが完全にできるなら --rm をつけるつけないで管理できます
なのでラベルをつけて --filter 指定という使い方はできなさそうでした

結局自作

標準機能ではできなさそうだったので諦めて当初の予定通りにスクリプトを作りました

#!/usr/bin/python3

import sys
import subprocess

try:
with open("docker-prune-keep") as f:
keep_str = f.read()
except:
print("Error: docker-prune-keep file is not found in current directory.")
exit()

keep = set([x for x in keep_str.splitlines() if x])

result = subprocess.run(["docker", "ps", "-a", "--format", "{{.Names}}"], encoding="utf-8", capture_output=True)
if result.returncode != 0:
print(result.stderr)
exit()

containers = set([x for x in result.stdout.splitlines() if x])
print("List of containers")
for name in containers:
print("- " + name)
print("")

dryrun = len(sys.argv) >= 2 and sys.argv[1] == "-d"
if dryrun:
print("mode: dry-run\n")

removed = 0
for name in containers - keep:
if not dryrun:
result = subprocess.run(["docker", "container", "rm", name], encoding="utf-8", capture_output=True)
if result.returncode != 0:
print(result.stderr)
exit()
else:
removed += 1

print("remove: " + name)

print("")
print(str(removed) + " containers removed")

docker-prune-keep ファイルを作ってそこにコンテナ名を書いておきます
ここに書かれた以外のコンテナを削除します

-d オプションをつけると dry-run モードで実際に削除は行わず削除する対象を確認できます
カレントディレクトリが違っていて 保持するものなしで全部消してしまうのを避けるため docker-prune-keep ファイルがない場合はエラーにしてます