天天看點

容器OCI規範 鏡像規範容器OCI規範 鏡像規範

  • 容器OCI規範 鏡像規範
    • 前言
    • OCI 鏡像規範初步
    • OCI 檔案類型
      • Media Type
      • Media Type 的不一緻
    • OCI Content Descriptor
      • Content Descriptor 屬性
      • 摘要和校驗
      • Content Descriptor 示例
    • OCI 鏡像布局規範
      • 詳細内容
        • 示例
      • Blobs 檔案夾
        • Blobs 示例
      • oci-layout 檔案
        • oci-layout 示例
      • indexjson 檔案
        • indexjson 示例
    • OCI Image Manifest
      • 詳細内容
      • 示例
    • OCI Image Index
      • 詳細内容
      • 示例
    • Image Layer
    • Annotations
      • 使用規則
      • 預定義的一些注解
    • 其他需要考慮的問題
      • 可擴充性
      • 規範化

容器OCI規範 鏡像規範

整篇文章還沒有潤色,條理性還不夠強,Image Layerd的規範還沒來得及寫。還隻是半成品,先放出來給有興趣的同學看一下。

前言

  • OCI 官網:https://www.opencontainers.org/
  • OCI 鏡像規範:https://github.com/opencontainers/image-spec
    • OCI 鏡像規範的主要目的是:統一各種容器工具的鏡像格式,讓标準鏡像能夠在多種容器軟體下使用。
    • OCI 鏡像規範中還給出了Go語言描述的對象模型示例。(Go,親兒子)

OCI 鏡像規範初步

從一個比較高層次的角度來看這個規範,主要有以下内容:

  • 一個鏡像由四部分組成:Manifest、Image Index (可選)、Layers、Configuration。
  • 根據存儲内容的密碼學哈希值找到鏡像存儲的位置,根據内容尋址的描述格式。(Content Descriptors)
  • 一種格式存儲CAS斑點和引用它們(可選OCI層)
  • 簽名是基于簽名的圖像内容的位址(可選OCI層)
  • 命名是聯合基于DNS,可以授權(可選OCI層)

Manifest 包括鏡像内容的元資訊和鏡像層的摘要資訊,這些鏡像層可以解包部署成最後的運作環境。

Configuration 則包含了應用的參數環境。

Index 則從更高的角度描述了Manifest,主要應用于鏡像跨平台。

OCI 檔案類型

Media Type

  • application/vnd.oci.descriptor.v1+json

    : Content Descriptor(内容描述檔案)
  • application/vnd.oci.layout.header.v1+json

    : OCI Layout(布局描述檔案)
  • application/vnd.oci.image.index.v1+json

    : Image Index(高層次的鏡像元資訊檔案)
  • application/vnd.oci.image.manifest.v1+json

    : Image Manifest(鏡像元資訊檔案)
  • application/vnd.oci.image.config.v1+json

    : Image Config(鏡像配置檔案)
  • application/vnd.oci.image.layer.v1.tar

    : Image Layer(鏡像層檔案)
  • application/vnd.oci.image.layer.v1.tar+gzip

    : Image Layer(鏡像層檔案), gzip壓縮
  • application/vnd.oci.image.layer.nondistributable.v1.tar

    : Image Layer, 非内容尋址管理
  • application/vnd.oci.image.layer.nondistributable.v1.tar+gzip

    : Image Layer, gzip壓縮,非内容尋址管理

Media Type 的不一緻

當擷取塊檔案時,可以傳回檔案的Media Type,比如Http請求的傳回頭中設定Content-Type字段。鏡像規範的實作也可能會有預期的Media Type。

  • 當你沒有預期的Media Type時,信任塊檔案傳回的Media type類型。
  • 當你預期的Media Type和傳回一緻時,是正常情況。
  • 當你預期的Media Type和傳回不一緻時,你必須:
    • 如果你的預期的Digest和傳回塊的Digest一緻時,報一個警告。
    • 如果你的預期的Digest和傳回塊的Digest不一緻時,傳回錯誤。
    • 如果你沒有預期的Digest,傳回錯誤。

OCI Content Descriptor

  • OCI 鏡像由幾部分組成,每個元件都是存儲在一個目錄結構中。
  • 每個元件之間都是通過内容尋址的方式互相引用。
  • Content Descriptor 描述了一個目标内容的位置。
  • Content Descriptor 包含:内容的類型、内容的辨別符、内容的大小。
  • Content Descriptor 必須通過嵌入到其他格式中使用。

Content Descriptor 屬性

  • mediaType

    string
  • digest

    string
  • size

    int64
  • urls

    array of strings
  • annotations

    string-string map
  • data

    string 保留字段

摘要和校驗

digest屬性是Descriptor的核心,扮演了内容的辨別符的角色。digest使用了防碰撞的雜湊演算法唯一的辨別了内容。如果辨別符能夠以安全的擷取。那麼就算内容通過了不安全的來源擷取,也能獨立計算出辨別符對内容的正确性進行确認。

