📖

OCI image-specについて

2023/03/18に公開

概要

OCI image-specを実際のnginxイメージから少し理解を深めてみる.

作業

nginxイメージをOCIイメージとしてダウンロード

skopeoを使う.
OCI Image ImplementatinsにOCI specを満たすツール一覧があり, skopeoはその一番目にあると言う理由だけで採用した.
  
skopeoを使ってnginxイメージをダウンロードすると以下レイアウトになる.

skopeo copy docker://nginx:latest oci:nginx-image:latest 

tree nginx-image
nginx-image
├── blobs
│   └── sha256
│       ├── 1fbb850f12af0a4d2bb020ef8aa7b14eb84b9fb67ba1ba731150e9aefc93ba04
│       ├── 31a65c800bdcb184f4c7386a7ef724b085b953a8c36edfe6284649a08652b8c6
│       ├── 3a1b8f20135650110763d223f82a25007e00b28b268e6a875fe87c85ba7570e4
│       ├── 3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0
│       ├── 6058e3569a68e825f1085592ab0bb04c29345726119ed059ad933c0d9af5f533
│       ├── 73ae4d4511202a823260a789f97afb3a46b8c9172ae8d99d22a5a16ad2fa673b
│       ├── 9a8c6f28671867118799d40ec6748ffbd9eab3747503ca47a2a79856dffc7553
│       └── e81b85700bc2530b1298885f74210138872f60cd139920b54aef3d268d61f0de
├── index.json
└── oci-layout

2 directories, 10 files

ファイルの確認

oci-layout

oci-layoutではimageLayoutVersionが書かれている.

jq . oci-layout                                                                                                                                                                                                                                                        1{
  "imageLayoutVersion": "1.0.0"
}

index.json

詳細はimage-index.mdに記載されている.
そのためそれぞれの項目の説明をしないが重要なのはmanifestsのdigest. sha256:に続くハッシュ値が後述のblob/sha256以下にあるマニフェストファイル名となる. この例だとblob/sha256/1fbb850f12af0a4d2bb020ef8aa7b14eb84b9fb67ba1ba731150e9aefc93ba04がマニフェストファイルである.

jq . index.json 
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:1fbb850f12af0a4d2bb020ef8aa7b14eb84b9fb67ba1ba731150e9aefc93ba04",
      "size": 1126,
      "annotations": {
        "org.opencontainers.image.ref.name": "latest"
      }
    }
  ]
}

blobs/sha256

このフォルダ以下のファイル群が一番重要.

manifest

まずはマニフェストファイルを覗いてみる. 詳細はmanifest.msに記載されている. これを見るとおおまかにconfigとlayersで構成されていることがわかる. このmanifestファイルからどのハッシュ値がイメージを構成するレイヤなのか辿ることができる.

jq . blobs/sha256/1fbb850f12af0a4d2bb020ef8aa7b14eb84b9fb67ba1ba731150e9aefc93ba04
{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:31a65c800bdcb184f4c7386a7ef724b085b953a8c36edfe6284649a08652b8c6",
    "size": 6565
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0",
      "size": 31411403
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:9a8c6f28671867118799d40ec6748ffbd9eab3747503ca47a2a79856dffc7553",
      "size": 25471180
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:e81b85700bc2530b1298885f74210138872f60cd139920b54aef3d268d61f0de",
      "size": 626
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:73ae4d4511202a823260a789f97afb3a46b8c9172ae8d99d22a5a16ad2fa673b",
      "size": 956
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:6058e3569a68e825f1085592ab0bb04c29345726119ed059ad933c0d9af5f533",
      "size": 772
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:3a1b8f20135650110763d223f82a25007e00b28b268e6a875fe87c85ba7570e4",
      "size": 1402
    }
  ]
}

config

詳細はconfig.mdに記載されている. このファイルから直接コンテナを作るわけではないが, イメージの情報が格納されており, コンテナランタイムやコマンドラインツールに利用される模様. 今回の例では上記のmanifestファイルからblobs/sha256/31a65c800bdcb184f4c7386a7ef724b085b953a8c36edfe6284649a08652b8c6がconfigファイルにあたる. 中身が長いのでここでは表示しない.

layer

layerがimageの実体になる. manifestファイルから以下のハッシュ値がイメージを構成するファイル群となる. これの詳細もlayer.mdに記載されている

layers.txt
3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0
9a8c6f28671867118799d40ec6748ffbd9eab3747503ca47a2a79856dffc7553
e81b85700bc2530b1298885f74210138872f60cd139920b54aef3d268d61f0de
73ae4d4511202a823260a789f97afb3a46b8c9172ae8d99d22a5a16ad2fa673b
6058e3569a68e825f1085592ab0bb04c29345726119ed059ad933c0d9af5f533
3a1b8f20135650110763d223f82a25007e00b28b268e6a875fe87c85ba7570e4

レイヤ用のディレクトリlayer[1-6]を作り, それぞれのディレクトリにlayerファイルを展開して確認してみる.

tar -C layer1 -xf blobs/sha256/3f9582a2cbe7197f39185419c0ced2c986389f8fc6aa805e1f5c090eea6511e0
ls layer1
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

tar -C layer2 -xf blobs/sha256/9a8c6f28671867118799d40ec6748ffbd9eab3747503ca47a2a79856dffc7553
ls layer2 
docker-entrypoint.d  etc  lib  tmp  usr  var

tar -C layer3 -xf blobs/sha256/e81b85700bc2530b1298885f74210138872f60cd139920b54aef3d268d61f0de ls layer3
docker-entrypoint.sh 

tar -C layer4 -xf blobs/sha256/73ae4d4511202a823260a789f97afb3a46b8c9172ae8d99d22a5a16ad2fa673b
tree layer4                                               
layer4
└── docker-entrypoint.d
    └── 10-listen-on-ipv6-by-default.sh

tar -C layer5 -xf blobs/sha256/6058e3569a68e825f1085592ab0bb04c29345726119ed059ad933c0d9af5f533
tree layer5
layer5
└── docker-entrypoint.d
    └── 20-envsubst-on-templates.sh
    
tar -C layer6 -xf blobs/sha256/3a1b8f20135650110763d223f82a25007e00b28b268e6a875fe87c85ba7570e4

tree layer6 
layer6
└── docker-entrypoint.d
    └── 30-tune-worker-processes.sh

まとめるには例えばrootfs以下で以下コマンドを実行する. このrootfs以下のディレクトリ構成がコンテナで利用するファイルシステムとなる.

for layer in `cat layers.txt`; do tar -C rootfs -xf blobs/sha256/$layer; done
ls rootfs 
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

umociを使えばこのようにシェルコマンドでファイルシステムを展開する必要はないが, 確認のため今回はシェルコマンドで試してみた.

mediaTypeについて

今まで説明しなかったがそれぞれのdigestにmediaTypeというのが紐づいている. digestはただのハッシュ値なのでこれを見るだけでは何なのかわからないが, mediaTypeを確認することによってそのハッシュ値が何を表しているのかわかる.

今回の例のlayerの場合, application/vnd.oci.image.layer.v1.tar+gzipとなっているが, これはアーカイブされたファイル/フォルダ群をgzip圧縮していることがわかる.

mediaTypeの種類はmedia-types.mdで定義されている.

所感

触り程度にはOCI image-specの理解ができたと思う.

参照

opencontainers/image-spac

Discussion