1. Blog
  2. Golang
  3. kubernetes
  4. Rust
  5. 关于作者

OCI 规范翻译

开放容器倡议(OCI)是 Linux 基金会的项目,目的是建立围绕容器格式和运行时的开放式行业标准的明确目的的开放式治理结构。

当前有三个规范正在开发和使用中:运行时规范runtime-spec、镜像规范image-spec和分发规范distribution-spec

此外该组织opencontainers还包含了 runtime 实现 runc其他实现和一些工具类。

当前的版本为:

runtime spec

开放容器计划运行时规范(runtime-spec)旨在指定容器的配置,运行环境和生命周期。

该规范指定了 linuxsolariswindowvm 四类平台下的运行环境配置,每个平台下的配置。详细参见platforms。也就是说 oci 的实现,不仅仅是在 linux 环境上,还支持 windows 环境,甚至虚拟机。

该规范被分为两部分描述,一部分为 runtime 一部分为 config。

此外该规范还定义了一个 filesystem bundle 程序包,该程序包为容器运行的起点和入口。

至目前为止已经有了虚拟机和容器的实现可供参考。

Container:

Virtual Machine:

bundle

运行时规范参照macos 应用程序包的方式制定了一个容器应用的 bundle。 实现了 runtime-spec 的程序以一个 bundle 开始创建容器。

runtime-impl create <cintainer-id> <bundle path>

bundle 包含了两部分,一部分为 bundle 的配置信息config.json,一部分为 bundle 的根文件系统目录rootfs。一个推荐的 bundle 目录结构大致为如下样子:

bundle/
├── config.json
└── rootfs

1 directory, 1 file

config

该配置文件config.json包含对容器实施标准操作所必需的元数据。 包括要运行的过程,要注入的环境变量,要使用的沙箱功能等配置信息等。其包含了:

公共配置:

平台特定的配置,以 linux 平台配置为例:

更详细的信息

下面是一个完整的config.json文件

