Open6

OCI

Kota UENISHIKota UENISHI

参考

関連

ツール・ライブラリ

Kota UENISHIKota UENISHI

仕様読んでみたけど、よくわからないので実物を見てみることに
まずは適当なものをファイルにして持ってくる

$ docker save --output ubuntu-docker.tar ubuntu:latest
$ tar tf ubuntu-docker.tar
blobs/
blobs/sha256/
blobs/sha256/3f4714ee068a59a09d9e77de71ec1254e5916d6e5779140bc96cec7d0edea18d
blobs/sha256/53dc5b2baa3b80cddf87c2877dec90e123ddf119189157a550822292a2ad8792
blobs/sha256/9472b7b49c37b675e7e17c23dbec1d1476c2af093d8cdf6f66447fa18643d910
blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d
index.json
manifest.json
oci-layout
repositories

index.json がIndexっぽいのでみてみる

{
    "schemaVersion": 2,
    "mediaType": "application/vnd.oci.image.index.v1+json",
    "manifests": [
        {
            "mediaType": "application/vnd.oci.image.manifest.v1+json",
            "digest": "sha256:53dc5b2baa3b80cddf87c2877dec90e123ddf119189157a550822292a2ad8792",
            "size": 402,
            "annotations": {
                "io.containerd.image.name": "docker.io/library/ubuntu:latest",
                "org.opencontainers.image.ref.name": "latest"
            }
        }
    ]
}

こうやってみると大きいのはひとつだけ

$ ls -l blobs/sha256/
total 78468
-rw-r--r-- 1 kuenishi kuenishi     1463 Apr 22  2022 3f4714ee068a59a09d9e77de71ec1254e5916d6e5779140bc96cec7d0edea18d
-rw-r--r-- 1 kuenishi kuenishi      402 Jan  1  1970 53dc5b2baa3b80cddf87c2877dec90e123ddf119189157a550822292a2ad8792
-rw-r--r-- 1 kuenishi kuenishi     1138 Apr 22  2022 9472b7b49c37b675e7e17c23dbec1d1476c2af093d8cdf6f66447fa18643d910
-rw-r--r-- 1 kuenishi kuenishi 80335360 Apr 22  2022 b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d

これがイメージ本体(?)だろうということで覗くと

$ file blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d
blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d: POSIX tar archive
$ tar tf blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d | head
bin
boot/
dev/
etc/
etc/.pwd.lock
etc/adduser.conf
etc/alternatives/
etc/alternatives/README
etc/alternatives/awk
etc/alternatives/nawk
$ tar tf blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d | tail
var/log/dpkg.log
var/log/faillog
var/log/lastlog
var/log/wtmp
var/mail/
var/opt/
var/run
var/spool/
var/spool/mail
var/tmp/
$ tar tf blobs/sha256/b401a928648a77a9d167b6aa775519af3b6ab1e710977b49971de76d9b30570d | wc
   3516    3516  130621

