Dockerイメージをファイルで共有する

今回はDockerイメージをDocker Hubを利用せずにファイルで共有する方法です。
社内で共通のDockerイメージを共有する場合など、Docker Hubの利用が制限される場合には有効な手段です。

コマンドには、export/importとsave/loadの2種類がありますが、それぞれ挙動が少し異なります。
どのように違うのか確認したところ下記のようになりました。

Dockerコンテナのexport/import

Dockerコンテナのファイルシステムをexport/importしてみました。

作成したコンテナのファイルシステムをtarアーカイブの形式で出力するにはexportコマンドを使用します。

使い方は

$ docker export [OPTIONS] CONTAINER

です。

それでは、実際にexportしてみます。

$ sudo docker export developer-env | gzip -c > developer-env.tgz

export後のサイズは下記のようになりました。

$ ls -l developer-env.tgz
-rw-r--r-- 1 developer developer 76805143  5月 25 11:42 developer-env.tgz

次に、exportしたtarballから内容を読み込むにはimportコマンドを使用します。

使い方は

$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

です。

それでは、さきほどexportしたtarballをimportしてみます。

$ sudo docker import developer-env.tgz

また、下記のようにWEBから直接読み込むような使用方法もあるようです。

$ sudo docker import http://example.com/exampleimage.tgz

今回は、下記のようにimportしてみました。

$ sudo docker import developer-env.tgz

イメージを確認します。

$ sudo docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
<none>       <none>    bb234474c57b   52 seconds ago   168MB

REPOSITORYもTAGも未指定だったので、いずれも<none>となっています。

次に実行します。

$ sudo docker run -d -it --name developer-env bb234474c57b
docker: Error response from daemon: No command specified.
See 'docker run --help'.

エラーで怒られてしまいました。
コンテナに関連づけられたボリュームに含まれる内容を出力しないために、実行コマンドを指定する必要があるようです。

$ sudo docker run -d -it --name developer-env bb234474c57b /bin/bash
5ce860cb73ffdf1092e1a1dddb6e6da888fcdb2a24bd253ab46d93f55ec03ad4

実行中のコンテナ内でコマンドを実行します。

$ sudo docker exec -it developer-env bash
root@5ce860cb73ff:/#

実行コマンドを指定した時点で想像はできたのですが、rootでのログインとなりました。
この使い方は自分のニーズではないようです。

Dockerイメージのsave/load

次にDockerイメージをsave/loadしてみました。

作成した複数のイメージをtarアーカイブの形式で出力するにはsaveコマンドを使用します。

使い方は

$ docker save [OPTIONS] IMAGE [IMAGE...]

です。

先ほどと同じイメージをsaveします。

$ sudo docker save debian:bullseye-ja | gzip > developer-env.tgz

save後のサイズは下記のようになりました。
exportに比べると少し大きいようです。

$ ls -l developer-env.tgz
-rw-r--r-- 1 developer developer 77535089  5月 25 13:36 developer-env.tgz

イメージを取り込むにはloadコマンドを使用します。

使い方は

$ docker load [OPTIONS]

です。

先ほどsaveしたイメージをloadしてみます。

$ sudo docker load < developer-env.tgz
78658088978a: Loading layer [==================================================>]  129.1MB/129.1MB
83cf275345d6: Loading layer [==================================================>]  349.7kB/349.7kB
564586e372a3: Loading layer [==================================================>]  23.49MB/23.49MB
83d0a723ac55: Loading layer [==================================================>]   5.12kB/5.12kB
d0442dfa25b3: Loading layer [==================================================>]  22.94MB/22.94MB
3f3ead373257: Loading layer [==================================================>]  11.78kB/11.78kB
27b4b3e5eaef: Loading layer [==================================================>]  1.172MB/1.172MB
c781741667dd: Loading layer [==================================================>]  3.072kB/3.072kB
9102d579176b: Loading layer [==================================================>]  8.192kB/8.192kB
Loaded image: debian:bullseye-ja

作成時のレイヤを再現することがわかります。

イメージを確認すると下記のようになりました。

$ sudo docker images
REPOSITORY   TAG           IMAGE ID       CREATED        SIZE
debian       bullseye-ja   802df363c999   21 hours ago   171MB

次に実行します。
今回は怒られることがありませんでした。

$ sudo docker run -d -it --name developer-env debian:bullseye-ja
66f0ee8dd74243735c5e47ae7af2eee6783188f53c2d80b8f6e1542978b0717c

実行中のコンテナ内でコマンドを実行します。

$ sudo docker exec -it developer-env bash
developer@66f0ee8dd742:~$

どうも、自分の使い方にはsave/loadのほうが良いようです。

コンテナ上の変更の反映

コンテナに対して加えた修正などは、上記のsave/loadでも反映されません。

そこで、コンテナの変更を反映し、新しいイメージを作成するにはcommitコマンドを使用します。

使い方は

$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

です。

実際の使用方法としては

$ sudo docker commit ubuntu-16.04-ja ubuntu-16.04-ja:20220529

という風に使用します。

さきほどと同様にcommitしたイメージを保存すれば完了です。

# sudo docker save ubuntu:16.04-ja | gzip > ubuntu-16.04-ja.tgz

これでコンテナに加えた修正を含めたイメージの保存が完了です。