Closed11

docker イメージの中身を見る

霧咲空人霧咲空人

docker save -o <filename> <image_id> で docker image が tar で取ってこれる。

霧咲空人霧咲空人

docker build | Docker Documentation

docker build --output type=tar,dest=<path> .

でもいけるらしい。ただわたしの docker(Docker version 20.10.2, build 2291f61)では DOCKER_BUILDKIT=1 にしておかないといけなかったけど。オプションのパースは通るのに機能は走らない。そういうとこやぞ!docker!

霧咲空人霧咲空人

試しに以下のような Dockerfile をビルドする。

FROM debian
RUN touch /foo
CMD ["echo", "nyaan"]
$ docker build -t kirisaki/nyaan:1.0 .

別にタグとか真面目に付けなくてよい(digest について調べてたときの名残)。

REPOSITORY                   TAG                IMAGE ID       CREATED          SIZE
kirisaki/nyaan               1.0                04ba6f024535   44 minutes ago   114MB

無事ビルドできたので取り出す。

$ docker save -o nyaan.tar 04ba6f024535
霧咲空人霧咲空人

適当に展開するとこうなる。

合計 116476
drwxrwxr-x  4 kirisaki docker      4096  120 23:12 .
drwxrwxr-x 11 kirisaki docker      4096  120 22:10 ..
-rw-r--r--  1 kirisaki docker      1759  120 22:30 04ba6f024535a145eb2ae8e15623ade99d58dacff1218f7bff6b7e6b4ecc3d5f.json
drwxr-xr-x  2 kirisaki docker      4096  120 22:30 6e02e5eac0b0969b0c6fbc392c0301bf0dffc180dd95efb70309cde476ed0d36
-rw-rw-r--  1 kirisaki docker        49  120 22:11 Dockerfile
drwxr-xr-x  2 kirisaki docker      4096  120 22:30 b18fcdaad09d0e220b99d0a164445c49d20806c6a1bbbee4f309fdb7dfff270e
-rw-r--r--  1 kirisaki docker       266  11  1970 manifest.json
-rw-------  1 kirisaki docker 119236608  120 22:36 nyaan.tar
霧咲空人霧咲空人

manifest.json が一番人間に優しそうな名前をしているので開く。

manifest.json
[
  {
    "Config": "04ba6f024535a145eb2ae8e15623ade99d58dacff1218f7bff6b7e6b4ecc3d5f.json",
    "RepoTags": null,
    "Layers": [
      "6e02e5eac0b0969b0c6fbc392c0301bf0dffc180dd95efb70309cde476ed0d36/layer.tar",
      "b18fcdaad09d0e220b99d0a164445c49d20806c6a1bbbee4f309fdb7dfff270e/layer.tar"
    ]
  }
]

ID ばっかであんま優しくなかった。Config がこの image 自体の設定(ファイル名と image ID が一致するので上に戻って見比べてほしい)。Layers というのは image の集合体。
About storage drivers | Docker Documentation
詳しくは公式のドキュメントに譲るが、docker image というのはファイルが入った image を層のように重ねて作られており、それを layer と呼んでいる。

霧咲空人霧咲空人

Config に書いてある json から見ていこう。

04ba6f024535a145eb2ae8e15623ade99d58dacff1218f7bff6b7e6b4ecc3d5f.json
{
  "architecture": "amd64",
  "config": {
    "Hostname": "",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": [
      "echo",
      "nyaan"
    ],
    "Image": "sha256:ce67ee3ec050b12f8aa00c03410fa4577cfe9a18145202c8b14f25d1e0537ad1",
    "Volumes": null,
    "WorkingDir": "",
    "Entrypoint": null,
    "OnBuild": null,
    "Labels": null
  },
  "container": "76f200d24fec6499c63b9ace40f2efbec0357d9f83f0e31c92c2e08ccd772882",
  "container_config": {
    "Hostname": "76f200d24fec",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": [
      "/bin/sh",
      "-c",
      "#(nop) ",
      "CMD [\"echo\" \"nyaan\"]"
    ],
    "Image": "sha256:ce67ee3ec050b12f8aa00c03410fa4577cfe9a18145202c8b14f25d1e0537ad1",
    "Volumes": null,
    "WorkingDir": "",
    "Entrypoint": null,
    "OnBuild": null,
    "Labels": {}
  },
  "created": "2021-01-20T13:30:49.936230187Z",
  "docker_version": "20.10.2",
  "history": [
    {
      "created": "2020-12-11T02:05:52.252977647Z",
      "created_by": "/bin/sh -c #(nop) ADD file:6014cd9d7466825f80d4a3345847efd6fd7ef600b8135811cab4f0e304f66cd7 in / "
    },
    {
      "created": "2020-12-11T02:05:52.632610226Z",
      "created_by": "/bin/sh -c #(nop)  CMD [\"bash\"]",
      "empty_layer": true
    },
    {
      "created": "2021-01-20T13:30:49.856473598Z",
      "created_by": "/bin/sh -c touch /foo"
    },
    {
      "created": "2021-01-20T13:30:49.936230187Z",
      "created_by": "/bin/sh -c #(nop)  CMD [\"echo\" \"nyaan\"]",
      "empty_layer": true
    }
  ],
  "os": "linux",
  "rootfs": {
    "type": "layers",
    "diff_ids": [
      "sha256:f0e10b20de190c7cf4ea7ef410e7229d64facdc5d94514a13aa9b58d36fca647",
      "sha256:d0cb884e1ad9503cfa1113b44b6d37c97acb588d77ca56535d9686849ca88fa2"
    ]
  }
}