{
  "ociVersion": "1.0.1",
  "process": {
    "terminal": true,
    "user": {
      "uid": 1,
      "gid": 1,
      "additionalGids": [5, 6]
    },
    "args": ["sh"],
    "env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
      "TERM=xterm"
    ],
    "cwd": "/",
    "capabilities": {
      "bounding": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "permitted": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "inheritable": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "effective": ["CAP_AUDIT_WRITE", "CAP_KILL"],
      "ambient": ["CAP_NET_BIND_SERVICE"]
    },
    "rlimits": [
      {
        "type": "RLIMIT_CORE",
        "hard": 1024,
        "soft": 1024
      },
      {
        "type": "RLIMIT_NOFILE",
        "hard": 1024,
        "soft": 1024
      }
    ],
    "apparmorProfile": "acme_secure_profile",
    "oomScoreAdj": 100,
    "selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675",
    "noNewPrivileges": true
  },
  "root": {
    "path": "rootfs",
    "readonly": true
  },
  "hostname": "slartibartfast",
  "mounts": [
    {
      "destination": "/proc",
      "type": "proc",
      "source": "proc"
    },
    {
      "destination": "/dev",
      "type": "tmpfs",
      "source": "tmpfs",
      "options": ["nosuid", "strictatime", "mode=755", "size=65536k"]
    },
    {
      "destination": "/dev/pts",
      "type": "devpts",
      "source": "devpts",
      "options": [
        "nosuid",
        "noexec",
        "newinstance",
        "ptmxmode=0666",
        "mode=0620",
        "gid=5"
      ]
    },
    {
      "destination": "/dev/shm",
      "type": "tmpfs",
      "source": "shm",
      "options": ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"]
    },
    {
      "destination": "/dev/mqueue",
      "type": "mqueue",
      "source": "mqueue",
      "options": ["nosuid", "noexec", "nodev"]
    },
    {
      "destination": "/sys",
      "type": "sysfs",
      "source": "sysfs",
      "options": ["nosuid", "noexec", "nodev"]
    },
    {
      "destination": "/sys/fs/cgroup",
      "type": "cgroup",
      "source": "cgroup",
      "options": ["nosuid", "noexec", "nodev", "relatime", "ro"]
    }
  ],
  "hooks": {
    "prestart": [
      {
        "path": "/usr/bin/fix-mounts",
        "args": ["fix-mounts", "arg1", "arg2"],
        "env": ["key1=value1"]
      },
      {
        "path": "/usr/bin/setup-network"
      }
    ],
    "poststart": [
      {
        "path": "/usr/bin/notify-start",
        "timeout": 5
      }
    ],
    "poststop": [
      {
        "path": "/usr/sbin/cleanup.sh",
        "args": ["cleanup.sh", "-f"]
      }
    ]
  },
  "linux": {
    "devices": [
      {
        "path": "/dev/fuse",
        "type": "c",
        "major": 10,
        "minor": 229,
        "fileMode": 438,
        "uid": 0,
        "gid": 0
      },
      {
        "path": "/dev/sda",
        "type": "b",
        "major": 8,
        "minor": 0,
        "fileMode": 432,
        "uid": 0,
        "gid": 0
      }
    ],
    "uidMappings": [
      {
        "containerID": 0,
        "hostID": 1000,
        "size": 32000
      }
    ],
    "gidMappings": [
      {
        "containerID": 0,
        "hostID": 1000,
        "size": 32000
      }
    ],
    "sysctl": {
      "net.ipv4.ip_forward": "1",
      "net.core.somaxconn": "256"
    },
    "cgroupsPath": "/myRuntime/myContainer",
    "resources": {
      "network": {
        "classID": 1048577,
        "priorities": [
          {
            "name": "eth0",
            "priority": 500
          },
          {
            "name": "eth1",
            "priority": 1000
          }
        ]
      },
      "pids": {
        "limit": 32771
      },
      "hugepageLimits": [
        {
          "pageSize": "2MB",
          "limit": 9223372036854772000
        },
        {
          "pageSize": "64KB",
          "limit": 1000000
        }
      ],
      "memory": {
        "limit": 536870912,
        "reservation": 536870912,
        "swap": 536870912,
        "kernel": -1,
        "kernelTCP": -1,
        "swappiness": 0,
        "disableOOMKiller": false
      },
      "cpu": {
        "shares": 1024,
        "quota": 1000000,
        "period": 500000,
        "realtimeRuntime": 950000,
        "realtimePeriod": 1000000,
        "cpus": "2-3",
        "mems": "0-7"
      },
      "devices": [
        {
          "allow": false,
          "access": "rwm"
        },
        {
          "allow": true,
          "type": "c",
          "major": 10,
          "minor": 229,
          "access": "rw"
        },
        {
          "allow": true,
          "type": "b",
          "major": 8,
          "minor": 0,
          "access": "r"
        }
      ],
      "blockIO": {
        "weight": 10,
        "leafWeight": 10,
        "weightDevice": [
          {
            "major": 8,
            "minor": 0,
            "weight": 500,
            "leafWeight": 300
          },
          {
            "major": 8,
            "minor": 16,
            "weight": 500
          }
        ],
        "throttleReadBpsDevice": [
          {
            "major": 8,
            "minor": 0,
            "rate": 600
          }
        ],
        "throttleWriteIOPSDevice": [
          {
            "major": 8,
            "minor": 16,
            "rate": 300
          }
        ]
      }
    },
    "rootfsPropagation": "slave",
    "seccomp": {
      "defaultAction": "SCMP_ACT_ALLOW",
      "architectures": ["SCMP_ARCH_X86", "SCMP_ARCH_X32"],
      "syscalls": [
        {
          "names": ["getcwd", "chmod"],
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    },
    "namespaces": [
      {
        "type": "pid"
      },
      {
        "type": "network"
      },
      {
        "type": "ipc"
      },
      {
        "type": "uts"
      },
      {
        "type": "mount"
      },
      {
        "type": "user"
      },
      {
        "type": "cgroup"
      }
    ],
    "maskedPaths": [
      "/proc/kcore",
      "/proc/latency_stats",
      "/proc/timer_stats",
      "/proc/sched_debug"
    ],
    "readonlyPaths": [
      "/proc/asound",
      "/proc/bus",
      "/proc/fs",
      "/proc/irq",
      "/proc/sys",
      "/proc/sysrq-trigger"
    ],
    "mountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c715,c811"
  },
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}

runtime

运行时规范定义了 容器状态、生命周期和容器操作。

容器状态:

一个示例的状态为:

{
  "ociVersion": "1.0.2",
  "id": "oci-container1",
  "status": "running",
  "pid": 4422,
  "bundle": "/containers/redis",
  "annotations": {
    "myKey": "myValue"
  }
}

生命周期:

  1. create 调用 OCI 兼容的运行时命令时,请参考包的位置和唯一标识符。
  2. 必须根据中的配置创建容器的运行时环境 config.json。如果运行时无法创建中指定的环境 config.json,则必须生成错误。config.json 必须创建请求中的资源后,此时 process 不得运行用户指定的程序(来自)。config.json 在此步骤之后进行的任何更新都不得影响容器。
  3. 该 prestart 钩子必须由运行时调用。如果任何 prestart 钩子失败,则运行时务必生成错误,停止容器,并在步骤 12 继续生命周期。
  4. 该 createRuntime 钩子必须由运行时调用。如果任何 createRuntime 钩子失败,则运行时务必生成错误,停止容器,并在步骤 12 继续生命周期。
  5. 该 createContainer 钩子必须由运行时调用。如果任何 createContainer 钩子失败,则运行时务必生成错误,停止容器,并在步骤 12 继续生命周期。
  6. start 使用容器的唯一标识符调用运行时的命令。
  7. 该 startContainer 钩子必须由运行时调用。如果任何 startContainer 钩子失败,则运行时务必生成错误,停止容器,并在步骤 12 继续生命周期。
  8. 运行时必须运行由指定的用户指定程序 process。
  9. 该 poststart 钩子必须由运行时调用。如果有任何 poststart 钩子失败,运行时必须记录一个警告,但是剩余的钩子和生命周期将继续,就像钩子成功一样。
  10. 容器过程退出。这可能是由于错误,退出,崩溃或 kill 调用运行时的操作而发生的。
  11. delete 使用容器的唯一标识符调用运行时的命令。
  12. 必须通过取消在创建阶段(步骤 2)执行的步骤来销毁容器。
  13. 该 poststop 钩子必须由运行时调用。如果有任何 poststop 钩子失败,运行时必须记录一个警告,但是剩余的钩子和生命周期将继续,就像钩子成功一样。

容器操作:

runtime 还对 oci 实现的命令行进行了规定:

用途 命令 介绍
状态查询 state <container-id> 此操作务必返回“容器状态”部分中指定的容器状态。
创建容器 create <container-id> <path-to-bundle> 此操作必须创建一个新的容器。应用 config 中除了 process 的其他所有部分。
开始运行 start <container-id> 此操作必须运行所指定的用户指定程序 process。
结束运行 kill <container-id> <signal> 此操作必须将指定的信号发送到容器进程。
删除容器 delete <container-id> 删除容器必须删除在该 create 步骤中创建的资源。

在实现上,运行时不需要对 bundle 配置进行更改。

images spec

开放容器计划-镜像规范,该规范定义了一个 OCI 镜像,它由 manifest,image-index(可选),一组文件系统 layer 和一个配置组成。 本规范的目标是允许创建可互操作的工具,以构建,运输和准备要运行的容器映像。

该规范将容器镜像的组成,构建方式,传输方式均作了规定,目的是形成一个统一的格式。

与众多传输规范一样,oci image 也指定了许多的 Media Types。先了解一下 image spec 使用了哪些东西:

descriptor

OCI 内容描述符,又成为描述符。用于描述每一个 OCI iamge spec 中的部件,在其他地方被称为“元数据”的有相似作用,为每个部件的公共部分。

内容描述符由以下字段组成:

image manifest

manifest 又称之为清单,有三个用途:

  1. 寻找镜像内容。内部包含了各镜像层(layer)的 hash 值。
  2. fat manifest 可以设置多架构的镜像内容。包含了不同架构的镜像 index。
  3. 内容可以转换为运行时规范

manifest 内容包含:

一个清单文件大概是这样:

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

image index

image index 又称为镜像索引,它是指向特定映像清单的较高级别的清单,适合一个或多个平台。 镜像索引使用application/vnd.oci.image.index.v1+json 媒体类型。

其内容包含:

一个镜像索引的示例为:

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

image layer

distrbution spec