digest的格式要求與示例:(sha256已經是一個廣泛使用的Hash算法)

digest      := algorithm ":" hex
algorithm   := /[a-z0-9_+.-]+/
hex         := /[a-f0-9]+/

sha256:c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b
           

Content Descriptor 示例

這個 Content Descriptor 描述了一個Manifest

{
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "size": ,
  "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
}
           

OCI 鏡像布局規範

  • OCI的鏡像布局将内容尋址和位置尋址做了很明顯的分割。
  • 這個布局可以使用多種方式傳輸:歸檔檔案、共享檔案系統、網絡傳輸等

詳細内容

鏡像布局有以下部分組成:

  • blobs

    directory
    • 内容尋址的塊檔案
    • A blob has no schema and SHOULD be considered opaque ?
    • 目錄必須存在,但是可以為空
  • oci-layout

    file
    • 檔案必須存在、必須是JSON格式
    • 檔案中必須包含一個

      imageLayoutVersion

      字段
    • 檔案中可以有其他字段作為擴充使用
  • index.json

    file
    • 檔案必須存在、必須是JSON格式
    • 檔案中必須包含鏡像Index的基本屬性

示例

$ find . -type f
./index.json
./oci-layout
./blobs/sha256/d02542238316759cbf24502f4344ffcc8a60c803870022f335d1390c13b4
./blobs/sha256/b0bc1c4050b03c95ef2a8e36e25feac42fd31283e8c30b3ee5df6b043155d3c
./blobs/sha256/dc6b6171697c33df7815310468e694ac5be0ec03ff053bb135e768
           

Blobs 檔案夾

  • blobs檔案夾下的子檔案夾是以Hash算法的名稱來命名的,這些子檔案夾下包含了真正的實體檔案。
  • 一個塊被digest引用時(:,descriptor),這個塊必須存放在

    blobs/<alg>/<hex>

    目錄。
  • blobs檔案夾下面可能會存放很多已經沒有任何引用的塊檔案。
  • blobs檔案夾下可以缺失一些被引用的塊檔案,隻要被其他額外的塊填滿就可以了。

Blobs 示例

Image Index

$ cat ./blobs/sha256/9b97579de92b1c195b85bb42a11011378ee549b02d7fe9c17bf2a6b35d5cb079 | jq
{
  "schemaVersion": ,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": ,
      "digest": "sha256:afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
    ...
           

Image Manifest

$ cat ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 | jq
{
  "schemaVersion": ,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": ,
    "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": ,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
    },
    ...
           

Image Config

$ cat ./blobs/sha256/5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270 | jq
{
  "architecture": "amd64",
  "author": "Alyssa P. Hacker <[email protected]>",
  "config": {
    "Hostname": "8dfe43d80430",
    "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": null,
    "Image": "sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b",
    ...
           

Image Layer Blob

$ cat ./blobs/sha256/e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f
[tar stream]
           

oci-layout 檔案

在鏡像規範中,這個檔案特别簡單,隻有一個布局版本的字段。

oci-layout 示例

{
    "imageLayoutVersion": "1.0.0"
}
           

index.json 檔案

index.json檔案相當于整個鏡像的入口。從這個檔案可以擷取整個鏡像依賴到的所有檔案的資訊。

每一個在

manifests

字段中的

descriptor

都指向一個 application/vnd.oci.image.index.v1+json 或 application/vnd.oci.image.manifest.v1+json 類型的檔案。

一個通用的做法,org.opencontainers.image.ref.name注解被認為是鏡像Tag的含義。表示鏡像的不同版本。

index.json 示例

{
  "schemaVersion": ,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.index.v1+json",
      "size": ,
      "digest": "sha256:0228f90e926ba6b96e4f39cf294b2586d38fbb5a1e385c05cd1ee40ea54fe7fd",
      "annotations": {
        "org.opencontainers.image.ref.name": "stable-release"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": ,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      },
      "annotations": {
        "org.opencontainers.image.ref.name": "v1.0"
      }
    },
    {
      "mediaType": "application/xml",
      "size": ,
      "digest": "sha256:b3d63d132d21c3ff4c35a061adf23cf43da8ae054247e32faa95494d904a007e",
      "annotations": {
        "org.freedesktop.specifications.metainfo.version": "1.0",
        "org.freedesktop.specifications.metainfo.type": "AppStream"
      }
    }
  ],
  "annotations": {
    "com.example.index.revision": "r124356"
  }
}
           

OCI Image Manifest

官網中列舉了Manifest的三大主要目标,但我覺得Manifest的主要任務就隻有一個。

通過内容描述的方式,記錄一個鏡像的元資訊,包括Image Config和Image Layers。

詳細内容

  • schemaVersion int

    這個字段是必須的,以目前版本的規範你必須填

    2

    (為了相容老版本的Docker)。
  • mediaType string

    保留字段,用于辨別目前檔案是什麼類型的。

  • config descriptor

    這個字段是必須的,用于辨別鏡像的配置檔案的位置。

    • mediaType string

      配置檔案的mediaType,必須使用這個

      application/vnd.oci.image.config.v1+json

  • layers array of descriptor

    清單中的每一個成員都是一個鏡像層,最底層的鏡像在清單的第一項,其他各層按照堆疊順序依次排列在後面。最終得到的檔案系統應該和在一個空檔案夾上堆疊各層得到的結果一樣。用于堆疊的空檔案夾的各種權限是不确定的。

    • mediaType string

      鏡像層的mediaType,有比較多的選擇:

      • application/vnd.oci.image.layer.v1.tar
      • application/vnd.oci.image.layer.v1.tar+gzip
      • application/vnd.oci.image.layer.nondistributable.v1.tar
      • application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
  • annotations string-string map

    注釋,和其他定義一樣。

示例

{
  "schemaVersion": ,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": ,
    "digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": ,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": ,
      "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": ,
      "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
    }
  ],
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}
           

OCI Image Index

Image Index是一個更高層次的Manifest,一般在一個鏡像需要提供多個平台支援時使用。

MediaType:

application/vnd.oci.image.index.v1+json

詳細内容

  • schemaVersion int

    這個字段是必須的,以目前版本的規範你必須填

    2

    (為了相容老版本的Docker)。
  • mediaType string

    保留字段,用于辨別目前檔案是什麼類型的。

  • manifests array of objects

    這個字段是必須的,但是可能為空。他給出了對于特定平台的Manifests清單

    • mediaType string

      Manifests的mediaType,必須使用這個

      application/vnd.oci.image.manifest.v1+json

    • platform object

      這個字段是可選的,描述了Manifest中描述的鏡像是運作在哪一個指定的平台。

      • architecture string

        這個字段是必須的,指定了CPU的架構類型。在運作時規範中會給出平台的相關幫助。

      • os string

        這個字段是必須的,指定了作業系統的類型。在運作時規範中會給出作業系統的相關幫助。

      • os.version string

        這個字段是可選的,指定作業系統的版本要求。

      • os.features array of strings

        這個字段是可選的,指定了一些對于系統的特殊要求。

      • variant string

        這個字段是可選的,指定了CPU的版本要求。

      • features array of strings

        這個字段是可選的,指定了一些對于CPU指令集的特殊要求。(比如sse4、aes)

      • annotations string-string map

        注解

示例

{
  "schemaVersion": ,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": ,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": ,
      "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
      "platform": {
        "architecture": "amd64",
        "os": "linux",
        "os.features": [
          "sse4"
        ]
      }
    }
  ],
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}
           

Image Layer

Annotations

對于大部分前文中描述的結構,基本都可以添加Annotations。對于Annotations的使用主要有以下一些内容。

使用規則

  • Annotations必須是鍵值對,其中鍵必須是string類型的。
  • 鍵必須唯一,最佳實踐是使用命名空間,将其做區分。
  • 值必須存在,但是可以是空字元串。
  • org.opencontainers

    字首的鍵是OCI規範的,不要随便用。
  • org.opencontainers.image

    字首的鍵是OCI鏡像規範的,不要随便用。
  • 使用鏡像時,不要因為遇到了未知的注解,而直接抛出錯誤。

預定義的一些注解

  • org.opencontainers.image.created

    鏡像建構的日期 (string, RFC 3339).
  • org.opencontainers.image.authors

    鏡像的負責人或組織 (string)
  • org.opencontainers.image.homepage

    鏡像相關資訊位址 (string, URL)
  • org.opencontainers.image.documentation

    鏡像幫助文檔位址 (string, URL)
  • org.opencontainers.image.source

    鏡像源代碼位址 (string, URL)
  • org.opencontainers.image.ref.name

    鏡像名稱(Tag) (string)

其他需要考慮的問題

可擴充性

為了保證可擴充性。使用該規範的實作,不能因為擷取到了一些規範之外的屬性,而産生錯誤或者是異常。

規範化

  • OCI 鏡像是基于内容尋址的。
  • 内容尋址的一大好處就是可以共享重複的資料。
  • 多個鏡像依賴同一個層時,這個層隻會存儲一份。
  • 使用不同的序列化算法時,語義上一樣的層往往會得到不用的Hash值,這樣的話這樣語義上一樣的層就會被存儲兩份。這兩份是一樣的。
  • 為了保證高效存儲,我們必須使用權威的序列化方式。
  • 這樣的話多個不同的該規範實作在推送時表現出來的行為将會是一緻的。
  • 許多元件都是JSON格式的,這裡也應該使用權威的序列化方式。