OCI 容器镜像与运行时规范

FreeGuideOnline 最新 2026-07-04

myimage/ └── blobs └── sha256 ├── # JSON 格式的 Manifest ├── # JSON 格式的 Image Config ├── # 压缩的 tar 层文件 └──


### 2.3 Image Manifest 详解
Manifest 是一个 JSON 文档,关键字段:

```json
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:...",
    "size": 1234
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:...",
      "size": 567890
    }
  ]
}
  • config 指向 JSON 格式的镜像配置。
  • layers 是一个有序列表,基础层在前,上层在后,运行时联合挂载为根文件系统。

2.4 Image Configuration 详解

Image Config 定义了如何使用镜像创建容器,部分重要字段:

{
  "created": "2025-01-01T00:00:00Z",
  "author": "tutorial",
  "architecture": "amd64",
  "os": "linux",
  "config": {
    "Env": ["PATH=/usr/local/sbin:/usr/local/bin:..."],
    "Cmd": ["/bin/sh"],
    "WorkingDir": "/",
    "Volumes": {"/data": {}}
  },
  "rootfs": {
    "type": "layers",
    "diff_ids": ["sha256:abc...", "sha256:def..."]
  }
}
  • config 部分镜像 Dockerfile 中的指令(ENV、CMD、ENTRYPOINT 等)。
  • rootfs.diff_ids 是每一层未压缩内容的 SHA256,用于验证层完整性。

2.5 文件系统层与媒体类型

  • 层格式tar 归档,可选择压缩(gzip、zstd)。
  • 媒体类型(Media Types)
    • 清单:application/vnd.oci.image.manifest.v1+json
    • 配置:application/vnd.oci.image.config.v1+json
    • 层(gzip):application/vnd.oci.image.layer.v1.tar+gzip
    • 层(zstd):application/vnd.oci.image.layer.v1.tar+zstd

层的变更通过 Whiteout 文件实现删除,格式为以 .wh. 开头表示该文件或目录被删除。

3. OCI 运行时规范核心概念

运行时规范定义了如何将文件系统包(bundle)转换成运行的容器实例。

3.1 容器 Bundle(文件系统包)

一个 OCI Bundle 是一个目录结构:

bundle/
├── config.json    # 容器的完整运行时配置
└── rootfs/        # 容器的根文件系统(可由 OCI 镜像展开得到)

3.2 config.json 关键字段

根据 OCI 运行时规范,config.json 文件必须包含:

  • ociVersion:规范版本(如 "1.1.0"
  • process:容器启动进程信息(terminaluserargsenvcwd
  • root:文件系统路径与只读设置(path:相对 bundle 的 rootfs 路径,默认 "rootfs"
  • mounts:挂载点列表(proc、sys、cgroup 等)
  • linux(以 Linux 为例):命名空间(namespaces)、能力(capabilities)、seccomp、资源限制等。

示例片段:

{
  "ociVersion": "1.1.0",
  "process": {
    "terminal": true,
    "user": { "uid": 0, "gid": 0 },
    "args": ["/bin/sh"],
    "env": ["PATH=/usr/bin"],
    "cwd": "/"
  },
  "root": {
    "path": "rootfs",
    "readonly": false
  },
  "linux": {
    "namespaces": [
      {"type": "pid"},
      {"type": "network"},
      {"type": "mount"}
    ]
  }
}

3.3 容器生命周期与状态

运行时规范定义了严格的状态转换:

  • 创建 (creating):从 config.json 和 rootfs 初始化容器环境(命名空间、cgroup 等)。
  • 已创建 (created):环境已准备,尚未执行用户进程。
  • 运行 (running):用户进程已启动并执行。
  • 停止 (stopped):容器主进程退出,所有关联资源保留(除非容器进程被杀死)。

允许的操作:

  • create → 进入 created 状态
  • start → 从 created 进入 running
  • kill → 发送信号,进程终止后进入 stopped
  • delete → 释放 stopped 容器的资源

3.4 运行时 hook

支持在容器生命周期关键点插入脚本(prestart、poststart、poststop),增强定制能力。

4. OCI 镜像与运行时的协作流程

一个典型的容器启动流程展示了二者如何配合:

  1. 解包镜像:运行时工具(如 runc)根据 OCI 镜像 Manifest 拉取 config 和所有 layers。
  2. 生成 rootfs:将各层按顺序提取、合并(使用 diff_ids 验证),形成 rootfs 目录。
  3. 组合 config.json:以镜像 Config 为基础,结合用户参数(端口映射、挂载卷等)生成符合 OCI 运行时规范的 config.json
  4. 启动容器:调用 createstart,容器运行。

这种解耦设计使得任何 OCI 兼容的镜像都可以被任何 OCI 兼容的运行时执行,无需转换。

5. 如何与 OCI 规范交互

5.1 使用工具构建 OCI 镜像

  • Buildah:专门构建 OCI 镜像,无需守护进程。
    buildah bud -t myapp .
    
  • podman:执行 podman build 直接生成 OCI 标准镜像。
  • docker:Docker 镜像遵循 OCI 规范(Docker 镜像格式与 OCI 略有不同,但主流运行时均兼容)。

5.2 使用符合 OCI 的运行时

  • runc:OCI 参考实现,最广泛使用的低层运行时。
  • crun:用 C 编写的快速替代品。
  • youki:Rust 实现,内存安全。

运行示例(使用 runc 手动启动 bundle):

# 进入 bundle 目录
cd /mycontainer
runc run mycontainer

5.3 检查和转换

  • skopeo:在不同仓库间复制、检查 OCI 镜像。
    skopeo copy docker://alpine:latest oci:alpine-local
    
  • umoci:操作 OCI 镜像布局,可解包成 OCI bundle。
    umoci unpack --image alpine:latest bundle