【Docker】【ShellScript】Docker Compose 配下のイメージをまとめてエクスポートするワンライナーの紹介

 Dockerのイメージをエクスポートしたい時がままあります。これは別環境での再ビルドが面倒であったり(ファイルコピーとインポートで済ます)、使っているイメージをそっくりそのまま使いたかったり、イメージのバックアップをとりたかったりする時などです。

 Docker ComposeはあるプロジェクトのDockerに関するものをまとめて扱うための仕組みです。イメージもそれに含まれます。

 このためDocker Composeで管理しているイメージをまとめてエクスポートできると便利です。この方法を紹介します。

 まとめてエクスポートするためのコマンドは次です。これを実行すると images ディレクトリが作成され、そのimagesディレクトリ以下にDocker Composeで管理しているイメージが全てエクスポートされます。

mkdir -p images && docker compose images | awk 'NR>1 {print $2}' | xargs -I {} sh -c "docker save {} -o images/\$(echo {}.tar | tr '/' '-')"

 個々からはこのコマンドで何をやっているかの解説です。

 このコマンドはmkdir -p imagesdocker compose imagesawk 'NR>1 {print $2}'xargs -I {} sh -c "docker save {} -o images/\$(echo {}.tar | tr '/' '-')"に分解できます。

 まずmkdir -p imagesです。よく使われるディレクトリ作成のコマンドで images ディレクトリを生成しています。ここでのpオプションは既にディレクトリが存在していてもエラーにならないように付けています。&&で次コマンドと繋ぐことによって、imagesディレクトリが存在することを担保できたなら次コマンドに処理の手番を渡すようにします。

 次いでdocker compose imagesです。これはDocker Composeで管理しているイメージの一覧を表示するコマンドです。この表示結果は例えば次のようになります。これを元にエクスポートしたいイメージの名前を指定します。|を使って表示結果をawkコマンドに渡します。

$ docker compose images
CONTAINER	REPOSITORY  	TAG 	IMAGE ID   	SIZE
xxxx-app-1	xxxx-app   	latest	6b58ebeaa637	694MB
xxxx-mailpit-1	axllent/mailpit	latest	3ba39824b93d	23.6MB
xxxx-mysql-1	xxxx-mysql  	latest	5a6295095ed7	520MB

 awk 'NR>1 {print $2}'でヘッダ行を除去して2列目の文字列を得ます。NR>1はNumber of Recordが1より大きい、つまり2行目以降のみを対象に取ることを示します。{print $2}は現在のレコードの2番目のフィールド、つまり2列目の値を表示するという意味です。awk ‘NR>1 {print $2}’ は、入力されたデータの最初の行をスキップし、その後の各行について2番目のカラムのデータを出力するという動作をします。これでDocker Compose配下の各イメージの名前を抜き出します。|を用いて抜き出したイメージの名前達を最後のエクスポートコマンドに渡します。

 最後にxargs -I {} sh -c "docker save {} -o images/\$(echo {}.tar | tr '/' '-')"です。これはいささか複雑です。xrargsを使う理由はイメージ名をDockerイメージのエクスポートコマンドの標準入力で渡せる部分以外にも使いたいためです。xargsを使うことでより柔軟なコマンドを実現できます。先ほどのawkまでの処理の結果は次です。

xxxx-app
axllent/mailpit
xxxx-mysql

 これをxargs -I {} xxx に渡すと、xargsが受け取った入力の各行が後続のコマンド内の{}に置き換えられて使用されます。つまりxargsによって実行されるコマンドは次のようになります。

sh -c "docker save xxxx-app -o images/\$(echo xxxx-app.tar | tr '/' '-')"
sh -c "docker save axllent/mailpit -o images/\$(echo axllent/mailpit.tar | tr '/' '-')"
sh -c "docker save xxxx-mysql -o images/\$(echo xxxx-mysql.tar | tr '/' '-')"

 シェルを介しているのはイメージ名に含まれる「/」によってディレクトリがネストするのを避ける処理を入れるためです。「/」を「-」に置き換えて docker save に渡すための部分が\$(echo xxxx-app.tar | tr '/' '-')です。xargs で渡されたイメージ名に含まれる「/」を文字列変換・削除コマンドであるtrで「-」に変換します。この変換結果を$()で展開するようにします。「$」を「\」でエスケープをしているのは xargs の段階でこの部分が実行されるのを避けるためです。もし「\」がない場合、{} によって実際のイメージ名が渡される前に置換処理が走ってしまい、イメージ名の変換がなされません。この展開をして実行されるコマンドは次のようになります。

sh -c "docker save xxxx-app -o images/xxxx-app.tar"
sh -c "docker save axllent/mailpit -o images/axllent-mailpit.tar"
sh -c "docker save xxxx-mysql -o imagesxxxx-mysql.tar"

 イメージ名を元にした docker save をシェル経由で実行するコマンドの完成です。これが実行されて images 以下にDocker Composeで管理されているイメージが全てエクスポートされます。

 エクスポートされたイメージファイルはdocker load -i images/axllent-mailpit.tarのようにしてDockerイメージにできます。imagesディレクトリ以下のtarファイルを全てDockerイメージとするのはfind images/ -name "*.tar" | xargs -I{} docker load -i {}でできます。

 エクスポート、インポートの対象となるイメージが多い場合はここまでで紹介した逐次実行で動作するワンライナーのコマンドより、処理を平行させるようにしたシェルスクリプトを書いて使った方が快適になりやすいです。

 Dockerイメージを実ファイルとしてエクスポート、インポートすることはそんなにないですが、まとめて扱う方法があると知っておくとちょっと便利です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG