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
ちなみにこの image id、最初は digest と混同してて SHA-256 かと思ってたけど 256 bit の UUID らしい。
Explaining Docker Image IDs
嘘、SHA-256 で計算してあるって書いてあった。
適当に展開するとこうなる。
合計 116476
drwxrwxr-x 4 kirisaki docker 4096 1月 20 23:12 .
drwxrwxr-x 11 kirisaki docker 4096 1月 20 22:10 ..
-rw-r--r-- 1 kirisaki docker 1759 1月 20 22:30 04ba6f024535a145eb2ae8e15623ade99d58dacff1218f7bff6b7e6b4ecc3d5f.json
drwxr-xr-x 2 kirisaki docker 4096 1月 20 22:30 6e02e5eac0b0969b0c6fbc392c0301bf0dffc180dd95efb70309cde476ed0d36
-rw-rw-r-- 1 kirisaki docker 49 1月 20 22:11 Dockerfile
drwxr-xr-x 2 kirisaki docker 4096 1月 20 22:30 b18fcdaad09d0e220b99d0a164445c49d20806c6a1bbbee4f309fdb7dfff270e
-rw-r--r-- 1 kirisaki docker 266 1月 1 1970 manifest.json
-rw------- 1 kirisaki docker 119236608 1月 20 22:36 nyaan.tar
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 から見ていこう。
{
"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 1月 20 22:30 .
drwxrwxr-x 4 kirisaki docker 4096 1月 20 23:12 ..
-rw-r--r-- 1 kirisaki docker 3 1月 20 22:30 VERSION
-rw-r--r-- 1 kirisaki docker 1231 1月 20 22:30 json
-rw-r--r-- 1 kirisaki docker 1536 1月 20 22:30 layer.tar
layer.tar
以外になんか二つ出てきた。VERSION
は 1.0
と書かれているだけだったので無視でよいと思う。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 は
{
"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
は展開したら大変なことになった。おしまい。