Edited at

Docker のイメージ/ファイルシステムの形式 (1)

More than 3 years have passed since last update.


はじめに

Docker のイメージやファイルシステムの形式について調べてみました。

Docker のイメージやファイルシステムの形式と言ったとき、次の3つのいずれかを指すと思います。


  1. Docker Hub(または Private Registry) からダウンロードされる Docker イメージの形式

  2. ダウンロードした Docker イメージをホスト上に保存する際の形式。または、docker build コマンドでビルドしたイメージの形式。

  3. コンテナのファイルシステムの形式

今回は 1、つまり docker pull した時に Docker Hub から何がどう落ちてくるのかをまとめてみます。

DockerImages.png

調査環境


  • CentOS 7.1 (カーネル 4.2.1)

  • Docker 1.8.2 (ストレージドライバは overlay)


Docker イメージを構成するもの

Docker イメージは次の2種類のファイルから構成されます。


  • Manifest ファイル

    イメージのメタデータを持つ JSON ファイル。

  • レイヤーファイル

    各レイヤーのディレクトリツリーを含んだ tar.gz ファイル。
    1つのレイヤーに対して、1つの tar.gz が存在する。

例えば、1つの Docker イメージは以下のようなファイル群で表現されます。

DockerImageFiles.png


Manifest ファイル

Manifest ファイルは、Docker イメージに関する次のような情報を含む JSON ファイルです。

(Manifest のフォーマットに関してはここを参照してください)。


  • イメージ名 (例: centos)

  • イメージのタグ名 (例: latest)

  • イメージを構成するレイヤーのリスト

  • 各レイヤーの ID

  • 署名

docker pull <イメージ名> コマンドを実行すると、Docker Engine はまず Manifest ファイルをダウンロードします。 Manifest には、イメージを構成するレイヤーファイルが書かれた fsLayers フィールドがあります。

レイヤーファイルの実体は Docker Hub の Blob という領域に置かれており、Docker Engine は fsLayers を参照し、Blob からレイヤーファイルをダウンロードしていきます。

以下の Manifest の例では、5つのレイヤーファイルからイメージが構成されていることになります。


Manifestファイルの例

{

"schemaVersion": 1,
"name": "library/centos",
"tag": "latest",
"architecture": "amd64",
"fsLayers": [
{ "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" },
{ "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" },
{ "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" },
{ "blobSum": "sha256:c3bf6062f354b9af9db4481f24f488da418727673ea76c5162b864e1eea29a4e" },
{ "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" }
],
"history": [
{ "v1Compatibility": "{\"id\":\"0f73ae75014f435e...\",\"parent\":\"f37e6a610a37349d...\", (中略...)" },
{ "v1Compatibility": "{\"id\":\"f37e6a610a37349d...\",\"parent\":\"f9a8cbc8dd13fb5b...\", (中略...)" },
{ "v1Compatibility": "{\"id\":\"f9a8cbc8dd13fb5b...\",\"parent\":\"f6f39725d938c8ad...\", (中略...)" },
{ "v1Compatibility": "{\"id\":\"f6f39725d938c8ad...\",\"parent\":\"47d44cb6f252ea4f...\", (中略...)" },
{ "v1Compatibility": "{\"id\":\"47d44cb6f252ea4f...\", …" }
],
"signatures": [ "中略..." ]
}

なお、レイヤー間の親子関係は、Manifest の history に書かれています。

また、Manifest とレイヤーファイルの URL は以下のようになります(Docker Registry HTTP API V2 の場合)。


レイヤーファイル

Docker Engine はダウンロードしたレイヤーファイルを /var/lib/docker/tmp に一時的に置きます。

今回試した centos:latest のイメージは 5つのレイヤーから構成されているため、以下のように 5つのレイヤーファイルがダウンロードされています。

[root@centos7 tmp]# pwd

/var/lib/docker/tmp
[root@centos7 tmp]# ls -al
total 61460
drwx------. 2 root root 4096 Oct 3 06:32 .
drwx------. 9 root root 4096 Oct 3 06:32 ..
-rw-------. 1 root root 32 Oct 3 06:32 GetImageBlob068882538
-rw-------. 1 root root 32 Oct 3 06:32 GetImageBlob561232172
-rw-------. 1 root root 32 Oct 3 06:32 GetImageBlob568501953
-rw-------. 1 root root 62906573 Oct 3 06:32 GetImageBlob621683063
-rw-------. 1 root root 32 Oct 3 06:32 GetImageBlob747002488

(補足) これらのファイルは通常はすぐに削除されるため、削除されないように Docker のソースを修正して調査しています。

GetImageBlobXXX ファイルの実体は tar.gz です。中身は何かというと、ディレクトリツリーが含まれています。GetImageBlob621683063~~という0バイトのファイルが複数含まれてますが理由は分かりません。

LayerFile.png

Docker Engine は、このように /var/lib/docker/tmp にレイヤーファイルをダウンロードした後は、ストレージドライバ(AUFS, devicemapper, overlay など)を使いイメージをホストに保存していきます。


最後に

今回は、docker pull する際に、何がどうダウンロードされるかを調べてみました。あくまで Docker Hub からダウンロードされる際の形式なので、まだ Docker Engine のストレージドライバからは独立した段階です。

次回は、ダウンロードした Docker イメージが、Linux ホスト上でどのような形式で保存されるかをまとめてみます。


参考サイト