Docker イメージの断捨離を圧倒的に効率化する


こういうのを作りました。

Docker イメージの断捨離がダルい問題

Docker イメージがディスク容量を圧迫して困ることがありますよね。

docker image prunedocker system prune をすれば dangling なイメージをまとめて削除することができます。danglings (宙ぶらりんな) イメージとは「タグ付けされていない」「どのコンテナも使ってない」イメージのことなので、つまりは「削除しても問題なさそうなイメージをまとめて削除する」ってやつです。

これだけである程度は削除できますが、タグ付けされている不要なイメージまでは削除できません。 -a / --all オプションを使えばタグ付けされている未使用なイメージをまとめて削除できますが、これだと今度は必要なイメージまで削除してしまうので難しいです。

結局、ちゃんと断捨離しようと思ったら目視でひとつひとつ削除していくしかないのです。

しかしそれが大変で、latest ではないイメージは <Repository>:<Tag> と指定するかイメージ ID を直接指定するしかなく、手でポチポチとコピペしていくハメになります。しかも削除順序を間違えると「このイメージはこっちのイメージが依存しているから削除できんよ」などとエラーを吐かれます。やってられるか。

こうした単純作業は効率化するのが IT エンジニアの美徳です。

「リストの中から人間が選択をする」操作を効率化する手段といえば何ですか?
そう、peco ですね。

peco とは

@xtetsuji さんの「pecoの基礎の基礎」がわかりやすいです。

とてもシンプルなツールで 「標準入力から受けた行データをインクリメンタルサーチして、選択した行を標準出力に返す」 コマンドです。

シンプルゆえに様々な組み合わせで効果を発揮します。あらゆる場面での選択肢を標準入力に渡して、選択された結果を標準出力から受け取って加工してコマンド実行をする、というのが基本的な流れ。

自分も「コマンド履歴を検索して再実行」とか「SSH の接続先を選んで接続」とか「Git リポジトリのブランチを選んで切り替え」とか1 頻繁に使います。 控えめに言ってめちゃくちゃ便利。

macOS だったら brew install peco で入ります。

実はあまり知られていないっぽいですが、 peco は複数行選択ができます。
今回はこれを使って Docker イメージを断舎離するやつを作っていきましょう。

peco で Docker イメージを選択

peco で複数行選択をするためには control + space を使いますが、macOS ではこの組み合わせは「入力ソースの切り替え」に割り当てられているので、そのままでは使えません。回避方法は何でもいいですが、今回は「tab で複数行選択」が出来るように peco の設定ファイルを書いておきます。

~/.config/peco/config.json
{
  "Keymap": {
    "Tab": "peco.ToggleSelectionAndSelectNext"
  }
}

さて、おもむろに以下のコマンドを実行してみましょう。

$ docker images | peco

docker images の結果を peco に渡して、peco でフィルタリングして、標準出力に流しただけです。

というわけで、Docker イメージをフィルタリングして選択するやつができました。

便利スクリプトを書く

あとはもういい感じに仕上げるだけです。

~/.zshrc
function peco-docker-images() {
  local images="$(docker images | tail +2 | sort | peco --prompt 'DOCKER IMAGES>' | awk '{print $3}' ORS=' ')"
  [ -z "$images" ] && return
  BUFFER="$LBUFFER$images$RBUFFER"
  CURSOR=$#BUFFER
}

zle -N peco-docker-images
bindkey '^x^i' peco-docker-images

イメージを削除するために必要なのはイメージ ID なので、peco の結果に対して awk でイメージ ID だけを取り出して space で結合しています。

これは zsh スクリプトですが、bash でも似たような雰囲気で書けるのではないでしょうか。(知らん)

この例では control + x control + i で peco が起動して、選択したイメージ ID がプロンプトのバッファに差し込まれます。

これで地道なコピペをすることなく Docker イメージをごっそり断捨離できるようになりました。めでたしめでたし。