はい、承知いたしました。Dockerイメージをdocker save
コマンドで安全に保存するための詳細な情報を網羅した記事を作成します。約5000語となるよう、各項目を掘り下げ、技術的な詳細、実践的な使い方、注意点などを網羅します。
これを知れば安心!docker saveコマンドでDockerイメージを安全に保存・活用する方法
現代のソフトウェア開発と運用の現場において、Dockerはデファクトスタンダードとも言える存在になりました。アプリケーションとその実行環境をコンテナとしてパッケージングすることで、開発、テスト、本番環境間での一貫性を保ち、デプロイを劇的に簡素化します。Dockerにおけるコンテナの基盤となるのが「Dockerイメージ」です。
Dockerイメージは、アプリケーションを実行するために必要なコード、ランタイム、システムツール、システムライブラリ、設定など、すべてを一つのファイルシステムとしてまとめた読み取り専用のテンプレートです。このイメージから、実行可能なコンテナが作成されます。
Dockerイメージの再利用性、移植性、配布の容易さは、Dockerが広く普及した大きな理由の一つです。通常、イメージはDocker Registry(Docker HubやプライベートRegistryなど)を通じて共有されます。しかし、インターネット接続がない環境へのデプロイ、特定のバージョンの確実な保管、Registryにアップロードできないプライベートなイメージの共有など、Registryを介さずにDockerイメージをファイルとして保存し、後で復元したいというニーズは少なくありません。
そこで活躍するのが、今回詳しく解説するdocker save
コマンドです。このコマンドを使うことで、Dockerデーモンに存在するイメージを一つのアーカイブファイル(通常はtar形式)としてエクスポートできます。そして、エクスポートしたファイルを別のDocker環境に持ち込み、docker load
コマンドを使って簡単にイメージを復元できます。
本記事では、docker save
コマンドの基本的な使い方から、その内部的な仕組み、実践的な応用例、注意点、そして他のイメージ保存・配布方法との比較まで、幅広く、そして詳細に解説します。この記事を読み終える頃には、docker save
コマンドを自信を持って使いこなし、あなたのDocker運用をさらに安全で効率的なものにできるはずです。
さあ、docker save
の世界へ深く踏み込んでいきましょう。
1. Dockerイメージとは何か?その構造と重要性
docker save
コマンドを理解する前に、まずはDockerイメージそのものについて深く理解しておくことが重要です。Dockerイメージは単なる単一のファイルではなく、いくつかの重要な特性を持っています。
1.1. レイヤー構造 (Layered Architecture)
Dockerイメージの最大の特徴は、そのレイヤー構造です。イメージは複数の読み取り専用レイヤーが積み重ねられて構成されています。各レイヤーは、その一つ下のレイヤーからの変更点(ファイルシステムの追加、削除、変更など)を表しています。例えば、ベースイメージ(Alpine Linuxなど)の上に、いくつかのライブラリを追加するレイヤー、アプリケーションコードを追加するレイヤーなどが順に積み上がります。
このレイヤー構造にはいくつかの利点があります。
- 効率的なストレージ利用: 複数のイメージが同じベースレイヤーを使用している場合、そのベースレイヤーはディスク上で一度だけ保存されます。
- 高速なビルド: イメージビルド時に変更があったレイヤーとその上のレイヤーのみが再ビルドされるため、全体のビルド時間が短縮されます(キャッシュの利用)。
- 効率的な配布: イメージをRegistryから取得する際、既にローカルに存在するレイヤーはダウンロードする必要がありません。
docker save
コマンドは、このレイヤー構造を含めたイメージ全体をアーカイブします。保存されるファイルには、イメージを構成する全てのレイヤーデータと、それらをどのように組み合わせるかのメタデータが含まれます。
1.2. Immutable (不変) な性質
Dockerイメージはビルドされると不変(Immutable)になります。つまり、一度作成されたイメージの内容は変更できません。コンテナを実行する際は、イメージの一番上に書き込み可能なレイヤー(Container Layer)が追加され、そのレイヤー上でのみファイルシステムの変更が行われます。これにより、同じイメージから起動された複数のコンテナが互いに干渉することなく、それぞれ独立した状態を持つことができます。
docker save
で保存されるのは、この不変なイメージそのものです。保存したファイルには、特定の時点でのイメージの正確なスナップショットが含まれます。
1.3. イメージIDとタグ
各Dockerイメージは一意なイメージIDを持っています。これはイメージの内容(各レイヤーのハッシュ値など)に基づいて計算されるSHA256ハッシュ値の長い文字列です。イメージの内容がわずかでも変更されれば、イメージIDも変わります。
タグは、イメージIDに人間が識別しやすい名前(通常はリポジトリ名:タグ名
の形式)を付けるためのラベルです。例えば、ubuntu:latest
やmyapp:v1.0
などです。タグは特定のイメージIDを指し示しますが、タグ自体は変更可能です。例えば、myapp:latest
というタグが、最初はバージョン1.0のイメージを指していても、後でバージョン1.1のイメージを指すように更新されることがあります。
docker save
コマンドは、イメージIDまたはリポジトリ名:タグ名
を指定して実行できます。保存されるファイルには、イメージのメタデータとしてイメージIDや関連付けられたタグ情報も含まれるため、docker load
で復元する際に元のタグ情報も一緒に再現されます。
1.4. Docker Registryとの関係
通常、DockerイメージはDocker Registryにアップロード(Push)され、他のユーザーやシステムに共有(Pull)されます。Registryはイメージの中央リポジトリとして機能し、異なるバージョンやアプリケーションのイメージを管理します。
しかし、Registryへのアクセスが制限されている環境や、インターネットに接続されていない環境(エアギャップ環境)では、Registryからのイメージ取得が困難になります。また、自社開発のプライベートなイメージを外部のRegistryに置きたくない場合や、特定の時点のイメージをオフラインで確実に保管したい場合などもあります。
このような場合に、docker save
コマンドが役立ちます。Registryを介さずに、ローカルのDockerデーモンにあるイメージを直接ファイルとしてエクスポートし、手動で持ち運んだり、別の手段で転送したりすることができるからです。
2. なぜDockerイメージを保存する必要があるのか?docker save
のユースケース
RegistryへのPush/Pullが一般的なイメージ配布方法であるにも関わらず、なぜわざわざdocker save
を使ってイメージをファイルとして保存する必要があるのでしょうか?主なユースケースを具体的に見ていきましょう。
2.1. オフライン環境での利用 (エアギャップ環境)
最も代表的なユースケースです。製造ライン、研究施設、機密性の高いネットワークなど、インターネットに接続されていない、あるいは接続が制限されている環境でDockerを利用する場合、Docker Hubなどの外部RegistryからイメージをPullすることはできません。
このようなエアギャップ環境にイメージをデプロイするには、外部ネットワークでイメージをビルドまたはPullし、それをdocker save
でファイルとして保存します。保存したファイルをUSBメモリや外部HDDなどの物理メディア、あるいは制限されたネットワーク経路を通じてエアギャップ環境に持ち込み、そこでdocker load
を使ってイメージを復元します。これにより、オフラインでも必要なイメージを環境に準備できます。
2.2. バージョンの確実な固定・管理
開発、テスト、本番といった異なる環境で、全く同じイメージを使ってデプロイしたい場合があります。通常は特定のタグ(例: myapp:v1.2.3
)を指定してRegistryからPullしますが、もしRegistry側のイメージが誤って変更されたり、タグが他のイメージに付け替えられたりした場合、意図しないバージョンのイメージを取得してしまうリスクがゼロではありません(特にlatest
タグなどは頻繁に内容が変わります)。
docker save
を使って特定の時点のイメージをファイルとして保存しておけば、そのファイルにはその時点のイメージIDと内容が確実に含まれています。たとえRegistry上のイメージが変更されても、保存したファイルからロードすれば、元の正確なイメージを再現できます。これは、長期的な運用や、特定のバージョンのイメージを監査目的などで保管しておく際に非常に有効です。
2.3. 配布・共有(プライベートなイメージなど)
自社で開発したイメージを、外部のRegistry(Docker Hubなど)に公開したくない場合があります。また、プライベートRegistryを構築していない場合でも、チーム内で特定のイメージを共有したいことがあります。
docker save
でイメージをファイル化すれば、そのファイルを社内ネットワークのファイルサーバーに置いたり、セキュアなファイル転送手段(SCPなど)を使って直接共有したりできます。Registryを介さずにイメージを配布するシンプルかつ直接的な方法として利用できます。ただし、大きなイメージの場合はファイルの転送自体に時間がかかる点には注意が必要です。
2.4. 災害対策・バックアップ
Dockerコンテナが稼働しているホストに障害が発生した場合に備え、使用しているDockerイメージのバックアップを取りたい場合があります。RegistryにプッシュしているイメージであればRegistry自体がバックアップの役割を果たしますが、ローカルで一時的にビルドしたイメージや、特定のタグが付いていない中間的なイメージなども含めてバックアップしておきたい場合があります。
定期的にdocker save
コマンドを実行し、重要なイメージをファイルとして保存し、その保存先を別のストレージにバックアップすることで、ホスト障害時でもイメージを復旧できるようになります。
2.5. CI/CDパイプラインでの利用
CI/CDパイプラインにおいて、イメージのビルド後にそのイメージをRegistryにプッシュするのが一般的ですが、一時的にイメージをファイルとして扱いたい場合があります。例えば、ビルドサーバーとは別のサーバーで追加のテストを実行する前に、ビルド済みのイメージをRegistryを介さずにテストサーバーに転送したい場合などです。
ビルドサーバーでdocker save
を実行し、テストサーバーにファイルを転送後、テストサーバーでdocker load
を実行することで、効率的にイメージを移動させることができます。これにより、Registryへのプッシュ/プルにかかる時間や帯域幅を節約できる場合があります。
3. docker save
コマンドの基本と使い方
それでは、実際にdocker save
コマンドの使い方を見ていきましょう。非常にシンプルですが、いくつかの形式があります。
3.1. 基本書式
docker save
コマンドの基本書式は以下の通りです。
bash
docker save [OPTIONS] IMAGE [IMAGE...]
IMAGE
の部分には、保存したいDockerイメージのリポジトリ名:タグ名またはイメージIDを指定します。複数のイメージを同時に指定することも可能です。
デフォルトでは、docker save
は保存されたイメージデータを標準出力 (stdout
) に出力します。そのため、通常はリダイレクトを使ってファイルに保存します。
3.2. 基本的な使い方(単一イメージの保存)
最も一般的な使い方は、単一のイメージを指定し、その出力をファイルにリダイレクトすることです。
まず、保存したいイメージがローカルにあるか確認します。
bash
docker images
例えば、ubuntu:latest
というイメージを保存する場合:
bash
docker save ubuntu:latest > ubuntu_latest.tar
このコマンドは、ubuntu:latest
イメージをubuntu_latest.tar
という名前のtarファイルとして現在のディレクトリに保存します。
3.3. 複数のイメージを同時に保存
複数のイメージをまとめて一つのtarファイルに保存することも可能です。これは、関連する複数のイメージ(例: フロントエンド、バックエンド、データベースなど)をまとめて配布・バックアップしたい場合に便利です。
bash
docker save image1:tagA image2:tagB image3:tagC > multiple_images.tar
このコマンドは、指定された3つのイメージを一つのmultiple_images.tar
ファイルにまとめます。後述するdocker load
コマンドを使えば、この一つのファイルから全てのイメージを一度に復元できます。
3.4. -o
オプションを使ったファイル指定
標準出力へのリダイレクト (>
) の代わりに、-o
または --output
オプションを使って出力ファイルを直接指定することもできます。
bash
docker save -o my_image.tar my_image:latest
この形式は、リダイレクトを使う場合と機能的にはほとんど同じですが、コマンドとして出力ファイルを指定する意図が明確になります。Dockerの公式ドキュメントや多くの例では-o
オプションが使われることが多いです。どちらを使っても問題ありませんが、統一しておくと分かりやすいでしょう。
複数のイメージを保存する場合も同様に-o
オプションが使えます。
bash
docker save -o images.tar image1:tagA image2:tagB
3.5. イメージIDを指定して保存
タグではなく、特定のイメージIDを指定して保存することも可能です。
bash
docker save abcdef123456 > image_by_id.tar
これは、タグが付いていないイメージや、特定のイメージIDで確実に指定したい場合に有効です。
3.6. 注意点:どのイメージを指定するか
docker save
コマンドにイメージを指定する際、リポジトリ名:タグ名またはイメージIDを使用します。
- リポジトリ名:タグ名: この形式で指定した場合、Dockerは指定されたタグが現在指しているイメージIDを特定し、そのイメージを保存します。もし同じイメージIDに複数のタグが付いている場合でも、特に指定しない限り、保存ファイルには指定したタグ情報が含まれて保存されます。
- イメージID: この形式で指定した場合、そのイメージIDを持つイメージが保存されます。ロード時、元のイメージに付けられていたタグのうち、リポジトリ名を持たないタグ(例えば、ビルド時に一時的に付けられる
<none>:<none>
など)は復元されない可能性があります。通常は、リポジトリ名とタグ名で指定するのが推奨されます。
もし、あるイメージIDに対して複数のタグが付いている場合(例: myapp:v1.0
とmyapp:latest
が同じイメージIDを指している)、docker save myapp:v1.0 > myapp_v1.0.tar
と実行しても、保存されるファイルにはmyapp:latest
というタグ情報も一緒に含まれる場合があります。これは、Dockerが内部的にイメージIDとそれに関連付けられている全てのタグ情報を管理しているためです。docker save
は指定されたイメージIDに紐づく情報を全て保存しようとします。ただし、保存ファイルに含まれるリポジトリ/タグ情報の具体的な形式はDockerのバージョンによって若干異なる可能性もあります。基本的には、指定したイメージとそのイメージIDに関連付けられているタグ情報が復元されると理解しておけば良いでしょう。
最も確実なのは、docker images
で確認できるREPOSITORY:TAG
形式で指定することです。
4. docker save
で保存される内容の詳細
docker save
コマンドで生成されるtarファイルは、単にイメージのファイルシステムを固めたものではありません。イメージの構造やメタデータを維持するために、特定の構造を持っています。生成されたtarファイルの中身を詳しく見てみましょう。
生成されたtarファイルを展開(例えば tar -xf my_image.tar
)してみると、以下のようなファイルやディレクトリが含まれていることが分かります(実際のファイル名やディレクトリ名はイメージやDockerのバージョンによって異なる場合がありますが、構造は似ています)。
.
├── <layer_id_1>/
│ ├── layer.tar
│ └── VERSION
├── <layer_id_2>/
│ ├── layer.tar
│ └── VERSION
├── ...
├── <layer_id_N>/
│ ├── layer.tar
│ └── VERSION
├── manifest.json
└── repositories
4.1. 各レイヤーのディレクトリとlayer.tar
<layer_id_X>
という名前のディレクトリ(<layer_id>
は通常、レイヤーのハッシュ値の短い形式などになります)が複数存在します。これらはイメージを構成する各レイヤーに対応します。
layer.tar
: このファイルは、そのレイヤーでのファイルシステムの変更点(追加、削除、変更されたファイルなど)を含むtarアーカイブです。これがイメージの実際のファイルシステムデータになります。VERSION
: このファイルには通常、Docker Image Specificationのバージョン番号(例: “1.0”)が含まれています。
これらのディレクトリとlayer.tar
によって、イメージのレイヤー構造とその中身が保存されています。
4.2. manifest.json
manifest.json
ファイルは、保存されたイメージ全体に関するメタデータを含む非常に重要なファイルです。複数のイメージを保存した場合、このファイルはJSON配列になります。
manifest.json
には通常、以下のような情報が含まれています。
- Config: 各イメージのコンテナ設定(Entrypoint, Cmd, Env Vars, Volumesなど)への参照。実際の設定内容は別のJSONファイルとして保存される場合が多いです。
- RepoTags: この保存ファイルに含まれるイメージに関連付けられているリポジトリ名とタグ名のリスト(例:
["ubuntu:latest", "ubuntu:18.04"]
)。docker load
で復元する際に、この情報からイメージにタグが付けられます。 - Layers: イメージを構成する各レイヤーのディレクトリ名のリスト。このリストの順番が、レイヤーが積み重ねられる順序を示します。
- Parent (optional): 親イメージへの参照。
このmanifest.json
があるおかげで、docker load
はどのレイヤーをどのような順番で組み合わせ、どのような設定とタグを付けてイメージとして登録すれば良いかを正確に把握できます。
4.3. repositories
ファイル
repositories
ファイルは、保存されたイメージとそれに関連付けられているタグの古い形式のマップファイルです。manifest.json
が登場する前のDockerの古いバージョンで使用されていましたが、後方互換性のために現在も含まれています。
このファイルはJSON形式で、リポジトリ名をキーとし、そのリポジトリに紐づくタグとイメージID(またはレイヤーID)のマッピングを値として持ちます。
json
{
"ubuntu": {
"latest": "<image_id>",
"18.04": "<image_id>"
},
"myapp": {
"v1.0": "<another_image_id>"
}
}
現在では主にmanifest.json
が使用されますが、このファイルもロード時のタグ付け情報として参照されることがあります。
このように、docker save
で生成されるtarファイルは、イメージのレイヤーデータだけでなく、その構造やメタデータを完全に再現するために必要な情報を含んでいます。これにより、docker load
コマンドで元のDocker環境に忠実にイメージを復元することが可能になります。
5. docker save
コマンドの実践的な使い方とテクニック
基本的な使い方を理解したところで、より実践的なシナリオでdocker save
をどのように活用するかを見ていきましょう。
5.1. 特定のタグを持つイメージの保存
最も一般的で推奨される方法です。docker images
で確認できる正確なREPOSITORY:TAG
形式で指定します。
“`bash
例: nginxの特定のバージョンを保存
docker save -o nginx_1.21.6.tar nginx:1.21.6
“`
これにより、nginx:1.21.6
というタグが付いたイメージが保存されます。ロード時もこのタグで復元されます。
5.2. docker images
と組み合わせて保存
docker images
コマンドの出力を使って、保存したいイメージを指定することができます。特に、特定の条件(リポジトリ名だけ、タグの一部など)に一致するイメージをまとめて保存したい場合に便利です。
例えば、「myapp」というリポジトリ名を持つ全てのイメージを保存したい場合:
“`bash
まず、myappに関連するイメージのリストを取得
docker images myapp
取得したリストを使ってsaveコマンドを実行
シェルスクリプトなどで実行する場合
IMAGES_TO_SAVE=$(docker images –format “{{.Repository}}:{{.Tag}}” myapp)
docker save -o myapp_all_versions.tar $IMAGES_TO_SAVE
または、xargsを使う場合
docker images –format “{{.Repository}}:{{.Tag}}” myapp | xargs docker save -o myapp_all_versions.tar
“`
--format
オプションを使うことで、docker images
の出力をリポジトリ名:タグ名
形式のリストに整形できます。xargs
コマンドはそのリストを引数としてdocker save
に渡します。
注意: docker images
の出力には<none>:<none>
のようなタグなしイメージも含まれる場合があります。これらを指定して保存すると、ロード時にタグが付けられずに復元される可能性があります。また、依存関係にある親イメージなどが自動的に含まれるわけではありません。あくまで指定したイメージ自身が保存されます。
5.3. 圧縮しながら保存(ディスク容量と転送時間の節約)
Dockerイメージのtarファイルは非常に大きくなることがあります。ディスク容量を節約したり、ファイル転送時間を短縮したりするために、保存と同時に圧縮を行うのが一般的です。docker save
は標準出力にイメージデータを出力できるため、パイプ (|
) を使って圧縮コマンドに渡すことができます。
最も一般的なのはgzip圧縮です。
“`bash
gzip圧縮して保存 (.tar.gz または .tgz 拡張子を使うのが一般的)
docker save my_image:latest | gzip > my_image_latest.tar.gz
“`
または、bzip2やxzなどのより強力な圧縮ツールを使うこともできます(圧縮率は高いですが、時間もかかります)。
“`bash
bzip2圧縮
docker save my_image:latest | bzip2 > my_image_latest.tar.bz2
xz圧縮
docker save my_image:latest | xz > my_image_latest.tar.xz
“`
これらの圧縮ファイルをロードする際は、対応する解凍コマンドと組み合わせてパイプでdocker load
に渡します。
“`bash
gzip圧縮ファイルのロード
gunzip -c my_image_latest.tar.gz | docker load
bzip2圧縮ファイルのロード
bunzip2 -c my_image_latest.tar.bz2 | docker load
xz圧縮ファイルのロード
xzcat my_image_latest.tar.xz | docker load
``
-c`オプションは解凍したデータを標準出力に書き出すためのものです。
5.4. 保存ファイルの分割(容量制限のあるメディアへの保存)
非常に大きなイメージを、容量に制限のあるリムーバブルメディア(例: 容量の小さいUSBメモリ)に保存したり、ファイル転送システムに1ファイルのサイズ制限がある場合など、保存ファイルを分割したいことがあります。split
コマンドを使えば、標準入力から読み込んだデータを指定したサイズの複数のファイルに分割できます。
“`bash
例: イメージを1GBごとに分割して保存
docker save my_large_image:latest | split -b 1G – my_large_image.tar.gz.
“`
このコマンドは、my_large_image:latest
イメージを保存したデータを、1GBごとのファイルに分割します。出力ファイルの名前はmy_large_image.tar.gz.aa
, my_large_image.tar.gz.ab
, my_large_image.tar.gz.ac
, … となります。最後のハイフン (-
) は、splitコマンドに標準入力から読み込むことを指示します。
分割したファイルを元に戻してロードする際は、cat
コマンドで連結し、パイプでdocker load
に渡します。
“`bash
分割したファイルを連結してロード
cat my_large_image.tar.gz.* | docker load
“`
この方法を使うと、大きなイメージでも物理メディアやネットワークの制限に合わせて分割して取り扱うことができます。ただし、分割されたファイルは全て揃っている必要があり、一つでも欠けると復元できません。
5.5. スクリプトでの自動化
定期的なバックアップや、CI/CDパイプラインへの組み込みなど、docker save
コマンドをスクリプト内で自動実行したいケースが多くあります。以下は、指定したリポジトリの全てのタグ付きイメージをまとめて保存するシンプルなシェルスクリプトの例です。
“`bash
!/bin/bash
REPO_NAME=”my_app”
OUTPUT_FILE=”${REPO_NAME}_$(date +%Y%m%d).tar.gz”
指定したリポジトリのタグ付きイメージリストを取得
IMAGES_TO_SAVE=$(docker images –format “{{.Repository}}:{{.Tag}}” “$REPO_NAME” | grep -v “
if [ -z “$IMAGES_TO_SAVE” ]; then
echo “Error: No images found for repository ‘$REPO_NAME’ with tags.”
exit 1
fi
echo “Saving images: $IMAGES_TO_SAVE”
echo “Output file: $OUTPUT_FILE”
イメージを保存し、gzip圧縮
docker save $IMAGES_TO_SAVE | gzip > “$OUTPUT_FILE”
if [ $? -eq 0 ]; then
echo “Successfully saved images to $OUTPUT_FILE”
else
echo “Error saving images.”
exit 1
fi
“`
このスクリプトは、my_app
という名前のリポジトリを持つ全てのタグ付きイメージを検索し、それらをまとめて日付入りのgzip圧縮ファイルとして保存します。必要に応じて、保存対象のフィルタリングやエラー処理などを追加できます。
6. 保存したイメージの復元方法 – docker load
コマンド
docker save
で保存したイメージファイルは、docker load
コマンドを使ってDockerデーモンに復元します。
6.1. 基本書式
docker load
コマンドの基本書式は以下の通りです。
bash
docker load [OPTIONS]
docker load
はデフォルトで標準入力 (stdin
) からイメージデータを読み込みます。
6.2. 基本的な使い方
docker save
でファイルにリダイレクトして保存したイメージを復元する場合、そのファイルを標準入力に渡します。
“`bash
例: 保存したtarファイルをロード
docker load < my_image.tar
“`
パイプを使って圧縮ファイルをロードする場合は、前述のように解凍コマンドと組み合わせます。
“`bash
gzip圧縮ファイルをロード
gunzip -c my_image_latest.tar.gz | docker load
“`
6.3. -i
オプションを使ったファイル指定
-i
または --input
オプションを使って、読み込むイメージファイルを直接指定することもできます。この形式は、標準入力へのリダイレクトよりも分かりやすい場合があります。
bash
docker load -i my_image.tar
圧縮ファイルを-i
オプションで直接指定することはできません。-i
オプションは非圧縮のtarファイルを想定しています。圧縮ファイルをロードする場合は、必ず解凍コマンドとパイプを組み合わせてください。
6.4. 複数のイメージが保存されたファイルの復元
docker save
で複数のイメージをまとめて一つのファイルに保存した場合、docker load
はそのファイルを読み込むだけで、ファイルに含まれる全てのイメージを一度に復元します。
bash
docker load -i multiple_images.tar
このコマンドを実行すると、multiple_images.tar
に含まれている全てのイメージ(とそのタグ)がDockerデーモンに登録されます。
6.5. 復元後の確認
ロードが完了したら、docker images
コマンドを実行して、意図したイメージが正しく復元されているか確認します。
bash
docker images
保存時に付いていたタグ情報も同時に復元されているはずです。もし同じリポジトリ名/タグ名のイメージが既に存在する場合、新しくロードされたイメージがそのタグを持つことになり、元々そのタグを持っていたイメージはタグなし(<none>:<none>
)になる可能性があります。重要なイメージの場合は、ロード前に既存のイメージを確認したり、ロード後にタグを確認したりすることをお勧めします。
6.6. ロード時の内部的な挙動
docker load
コマンドが実行されると、Dockerデーモンは指定されたtarファイルを読み込みます。ファイルに含まれるmanifest.json
やrepositories
ファイルを解析し、イメージの構造とメタデータを把握します。
次に、tarファイルに含まれる各レイヤーのlayer.tar
を展開し、それぞれのレイヤーデータをDockerのストレージドライバを使って格納します。ストレージドライバは、Union File Systemの仕組みを使ってこれらのレイヤーを管理します。
全てのレイヤーの格納が終わると、manifest.json
やrepositories
ファイルに基づいて、イメージIDを生成し、関連付けられているタグ情報を登録します。このプロセスを経て、docker images
で新しいイメージが表示されるようになります。
この仕組みにより、docker save
とdocker load
は、イメージの完全な状態を忠実に再現できるのです。
7. docker save
と他のイメージ保存・配布方法との比較
Dockerイメージを扱う方法はdocker save
/load
だけではありません。他の関連コマンドや方法と比較することで、それぞれの使いどころをより明確に理解できます。
7.1. docker export
との違い
docker export
コマンドもDockerのデータをファイルとしてエクスポートしますが、その対象は「コンテナ」であり、「イメージ」ではありません。
docker save
: Dockerイメージをファイルとして保存。イメージのレイヤー構造やメタデータ(Entrypoint, Cmdなどの設定、タグ情報)を含む。複数のイメージや、同じレイヤーを共有するイメージを効率的に保存できる。復元にはdocker load
を使用。docker export
: 実行中の、あるいは停止中のDockerコンテナのファイルシステムのスナップショットをファイルとして保存。コンテナの書き込み可能なレイヤーの内容のみを含む。レイヤー構造やイメージのメタデータは含まれない。復元にはdocker import
を使用し、これは元のイメージではなく、単一レイヤーの新しいイメージとしてロードされる。
使い分け:
* イメージそのもの(レイヤー構造、設定、タグなど)を別の環境に移動・バックアップしたい場合はdocker save
。
* 特定のコンテナの状態(実行中にファイルシステムに行った変更など)をファイルシステムとして保存したい場合はdocker export
。ただし、コンテナの状態を保存する場合は、通常はデータボリュームを使う方が推奨されます。docker export
は、特定のツールや設定が施されたコンテナのスナップショットを、単一のファイルシステムイメージとして取得したい場合に限定的に使われます。
7.2. Docker RegistryへのPushとの違い
Docker Registry(Docker Hub, Quay.io, GCR, ECR, ACR, HarborなどのプライベートRegistry)へのPushは、最も一般的で推奨されるイメージ配布方法です。
- Registry Push: オンラインでイメージを共有・配布するための標準的な方法。認証機構があり、バージョン管理機能やWebhookなどのCI/CD連携機能が豊富。Pull時には差分転送が行われるため効率が良い。Registryサーバーの運用が必要(パブリックRegistryを使う場合はその限りではない)。インターネット接続が必須。
docker save
: オフラインでのイメージ配布・保管に適した方法。Registryサーバーは不要。ファイル転送手段さえあればどこへでも持ち運べる。認証やバージョン管理機能はファイルシステムに依存する。ファイルサイズは通常Registry経由よりも大きくなる傾向がある(メタデータなどが全て含まれるため)。
使い分け:
* インターネットに接続された環境で、複数の開発者やサーバー間でイメージを継続的に共有・管理する場合は、RegistryへのPushが最適です。
* インターネット接続がない環境、特定の時点のイメージを確実にオフライン保管したい、プライベートなイメージをRegistryなしで共有したい、といった場合はdocker save
が適しています。
7.3. Dockerfileを使った再ビルドとの違い
Dockerイメージは、Dockerfileというテキストファイルに書かれた手順に従ってdocker build
コマンドでビルドされるのが本来の方法です。
- Dockerfile &
docker build
: イメージのソースコードからイメージを再生成する方法。Dockerfileを見ればイメージの構成手順が明確で、変更管理が容易。様々な環境で再現性の高いビルドが可能。ただし、ビルドにはソースコードや依存関係のダウンロード、コンパイルなどの時間が必要。ビルドを実行する環境によって、完全に同一のイメージIDにならない可能性がある(キャッシュやビルド時刻など微妙な差により)。 docker save
/load
: 既存のバイナリイメージをそのままファイルとしてコピーする方法。ビルドは不要なので高速にイメージを準備できる。元のイメージと全く同じイメージID(レイヤー含め)を再現できる(タグは異なる場合あり)。ただし、イメージがどのように作られたか(元のDockerfileやビルド引数など)は、保存ファイルからは直接分からない。
使い分け:
* 開発フェーズやCI/CDパイプラインにおいて、アプリケーションのソースコードからイメージを継続的に生成する場合はdocker build
が基本です。
* ビルド済みイメージを別の環境にそのまま配布したい、ビルド時間を節約したい、特定のビルド結果を確実に再現したい、といった場合はdocker save
/load
が有効です。
8. docker save
を使う上での注意点とトラブルシューティング
docker save
は便利なコマンドですが、使う上でいくつか注意すべき点や、遭遇しうるトラブルがあります。
8.1. 保存先のディスク容量
Dockerイメージは特に大きなものになると、数GBや十数GBになることも珍しくありません。docker save
で出力されるtarファイルも、そのイメージサイズに比例して大きくなります。保存を実行する前に、保存先のディスクに十分な空き容量があるか確認してください。容量不足の場合、コマンドがエラーで終了するか、不完全なファイルが生成される可能性があります。
8.2. 大きなイメージの保存・ロードにかかる時間
イメージサイズが大きい場合、docker save
やdocker load
の実行にはかなりの時間がかかることがあります。特に、HDDなどI/O性能が低いストレージを使用している場合、完了まで数十分かかることもあります。また、ネットワーク経由でファイルを転送する場合、ネットワーク帯域幅がボトルネックになることもあります。これらの時間を考慮して計画を立てる必要があります。
8.3. 複数のイメージを保存した場合のファイルサイズ
複数のイメージを一つのtarファイルにまとめて保存した場合、ファイルサイズは単純な合計よりも小さくなることがあります。これは、複数のイメージが共通のベースレイヤーを持っている場合、そのレイヤーデータがファイル内で重複して保存されるわけではない(正確には、tarファイル内の各レイヤーディレクトリは個別のファイルとして存在しますが、物理的なコピーは効率化されているか、あるいはロード時にDockerが重複を検知して最適化します)ためです。しかし、それでも含まれる全レイヤーの合計に近いサイズになることが一般的です。
8.4. 互換性に関する考慮事項
基本的に、docker save
で作成されたイメージファイルは、異なるバージョンのDockerエンジン間でも高い互換性があります。古いバージョンのDockerで保存したイメージを新しいバージョンのDockerでロードすることは、通常問題ありません。新しいバージョンのDockerで保存したイメージを古いバージョンのDockerでロードする場合も、新しいバージョンの機能に依存する要素(例えば、新しいイメージ形式など)がなければ互換性は保たれることが多いです。
ただし、Dockerの基盤となるイメージ形式やストレージドライバは進化しているため、古いDockerバージョンでロードする際に警告が出たり、一部のメタデータが正しく扱われなかったりする可能性はゼロではありません。特に、Multi-archイメージ(複数のCPUアーキテクチャに対応したイメージ)を保存する場合、ロードするDocker環境のアーキテクチャに対応した部分が正しく扱われるか確認が必要です。基本的には、保存元とロード先のDockerバージョンを合わせておくか、ロード先を新しいバージョンにしておくのが最も安全です。
8.5. tarファイルが壊れた場合の対処法
保存中にプロセスが中断されたり、ファイル転送中にデータが破損したりすると、生成されたtarファイルが壊れる可能性があります。壊れたファイルをdocker load
しようとすると、エラーメッセージが表示されてロードに失敗します。
ファイルが壊れているか確認するには、tar
コマンドのt
オプション(リスト表示)とv
オプション(詳細表示)、f
オプション(ファイル指定)を組み合わせて試すことができます。
bash
tar tvf my_image.tar
もしファイルが破損していなければ、ファイルに含まれるファイルやディレクトリのリストが表示されます。破損している場合は、エラーメッセージが表示されるか、途中で停止します。ファイルが壊れている場合は、残念ながらそのファイルからイメージを復元することは難しく、再度docker save
からやり直す必要があります。
8.6. セキュリティに関する考慮事項
docker save
で保存されたファイルは、イメージの完全な複製です。これには、アプリケーションコード、設定ファイル、ミドルウェアなどが含まれます。機密情報(パスワード、APIキー、証明書など)がイメージ内にハードコーディングされている場合、保存されたファイルからこれらの情報が漏洩するリスクがあります。
- イメージに機密情報を含めない: ビルド時に機密情報をイメージに含めるのではなく、実行時に環境変数やシークレットとして渡すようにアプリケーションを設計してください。
- 保存ファイルの保護: 保存されたtarファイルは、機密性の高いデータを含む可能性があるため、アクセス権限を適切に設定し、不要になったら安全に削除するなど、厳重に管理してください。可能であれば、ファイルを暗号化して保存・転送することを検討してください。
8.7. タグやリポジトリ名の管理
docker load
でイメージを復元する際、保存ファイルに含まれるmanifest.json
などのメタデータに基づいて、元のリポジトリ名とタグ名が再作成されます。
もし、ロード先のDockerデーモンに同じリポジトリ名とタグ名を持つ別のイメージが既に存在する場合、新しくロードされたイメージがそのタグを引き継ぎ、元々そのタグを持っていた既存のイメージはタグなしの状態(<none>:<none>
)になることがあります。これは意図しない結果を招く可能性があるため、ロード前に既存のイメージを確認したり、必要に応じて既存イメージのタグを変更したり削除したりすることを検討してください。
また、複数のイメージを一つのファイルに保存した場合、ロードされるイメージの順番は保証されない可能性があります。特定のタグを持つイメージが正しくロードされたか、ロード後にdocker images
で確認することが重要です。
9. docker save
の応用例
これまでに解説した内容を踏まえ、docker save
コマンドが具体的にどのようなシナリオで役立つか、より詳細な応用例を見ていきましょう。
9.1. エアギャップ環境(インターネット接続がない環境)へのデプロイ
これはdocker save
/load
の最も強力なユースケースの一つです。
- 外部ネットワーク環境でイメージを準備:
- 必要なDockerイメージ(OSベースイメージ、ミドルウェア、自社アプリケーションイメージなど)をインターネット経由で
docker pull
またはdocker build
で取得・作成します。 - 必要な全てのイメージがローカルのDockerデーモンに存在することを確認します (
docker images
)。
- 必要なDockerイメージ(OSベースイメージ、ミドルウェア、自社アプリケーションイメージなど)をインターネット経由で
- イメージをファイルに保存:
- 必要な全てのイメージをまとめて
docker save
で一つのtarファイルに保存します。 docker save -o offline_images.tar.gz image1:tagA image2:tagB ... | gzip
- 大きなファイルになる場合は、必要に応じて分割・圧縮します。
- 必要な全てのイメージをまとめて
- ファイルをエアギャップ環境へ転送:
- 保存したtar.gzファイルをUSBメモリ、外部HDD、DVD、あるいは限定的なネットワーク経路(例: セキュアなファイル転送プロトコル)を使ってエアギャップ環境に持ち込みます。
- エアギャップ環境でイメージをロード:
- 持ち込んだファイルをエアギャップ環境内のサーバーにコピーします。
docker load -i offline_images.tar.gz
(圧縮している場合はgunzip -c offline_images.tar.gz | docker load
)を実行してイメージを復元します。docker images
でイメージが正しくロードされたか確認します。
- コンテナを起動:
- ロードしたイメージを使って、通常通り
docker run
コマンドでコンテナを起動し、アプリケーションをデプロイします。
- ロードしたイメージを使って、通常通り
この手順により、インターネット接続なしにDockerアプリケーションを展開できます。セキュリティ要件の高い環境や、ネットワークインフラが整備されていない場所でのデプロイに不可欠な手法です。
9.2. 過去の特定のバージョンのイメージを保管
アプリケーションのリリースごとに、使用したDockerイメージを永続的に保管しておきたい場合があります。Registryに全てのバージョンをプッシュすることも可能ですが、Registryのストレージ容量が限られている場合や、特定の重要なバージョンだけを確実にオフラインで手元に置いておきたい場合があります。
リリースが確定したタイミングで、使用されたアプリケーションイメージとその依存イメージの一部(変更頻度が低いものなど)をdocker save
で保存し、長期保管用のストレージ(テープアーカイブ、オフラインストレージなど)に移動します。
“`bash
例: リリース v1.5 で使用したイメージを保存
docker save -o myapp_release_v1.5.tar.gz myapp:v1.5 baseimage:2.0 library:1.2 | gzip
“`
これにより、将来的に特定のリリースの環境を完全に再現する必要が生じた際(例: 過去の不具合の調査、顧客環境での問題再現など)、Registryの状態に依存せずに、この保存ファイルから当時のイメージを正確に復元できます。
9.3. ステージング環境から本番環境へのイメージ配布
CI/CDパイプラインにおいて、ステージング環境でテストが完了したイメージを、そのままの形で本番環境にデプロイしたい場合があります。通常はRegistryを経由しますが、Registryへのアクセス権限がステージング環境と本番環境で異なる場合や、本番環境へのデプロイ手順にファイル転送が含まれる場合など、docker save
が有効な選択肢となることがあります。
- ステージング環境でイメージをビルド・テスト: CI/CDパイプライン上でイメージをビルドし、ステージング環境にデプロイしてテストを実行します。
- テスト済みのイメージを保存: テストが成功したイメージをステージングサーバー上で
docker save
コマンドでファイルに保存します。 - ファイルを本番環境へ転送: 保存したファイルをステージング環境から本番環境へセキュアな手段(SCP, RSYNC over SSHなど)で転送します。
- 本番環境でイメージをロード: 本番環境サーバー上で、転送されたファイルを
docker load
でロードします。 - 本番環境へデプロイ: ロードしたイメージを使って、本番環境にアプリケーションをデプロイします。
このフローは、Registryサーバーの負担を軽減したい場合や、特定のファイル転送ワークフローが既に確立している場合に適しています。
9.4. CI/CDパイプラインでの一時的な保存/転送
複雑なビルドプロセスや多段階のテストが必要なCI/CDパイプラインにおいて、中間生成物であるDockerイメージを効率的に受け渡ししたい場合があります。例えば、ビルドジョブでイメージを作成し、そのイメージをRegistryにプッシュする前に、別のジョブでセキュリティスキャンを実行したい場合などです。
- ビルドジョブ: イメージをビルドし、一時的なタグを付けます。そのイメージを
docker save
でファイルに保存します。
bash
docker build -t temp_image:$BUILD_ID .
docker save -o temp_image_$BUILD_ID.tar temp_image:$BUILD_ID - アーティファクトとして保存: CI/CDツール(Jenkins, GitLab CI, GitHub Actionsなど)の機能を使って、生成された
temp_image_$BUILD_ID.tar
ファイルをビルドアーティファクトとして保存します。 - スキャンジョブ: 次のジョブで、前のジョブのアーティファクトである
temp_image_$BUILD_ID.tar
ファイルをダウンロードします。ダウンロードしたファイルをdocker load
でDockerデーモンにロードします。
bash
docker load -i temp_image_$BUILD_ID.tar
ロードしたイメージに対してセキュリティスキャンツールを実行します。 - プッシュ/デプロイジョブ: スキャンが成功したら、そのイメージに正式なタグ(例:
myapp:v1.2.3
)を付け、Registryにプッシュしたり、ターゲット環境にデプロイしたりします。
この方法を使うと、Registryへのプッシュ/プルを繰り返すよりも、中間生成物の受け渡しが高速になる場合があります。また、一時的なイメージをRegistryに残さずに済むため、Registryをクリーンに保つことができます。
10. docker save
の代替手段
docker save
/load
は強力ですが、全てのケースに最適なわけではありません。状況によっては、以下の代替手段を検討すべきです。
10.1. プライベートDocker Registryの構築・利用
インターネットに公開したくないプライベートなイメージを複数ユーザー・複数サーバー間で共有する場合、最も推奨される方法はプライベートDocker Registryを構築・利用することです。
- メリット:
- 集中管理が可能で、どのイメージがどこにあるか管理しやすい。
- Pull時に差分転送が行われるため、ネットワーク帯域幅を節約できる。
- 認証・認可の仕組みにより、アクセスを制限できる。
- WebhookなどによるCI/CD連携機能が豊富。
- バージョン管理やタグ付けルールを確立しやすい。
- デメリット:
- Registryサーバーの構築・運用が必要。
- エアギャップ環境など、Registryへのネットワーク接続が困難な環境では利用できない。
Open SourceのHarborやDocker Registry、あるいはクラウドプロバイダー(AWS ECR, GCP GCR/Artifact Registry, Azure ACRなど)が提供するマネージドRegistryサービスがあります。
10.2. Registry Mirrorの利用
社内ネットワークなどにRegistry Mirrorを設置することで、外部Registryからのイメージ取得を高速化・安定化できます。Registry Mirrorは外部Registryのキャッシュとして機能し、一度PullしたイメージはローカルのMirrorから取得されるようになります。
これはdocker save
の代替というよりは、外部Registryへの依存性を軽減し、イメージ配布の効率を向上させるための手段です。エアギャップ環境では利用できません。
10.3. HelmやOperatorなどのデプロイツールによるイメージ管理
Kubernetesなどのコンテナオーケストレーションプラットフォームでは、HelmチャートやOperatorのようなツールを使ってアプリケーションをデプロイするのが一般的です。これらのツールは通常、デプロイ対象のイメージをRegistryからPullすることを前提としています。
これらのツールを利用している環境でイメージを配布する場合、docker save
/load
でホストにイメージをロードするよりも、RegistryにイメージをPushし、デプロイツールがRegistryからイメージをPullするように構成する方が、ツールとの連携がスムーズで運用も効率的です。エアギャップ環境向けには、ローカルRegistryを構築し、そこにdocker save
/load
でイメージをロードしてから、ローカルRegistryを参照するようにデプロイツールを設定するといった運用が考えられます。
11. まとめ:docker save
を安全に、賢く使いこなすために
本記事では、docker save
コマンドについて、その基本的な使い方から技術的な詳細、実践的な応用例、注意点、そして他の方法との比較まで、幅広く解説しました。
docker save
コマンドは、Dockerイメージをファイルとして保存する強力なツールです。特にインターネット接続が制限された環境でのイメージ配布や、特定の時点のイメージを確実にオフラインで保管したい場合に、その真価を発揮します。イメージのレイヤー構造やメタデータを含めて保存するため、docker load
コマンドを使えば、元のDocker環境に忠実にイメージを復元できます。
しかし、docker save
にはいくつかの注意点もあります。生成されるファイルのサイズが大きくなること、保存・ロードに時間がかかる場合があること、そしてセキュリティ上の考慮(ファイル自体の保護)などです。これらの点を理解し、適切に対処することが、docker save
を安全に、そして効果的に活用するための鍵となります。
docker save
を賢く使うためのヒント:
- ユースケースを明確にする: RegistryへのPushが難しい、あるいは適さない特定のシナリオでのみ
docker save
を利用する。 - 保存対象を限定する: 必要なイメージだけを選択して保存し、ファイルサイズを最小限に抑える。
- 圧縮を活用する: 大きなイメージを保存する際は、gzipなどのツールと組み合わせてファイルサイズを削減し、転送を効率化する。
- セキュリティを確保する: 保存されたファイルは機密情報を含む可能性があるため、アクセス制限や暗号化など、適切なセキュリティ対策を講じる。
- バージョン管理と整合性の確認: ロード後に
docker images
でイメージが正しく復元されたか、意図したタグが付いているか必ず確認する。 - スクリプトで自動化: 定期的なバックアップなど、繰り返しの作業はシェルスクリプトなどで自動化し、ヒューマンエラーを防ぐ。
docker save
コマンドは、Registryを中心としたイメージ管理を補完する、非常に有用なツールです。この記事を通じて、その機能と限界を深く理解し、あなたのDockerワークフローの中で安全かつ効果的に活用していただければ幸いです。
Dockerイメージの管理は、安定したアプリケーション運用に不可欠な要素です。docker save
をあなたのツールキットに加え、より堅牢で柔軟なシステムを構築していきましょう。