これを知れば安心!docker saveコマンドでDockerイメージを安全に保存

はい、承知いたしました。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:latestmyapp: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.0myapp: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.jsonrepositoriesファイルを解析し、イメージの構造とメタデータを把握します。

次に、tarファイルに含まれる各レイヤーのlayer.tarを展開し、それぞれのレイヤーデータをDockerのストレージドライバを使って格納します。ストレージドライバは、Union File Systemの仕組みを使ってこれらのレイヤーを管理します。

全てのレイヤーの格納が終わると、manifest.jsonrepositoriesファイルに基づいて、イメージIDを生成し、関連付けられているタグ情報を登録します。このプロセスを経て、docker imagesで新しいイメージが表示されるようになります。

この仕組みにより、docker savedocker 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 savedocker 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の最も強力なユースケースの一つです。

  1. 外部ネットワーク環境でイメージを準備:
    • 必要なDockerイメージ(OSベースイメージ、ミドルウェア、自社アプリケーションイメージなど)をインターネット経由でdocker pullまたはdocker buildで取得・作成します。
    • 必要な全てのイメージがローカルのDockerデーモンに存在することを確認します (docker images)。
  2. イメージをファイルに保存:
    • 必要な全てのイメージをまとめてdocker saveで一つのtarファイルに保存します。
    • docker save -o offline_images.tar.gz image1:tagA image2:tagB ... | gzip
    • 大きなファイルになる場合は、必要に応じて分割・圧縮します。
  3. ファイルをエアギャップ環境へ転送:
    • 保存したtar.gzファイルをUSBメモリ、外部HDD、DVD、あるいは限定的なネットワーク経路(例: セキュアなファイル転送プロトコル)を使ってエアギャップ環境に持ち込みます。
  4. エアギャップ環境でイメージをロード:
    • 持ち込んだファイルをエアギャップ環境内のサーバーにコピーします。
    • docker load -i offline_images.tar.gz (圧縮している場合は gunzip -c offline_images.tar.gz | docker load)を実行してイメージを復元します。
    • docker imagesでイメージが正しくロードされたか確認します。
  5. コンテナを起動:
    • ロードしたイメージを使って、通常通り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が有効な選択肢となることがあります。

  1. ステージング環境でイメージをビルド・テスト: CI/CDパイプライン上でイメージをビルドし、ステージング環境にデプロイしてテストを実行します。
  2. テスト済みのイメージを保存: テストが成功したイメージをステージングサーバー上でdocker saveコマンドでファイルに保存します。
  3. ファイルを本番環境へ転送: 保存したファイルをステージング環境から本番環境へセキュアな手段(SCP, RSYNC over SSHなど)で転送します。
  4. 本番環境でイメージをロード: 本番環境サーバー上で、転送されたファイルをdocker loadでロードします。
  5. 本番環境へデプロイ: ロードしたイメージを使って、本番環境にアプリケーションをデプロイします。

このフローは、Registryサーバーの負担を軽減したい場合や、特定のファイル転送ワークフローが既に確立している場合に適しています。

9.4. CI/CDパイプラインでの一時的な保存/転送

複雑なビルドプロセスや多段階のテストが必要なCI/CDパイプラインにおいて、中間生成物であるDockerイメージを効率的に受け渡ししたい場合があります。例えば、ビルドジョブでイメージを作成し、そのイメージをRegistryにプッシュする前に、別のジョブでセキュリティスキャンを実行したい場合などです。

  1. ビルドジョブ: イメージをビルドし、一時的なタグを付けます。そのイメージをdocker saveでファイルに保存します。
    bash
    docker build -t temp_image:$BUILD_ID .
    docker save -o temp_image_$BUILD_ID.tar temp_image:$BUILD_ID
  2. アーティファクトとして保存: CI/CDツール(Jenkins, GitLab CI, GitHub Actionsなど)の機能を使って、生成されたtemp_image_$BUILD_ID.tarファイルをビルドアーティファクトとして保存します。
  3. スキャンジョブ: 次のジョブで、前のジョブのアーティファクトであるtemp_image_$BUILD_ID.tarファイルをダウンロードします。ダウンロードしたファイルをdocker loadでDockerデーモンにロードします。
    bash
    docker load -i temp_image_$BUILD_ID.tar

    ロードしたイメージに対してセキュリティスキャンツールを実行します。
  4. プッシュ/デプロイジョブ: スキャンが成功したら、そのイメージに正式なタグ(例: 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をあなたのツールキットに加え、より堅牢で柔軟なシステムを構築していきましょう。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール