コンテナイメージのアーカイブのポータビリティ

ざっくりいうとコンテナイメージは、レイヤごとのファイルをまとめた tar.gz(あるいは tar)と、 どのようにコンテナを実行するかという設定(環境変数やエントリポイントなど)から構成されていて、 OCI Image Format Specification で標準化が進んでいる。

その OCI Image Format Specification の中でコンテナイメージのアーカイブの形式(save -> load するアレ)も定義されているが、 現在の主流と思われる docker は独自のフォーマットを利用しているので、いまいちポータビリティが悪い。

検証環境

$ cat /etc/redhat-release
Rocky Linux release 8.6 (Green Obsidian)

$ podman -v
podman version 4.1.1

$ docker -v
Docker version 20.10.18, build b40c2f6 

docker から podman にイメージを移す

podman が docker-archive 形式を解釈できるためイメージを移せる。 (ただし docker は oci-archive 形式では出力できない)

$ sudo docker pull ubuntu:20.04
$ sudo docker save ubuntu:20.04 -o ubuntu.tar

$ sudo chown -R rocky:rocky ubuntu.tar
$ podman load -i ubuntu.tar
Getting image source signatures
Copying blob b40ed86654e5 done
Copying config a0ce5a295b done
Writing manifest to image destination
Storing signatures
Loaded image: localhost/ubuntu:20.04

$ podman images
REPOSITORY        TAG         IMAGE ID      CREATED      SIZE
localhost/ubuntu  20.04       a0ce5a295b63  4 weeks ago  75.2 MB

podman から docker にイメージを移す

podman が docker-archive 形式で出力できるため、問題なく実行できる。

$ podman pull ubuntu:20.04
$ podman save ubuntu:20.04 -o ubuntu.tar
Copying blob b40ed86654e5 done
Copying config a0ce5a295b done
Writing manifest to image destination
Storing signatures

$ sudo docker load -i ubuntu.tar
Loaded image: ubuntu:20.04

ただし --formatオプションで oci-archive を選択すると、docker で load に失敗する。 (docker は oci-archive を解釈できない)

$ podman save --format=oci-archive ubuntu:20.04 -o oci-archive.tar
Copying blob b40ed86654e5 done
Copying config 0366c72f42 done
Writing manifest to image destination
Storing signatures

$ sudo docker load -i oci-archive.tar
open /var/lib/docker/tmp/docker-import-2367465397/blobs/json: no such file or directory

oci-archive と docker-archive

oci-archive と docker-archive を展開してみると、次のようになっていた。 コンテナイメージの tar.gz と 設定 があるのは一緒だけど、いろいろと構造が違いそう。

$ tree  --charset=C oci-archive
oci-archive
|-- blobs
|   `-- sha256
|       |-- 0366c72f42c93f821a53b2ad5c7df9b14a2499d0648f8234c71365be68221b80
|       |-- 96babd50cb37eb5509a13822ff6f2162751be3b06f51effc121e4b15f25ad949
|       `-- a5ae1e707212700852a8ffccb6218577421efc37a97315bf16f462b42b7b73e3
|-- index.json
`-- oci-layout

2 directories, 5 files
$ tree  --charset=C docker-archive
docker-archive
|-- 5e7907c0fec1583e8d47be9244ef7ea9f7bfdc7bd5ce449a87f908c12f1a5586
|   |-- json
|   |-- layer.tar -> ../b40ed86654e59e1012e1716d5384910f8c3bb58274b7b00fca564a53e9897ba3.tar
|   `-- VERSION
|-- a0ce5a295b637a10bc329ded296a0c895e5e56e7c5e674188d423e213b0d213e.json
|-- b40ed86654e59e1012e1716d5384910f8c3bb58274b7b00fca564a53e9897ba3.tar
|-- manifest.json
`-- repositories

1 directory, 7 files

oci-archive について

詳細は https://github.com/opencontainers/image-spec/blob/main/image-layout.md#oci-layout-file に書いてあるが、 いちおうファイルを見てみると、次のようになってた。

$ cat oci-archive/oci-layout | jq
{
  "imageLayoutVersion": "1.0.0"
}

$ cat oci-archive/index.json | jq
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:96babd50cb37eb5509a13822ff6f2162751be3b06f51effc121e4b15f25ad949",
      "size": 406,
      "annotations": {
        "org.opencontainers.image.ref.name": "docker.io/library/ubuntu:20.04"
      }
    }
  ]
}

$ cat oci-archive/blobs/sha256/96babd50cb37eb5509a13822ff6f2162751be3b06f51effc121e4b15f25ad949 | jq
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:0366c72f42c93f821a53b2ad5c7df9b14a2499d0648f8234c71365be68221b80",
    "size": 579
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:a5ae1e707212700852a8ffccb6218577421efc37a97315bf16f462b42b7b73e3",
      "size": 29819107
    }
  ]
}

$ cat oci-archive/blobs/sha256/0366c72f42c93f821a53b2ad5c7df9b14a2499d0648f8234c71365be68221b80 | jq
{
  "created": "2022-09-01T23:46:27.150780363Z",
  "architecture": "amd64",
  "os": "linux",
  "config": {
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": [
      "bash"
    ]
  },
  "rootfs": {
    "type": "layers",
    "diff_ids": [
      "sha256:b40ed86654e59e1012e1716d5384910f8c3bb58274b7b00fca564a53e9897ba3"
    ]
  },
  "history": [
    {
      "created": "2022-09-01T23:46:26.800519282Z",
      "created_by": "/bin/sh -c #(nop) ADD file:ff6963f777661fb16cc12fb04a97c558bd94768a6e4ab5bd90e01f3086818853 in / "
    },
    {
      "created": "2022-09-01T23:46:27.150780363Z",
      "created_by": "/bin/sh -c #(nop)  CMD [\"bash\"]",
      "empty_layer": true
    }
  ]
}

$ file oci-archive/blobs/sha256/a5ae1e707212700852a8ffccb6218577421efc37a97315bf16f462b42b7b73e3
oci-archive/blobs/sha256/a5ae1e707212700852a8ffccb6218577421efc37a97315bf16f462b42b7b73e3: gzip compressed data, original size 75148800

docker で oci-archive をサポートしようとする提案(2016 年に)もあるようだが、まだマージされてなさげ Proposal: Add support for OCI Image Layout · Issue #25779 · moby/moby · GitHub。 docker が oci-archive をサポートしてくれないと、他のツールも docker とのポータビリティのために docker-archive 形式をサポートし続けないといけない未来が見える。