最小のUbuntuがまるごと入っていて、ディレクトリとファイルあわせて3500ちょいある
圧縮とかは特にされていない(速度を気にしているからかな

Kota UENISHIKota UENISHI

もうひとつ distroless というやつも見てみる

$ docker pull gcr.io/distroless/static-debian12:latest-amd64
latest-amd64: Pulling from distroless/static-debian12
Digest: sha256:fd92c3ad6367e38449ee4547ba87473d87a693d272d8670e326c585c29fa25f2
Status: Image is up to date for gcr.io/distroless/static-debian12:latest-amd64
gcr.io/distroless/static-debian12:latest-amd64
$ docker save --output distroless.tar gcr.io/distroless/static-debian12:latest-amd64
$ tar tf distroless.tar
blobs/
blobs/sha256/
blobs/sha256/0a05ce3c4ca6f726d0a42fabe1f0de66ec79a07d35777e747f4a4eccd8b9fa1f
blobs/sha256/1a73b54f556b477f0a8b939d13c504a3b4f4db71f7a09c63afbc10acb3de5849
blobs/sha256/2a92d6ac9e4fcc274d5168b217ca4458a9fec6f094ead68d99c77073f08caac1
blobs/sha256/33a9c1fe1b9de747b36f27e8a41275eaec26f91acee572e8ba7e79b05bb00aeb
blobs/sha256/4d049f83d9cf21d1f5cc0e11deaf36df02790d0e60c1a3829538fb4b61685368
blobs/sha256/5010c1191169bde1fbcb9ec86c559981da5d6de79883987ae2a56678a1a43226
blobs/sha256/5d7d2b4256071447af7ff304af79cc961e7e2fb862009ece2c10fc25cebd16e6
blobs/sha256/6f1cdceb6a3146f0ccb986521156bef8a422cdbb0863396f7f751f575ba308f4
blobs/sha256/7a68c38227c001989853bc772842e8da74761fc32ba28c1cbb00b29e71f28ff0
blobs/sha256/7aa6c86e10a86924a65d7cc7002ecc12bfc19d79f1d30b83e26687b99078c920
blobs/sha256/8fa10c0194df9b7c054c90dbe482585f768a54428fc90a5b78a0066a123b1bba
blobs/sha256/93dbdfde69bd85b4b4187a74e341e29a3004de6794197aab4e0affd87201be51
blobs/sha256/a80545a98dcd0866ae5eeadc9a28dec703b1e54a01ce8ff245e83f48261fe575
blobs/sha256/af5aa97ebe6ce1604747ec1e21af7136ded391bcabe4acef882e718a87c86bcc
blobs/sha256/b056cd32692b05422119ec8391ac02bec605a44227924472578fb5fd508fedd3
blobs/sha256/b336e209998fa5cf0eec3dabf93a21194198a35f4f75612d8da03693f8c30217
blobs/sha256/bbb6cacb8c82e4da4e8143e03351e939eab5e21ce0ef333c42e637af86c5217b
blobs/sha256/c1eef4bd174742a2115299a933d8db660484d90791ced98a07b21e4da586ec05
blobs/sha256/c3bac019063b593deec8ba23e76395a46bb6381684bb731108016c736e0d0bf0
blobs/sha256/c65596a257a4a8ffe03bdc7ccfdfdc8f652d674d588aa7f7cd00a8e93be2ddeb
blobs/sha256/d874ff488fe8b8666c7e067e5dff2d6530b160a03f4eb41099b611ad87bef5de
blobs/sha256/f4aee9e53c42a22ed82451218c3ea03d1eea8d6ca8fbe8eb4e950304ba8a8bb3
blobs/sha256/f555b6118455a63226090d55f9ef32581459a5ac3e5db1b3fc72cb6b36cd2f2b
blobs/sha256/f920c5680b0b677741c5500dc365a9b074aa263ab43c3eb6be6a465b1caadd8e
index.json
manifest.json
oci-layout
repositories

こっちはなんか沢山あるw

$ ls -hl blobs/sha256/
total 3.0M
-rw-r--r-- 1 kuenishi kuenishi 1.9K Jan  1  1970 0a05ce3c4ca6f726d0a42fabe1f0de66ec79a07d35777e747f4a4eccd8b9fa1f
-rw-r--r-- 1 kuenishi kuenishi  10K Jan  1  1970 1a73b54f556b477f0a8b939d13c504a3b4f4db71f7a09c63afbc10acb3de5849
-rw-r--r-- 1 kuenishi kuenishi 1.5K Jan  1  1970 2a92d6ac9e4fcc274d5168b217ca4458a9fec6f094ead68d99c77073f08caac1
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 33a9c1fe1b9de747b36f27e8a41275eaec26f91acee572e8ba7e79b05bb00aeb
-rw-r--r-- 1 kuenishi kuenishi 1.5K Jan  1  1970 4d049f83d9cf21d1f5cc0e11deaf36df02790d0e60c1a3829538fb4b61685368
-rw-r--r-- 1 kuenishi kuenishi  890 Jan  1  1970 5010c1191169bde1fbcb9ec86c559981da5d6de79883987ae2a56678a1a43226
-rw-r--r-- 1 kuenishi kuenishi 1.5K Jan  1  1970 5d7d2b4256071447af7ff304af79cc961e7e2fb862009ece2c10fc25cebd16e6
-rw-r--r-- 1 kuenishi kuenishi 2.5K Jan  1  1970 6f1cdceb6a3146f0ccb986521156bef8a422cdbb0863396f7f751f575ba308f4
-rw-r--r-- 1 kuenishi kuenishi  406 Jan  1  1970 7a68c38227c001989853bc772842e8da74761fc32ba28c1cbb00b29e71f28ff0
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 7aa6c86e10a86924a65d7cc7002ecc12bfc19d79f1d30b83e26687b99078c920
-rw-r--r-- 1 kuenishi kuenishi  40K Jan  1  1970 8fa10c0194df9b7c054c90dbe482585f768a54428fc90a5b78a0066a123b1bba
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 93dbdfde69bd85b4b4187a74e341e29a3004de6794197aab4e0affd87201be51
-rw-r--r-- 1 kuenishi kuenishi 2.3M Jan  1  1970 a80545a98dcd0866ae5eeadc9a28dec703b1e54a01ce8ff245e83f48261fe575
-rw-r--r-- 1 kuenishi kuenishi 2.5K Jan  1  1970 af5aa97ebe6ce1604747ec1e21af7136ded391bcabe4acef882e718a87c86bcc
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 b056cd32692b05422119ec8391ac02bec605a44227924472578fb5fd508fedd3
-rw-r--r-- 1 kuenishi kuenishi 233K Jan  1  1970 b336e209998fa5cf0eec3dabf93a21194198a35f4f75612d8da03693f8c30217
-rw-r--r-- 1 kuenishi kuenishi 2.5K Jan  1  1970 bbb6cacb8c82e4da4e8143e03351e939eab5e21ce0ef333c42e637af86c5217b
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 c1eef4bd174742a2115299a933d8db660484d90791ced98a07b21e4da586ec05
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 c3bac019063b593deec8ba23e76395a46bb6381684bb731108016c736e0d0bf0
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 c65596a257a4a8ffe03bdc7ccfdfdc8f652d674d588aa7f7cd00a8e93be2ddeb
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 d874ff488fe8b8666c7e067e5dff2d6530b160a03f4eb41099b611ad87bef5de
-rw-r--r-- 1 kuenishi kuenishi 3.0K Jan  1  1970 f4aee9e53c42a22ed82451218c3ea03d1eea8d6ca8fbe8eb4e950304ba8a8bb3
-rw-r--r-- 1 kuenishi kuenishi  482 Jan  1  1970 f555b6118455a63226090d55f9ef32581459a5ac3e5db1b3fc72cb6b36cd2f2b
-rw-r--r-- 1 kuenishi kuenishi 320K Jan  1  1970 f920c5680b0b677741c5500dc365a9b074aa263ab43c3eb6be6a465b1caadd8e

ひとつずつ見たけど、なんか /tmp とか /etc/group とか nsswitch.conf とかが細かく層になっていた。こういうふうに分けることにどれだけ意味があるのかよくわかってないがなにか理由があるのだろう。 ちなみにタイムスタンプが全部Unix epoch=0になっているのはビルドをDeterministicにするため。

index.json こんな感じでお作法通り(あたりまえ)

{
    "schemaVersion": 2,
    "mediaType": "application/vnd.oci.image.index.v1+json",
    "manifests": [
        {
            "mediaType": "application/vnd.oci.image.manifest.v1+json",
            "digest": "sha256:0a05ce3c4ca6f726d0a42fabe1f0de66ec79a07d35777e747f4a4eccd8b9fa1f",
            "size": 1907,
            "annotations": {
                "io.containerd.image.name": "gcr.io/distroless/static-debian12:latest-amd64",
                "org.opencontainers.image.ref.name": "latest-amd64"
            }
        }
    ]
}

manifests.json はこんな感じで結構長い

[
    {
        "Config": "blobs/sha256/5d7d2b4256071447af7ff304af79cc961e7e2fb862009ece2c10fc25cebd16e6",
        "RepoTags": [
            "gcr.io/distroless/static-debian12:latest-amd64"
        ],
        "Layers": [
            "blobs/sha256/f920c5680b0b677741c5500dc365a9b074aa263ab43c3eb6be6a465b1caadd8e",
            "blobs/sha256/8fa10c0194df9b7c054c90dbe482585f768a54428fc90a5b78a0066a123b1bba",
            "blobs/sha256/a80545a98dcd0866ae5eeadc9a28dec703b1e54a01ce8ff245e83f48261fe575",
            "blobs/sha256/4d049f83d9cf21d1f5cc0e11deaf36df02790d0e60c1a3829538fb4b61685368",
            "blobs/sha256/af5aa97ebe6ce1604747ec1e21af7136ded391bcabe4acef882e718a87c86bcc",
            "blobs/sha256/6f1cdceb6a3146f0ccb986521156bef8a422cdbb0863396f7f751f575ba308f4",
            "blobs/sha256/bbb6cacb8c82e4da4e8143e03351e939eab5e21ce0ef333c42e637af86c5217b",
            "blobs/sha256/2a92d6ac9e4fcc274d5168b217ca4458a9fec6f094ead68d99c77073f08caac1",
            "blobs/sha256/1a73b54f556b477f0a8b939d13c504a3b4f4db71f7a09c63afbc10acb3de5849",
            "blobs/sha256/f4aee9e53c42a22ed82451218c3ea03d1eea8d6ca8fbe8eb4e950304ba8a8bb3",
            "blobs/sha256/b336e209998fa5cf0eec3dabf93a21194198a35f4f75612d8da03693f8c30217"
        ],
        "LayerSources": {
            "sha256:1a73b54f556b477f0a8b939d13c504a3b4f4db71f7a09c63afbc10acb3de5849": {
                "mediaType": "application/vnd.oci.image.layer.v1.tar",
                "size": 10240,
                "digest": "sha256:1a73b54f556b477f0a8b939d13c504a3b4f4db71f7a09c63afbc10acb3de5849"
            },
            "sha256:2a92d6ac9e4fcc274d5168b217ca4458a9fec6f094ead68d99c77073f08caac1": {
                "mediaType": "application/vnd.oci.image.layer.v1.tar",
                "size": 1536,
                "digest": "sha256:2a92d6ac9e4fcc274d5168b217ca4458a9fec6f094ead68d99c77073f08caac1"
            },
Kota UENISHIKota UENISHI

こんな感じでローカルに適当に tar を作った

$ tar tf foo.tar
manifest.json
index.json
blobs
blobs/sha256
blobs/sha256/348c4772272f5f120a3044c6ba109f4d189a9e36467bc02c22debdcc2b02ed52
blobs/sha256/95e2e9d7014080736ab17d24ed2bc6626377f711e9248cc15125b8792f4339d4
blobs/sha256/45d75ce3c01ccbf233066f6df15390d833d116ec5af1580722bfb93e085d00a5
oci-layout

これをロードするとしっぱいする

$ docker -D load --input foo.tar
time="2025-02-25T00:10:26+09:00" level=debug msg="otel error" error="1 errors occurred detecting resource:\n\t* conflicting Schema URL: https://opentelemetry.
io/schemas/1.21.0 and https://opentelemetry.io/schemas/1.26.0"
json: cannot unmarshal object into Go value of type []tarexport.manifestItem

どうもこれを踏んでいるっぽい→ Image format docker-archive is not equivalent to docker save #425
ubuntu:latest をみてみると

[
    {
        "Config": "blobs/sha256/b1d9df8ab81559494794e522b380878cf9ba82d4c1fb67293bcf931c3aa69ae4",
        "RepoTags": [
            "ubuntu:latest"
        ],
        "Layers": [
            "blobs/sha256/687d50f2f6a697da02e05f2b2b9cb05c1d551f37c404ebe55fdec44b0ae8aa5c"
        ],
        "LayerSources": {
            "sha256:687d50f2f6a697da02e05f2b2b9cb05c1d551f37c404ebe55fdec44b0ae8aa5c": {
                "mediaType": "application/vnd.oci.image.layer.v1.tar",
                "size": 80630272,
                "digest": "sha256:687d50f2f6a697da02e05f2b2b9cb05c1d551f37c404ebe55fdec44b0ae8aa5c"
            }
        }
    }
]

なんか全然違うな?!?!となる
DockerというかMoby 21.5.1のコード をみると

type manifestItem struct {
	Config       string
	RepoTags     []string
	Layers       []string
	Parent       image.ID                                 `json:",omitempty"`
	LayerSources map[layer.DiffID]distribution.Descriptor `json:",omitempty"`
}

知らない子だね・・・となる
頑張って似たようなJSONを作る

[{"Config":"blobs/sha256/0026e749363c77a77659a5b40bb8173913c8acf6be10d05553c15d13366cd178","LayerSources":{"blobs/sha256/348c4772272f5f120a3044c6ba109f4d189a9e36467bc02c22debdcc2b02ed52":{"digest":"sha256:348c4772272f5f120a3044c6ba109f4d189a9e36467bc02c22debdcc2b02ed52","mediaType":"application/vnd.oci.image.layer.v1.tar","size":10240}},"Layers":["blobs/sha256/348c4772272f5f120a3044c6ba109f4d189a9e36467bc02c22debdcc2b02ed52"],"RepoTags":["c1:latest"]}]

ロードできた!

$ docker -D load --input foo.tar
time="2025-02-25T01:17:00+09:00" level=debug msg="otel error" error="1 errors occurred detecting resource:\n\t* conflicting Schema URL: https://opentelemetry.
io/schemas/1.21.0 and https://opentelemetry.io/schemas/1.26.0"
Loaded image: c1:latest

実行には失敗する

$ docker run -it c1:latest pwd
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to
start container process: error during container init: exec: "pwd": executable file not found in $PATH: unknown.

なぜならイメージに何もないから

$ docker images c1
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
c1           latest    0026e749363c   55 years ago   6B

6Bは草

Kota UENISHIKota UENISHI

虚無レイヤーを食わせることによって更に小さくできた

$ docker images c1
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
c1           latest    95e2e9d70140   55 years ago   0B

/usr/bin/ls を食わせるとエラーがかわる (lsを食わせないと docker daemon がエラーを吐く)。この場合はおそらくコンテナ内で exec するときに実行ファイルが見つからないと言っている。

$ docker run -it c1:latest /ls
exec /ls: no such file or directory

tar の中身をみると

$ file sha256/*
sha256/117d5b39e32b237450baa2b3bdbf757359e3fbda69c591fc0d61f4d20cb024db: JSON text data
sha256/2f825a695e49e56855ff373ba4a5f15caa006e9961a5d47185d7bb65d44bf443: POSIX tar archive (GNU)
sha256/50092dc0631b03614a7458587522ca716362148a7b52de47fa14661b02d2528f: JSON text data
sha256/75ebcc750c01b78dcd229cd0db7779b968d73b9d7d7c408fcf361aa18e631477: POSIX tar archive (GNU)
$ tar tf sha256/2f*
./
./ls

なので一応ファイルはある(?)

適当なSingle binaryのGoのプログラムをわたしたら動いたので、これはELFバイナリに必要な動的ライブラリがないからと想像できる

$ ldd /bin/ls
        linux-vdso.so.1 (0x00007c78d993a000)
        libcap.so.2 => /usr/lib/libcap.so.2 (0x00007c78d98c6000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007c78d96d4000)
        /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007c78d993c000)