ちょっと調べたんだけと Image にはこの json 自体の SHA-256 が入るらしい……んだけど計算が合わない。多分 digest 周り調べてたときに build し直したかもしれない。おのれ。container はどうやって決まるんだろう……。ソースコードを読みにいってます。Cmd とか見ると Dockerfile で書いた内容が見えてきます。

そして history を見ると /bin/bash とかも書いてあるんで debian のイメージの内容も入ってることがわかります……が、最終的に

ADD file:6014cd9d7466825f80d4a3345847efd6fd7ef600b8135811cab4f0e304f66cd7 in /

というところにたどり着きこれ以上遡ることは出来ません。docker history でも <missing> ってでてくるやーつですね。

IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
04ba6f024535   2 hours ago   /bin/sh -c #(nop)  CMD ["echo" "nyaan"]         0B        
ce67ee3ec050   2 hours ago   /bin/sh -c touch /foo                           0B        
6d6b00c22231   5 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      5 weeks ago   /bin/sh -c #(nop) ADD file:6014cd9d7466825f8…   114MB  

ドキュメントを見ると

Note: The <missing> lines in the docker history output indicate that those layers were built on another system and are not available locally. This can be ignored.
About storage drivers | Docker Documentation

docker 以外のシステムでビルドされたイメージだから無視せーよと言ってますね。そういえばそんなことが出来たなと「docker image build alternatives」でググると Kaniko とか色々出てきます。これらでビルドされたイメージはローカルでのそのファイルの digest しか載せられない、とかそんな感じなのだろうか。今度試してみよう。

diff_ids は簡単ですね。各レイヤーの layer.tar の SHA-256 です。

霧咲空人霧咲空人

container はどうやって決まるんだろう……。

そうか、docker って image build するのに container 立ててその中で実行するのか。だからその ID か。なるほどー。

霧咲空人霧咲空人

d0cb884e1ad9503cfa1113b44b6d37c97acb588d77ca56535d9686849ca88fa2 ディレクトリを先に見る。Layer の後ろのほうがあとから作られたものである、という予想のもとである(答え知ってんだけどね)。

drwxr-xr-x 2 kirisaki docker 4096  120 22:30 .
drwxrwxr-x 4 kirisaki docker 4096  120 23:12 ..
-rw-r--r-- 1 kirisaki docker    3  120 22:30 VERSION
-rw-r--r-- 1 kirisaki docker 1231  120 22:30 json
-rw-r--r-- 1 kirisaki docker 1536  120 22:30 layer.tar

layer.tar 以外になんか二つ出てきた。VERSION1.0 と書かれているだけだったので無視でよいと思う。json はこんな感じ。

json
{
  "id": "b18fcdaad09d0e220b99d0a164445c49d20806c6a1bbbee4f309fdb7dfff270e",
  "parent": "6e02e5eac0b0969b0c6fbc392c0301bf0dffc180dd95efb70309cde476ed0d36",
  "created": "2021-01-20T13:30:49.936230187Z",
  "container": "76f200d24fec6499c63b9ace40f2efbec0357d9f83f0e31c92c2e08ccd772882",
  "container_config": {
    "Hostname": "76f200d24fec",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": [
      "/bin/sh",
      "-c",
      "#(nop) ",
      "CMD [\"echo\" \"nyaan\"]"
    ],
    "Image": "sha256:ce67ee3ec050b12f8aa00c03410fa4577cfe9a18145202c8b14f25d1e0537ad1",
    "Volumes": null,
    "WorkingDir": "",
    "Entrypoint": null,
    "OnBuild": null,
    "Labels": {}
  },
  "docker_version": "20.10.2",
  "config": {
    "Hostname": "",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": [
      "echo",
      "nyaan"
    ],
    "Image": "sha256:ce67ee3ec050b12f8aa00c03410fa4577cfe9a18145202c8b14f25d1e0537ad1",
    "Volumes": null,
    "WorkingDir": "",
    "Entrypoint": null,
    "OnBuild": null,
    "Labels": null
  },
  "architecture": "amd64",
  "os": "linux"
}

一つ前の json とだいたい似たようなことが書いてあるけど、これにはわたしが Dockerfile に書いたことしか書いてない。レイヤーが分かれている証拠。

そして layer.tar を展開すると……

 % tar -xvf layer.tar                                                 
foo

touch で作った foo が出てきた!こんな感じで差分だけレイヤーとしてまとめられているのである。

霧咲空人霧咲空人

ちなみにもう一つのレイヤー(debian)の json は

json
{
  "id": "6e02e5eac0b0969b0c6fbc392c0301bf0dffc180dd95efb70309cde476ed0d36",
  "created": "1970-01-01T09:00:00+09:00",
  "container_config": {
    "Hostname": "",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": null,
    "Cmd": null,
    "Image": "",
    "Volumes": null,
    "WorkingDir": "",
    "Entrypoint": null,
    "OnBuild": null,
    "Labels": null
  },
  "os": "linux"
}

めっちゃ寂しい。layer.tar は展開したら大変なことになった。おしまい。

このスクラップは2021/01/21にクローズされました