Docker 与开放容器计划到底是什么关系?

来源:NET教程网作者:何守业头衔:网络博主
导读:本期聚焦于何守业创作的《Docker 与开放容器计划到底是什么关系?》,敬请观看详情。Docker 并不等于容器。严格来说,Docker 只是一套工具链,而开放容器计划 OCI 定义了容器运行和镜像分发的行业标准。很多人把 Docker 引擎与容器运行时划等号,其实从 Docker 1.11 起,Docker 已经把容器启动交给 containerd,再由 runc 按照 OCI runtime-spec 创建进程。也就是说,Docker 本身不再直接操作 cgroups 和 namespace,而是通过 OCI 兼容层完成。理解这层关系,才能明白为什么 Kubernetes 可以替换 Docker 为 containerd 或 CRI-O,却不会影响 OCI 镜像的兼容性。本文会梳理 Docker 与 OCI 的演进背景、核心规范、组件分工,以及如何验证一个工具是否真正符合 OCI 标准。

容器技术的早期阶段,Docker 几乎就是容器的代名词。但随着生态走向标准化,Docker 已经不再是一个封闭的引擎,而是围绕开放容器计划 OCI 构建的模块化工具。要理解这一点,需要回到 Docker 的架构演进,以及 OCI 两个核心规范:runtime-spec 和 image-spec。本文将先梳理二者关系,再深入规范细节,最后给出验证兼容性的具体方法。

Docker 与开放容器计划到底是什么关系?

一、从 Docker 引擎到 OCI 标准:一次关键的架构拆分

早期 Docker 把镜像构建、容器运行、镜像分发都塞在 docker daemon 中。这种单体架构虽然上手快,但一旦需要调度大规模容器,就会暴露出与 Kubernetes、Mesos 等编排系统的耦合问题。2015 年,Docker 联合 CoreOS、Google、Red Hat 等公司发起开放容器计划 Open Container Initiative,简称 OCI,目标是以厂商中立的方式定义容器运行时和镜像格式。Docker 把底层运行时 libcontainer 捐给 OCI,成为 runc 的前身,同时把镜像格式草案作为 OCI image-spec 的基础。这个拆分让 Docker 本身可以继续专注用户体验,而更底层的容器创建、启动、停止则由独立组件完成。

这一变化并不是简单的代码搬家。它意味着容器的接口被标准化了,任何实现 OCI runtime-spec 的运行时都可以接管同一个容器 bundle,任何实现 OCI image-spec 的镜像都可以在不同工具之间流转。对 Docker 来说,它从事实标准转变为遵循标准的角色,反而推动了整个云原生生态的健康发展。现在我们在服务器上看到的 Docker,实际上由 Docker CLI、dockerd、containerd、runc 多层组成,runc 是真正读写 cgroups 和 namespace 的 OCI 运行时。

二、OCI 两大规范拆解:runtime-spec 与 image-spec

OCI 规范由两个独立文件组成。runtime-spec 定义容器的配置文件格式、运行生命周期、状态机,以及 hooks 的调用时机。一个符合规范的容器 bundle 必须包含 config.json 和 rootfs 目录。config.json 中声明了进程入口、环境变量、挂载点、Linux 资源限制、namespaces 设置等。runc 就是根据这份 config.json 来创建进程,并在结束后返回状态。可以手工编辑 config.json 再交给 runc 执行,这就解释了为什么不同厂商的容器运行时能够互相替换。

image-spec 则负责镜像的存储和分发。一个 OCI 镜像在磁盘上通常以目录形式存在,包含 index.json、oci-layout 文件和 blobs 目录。blobs 中保存了 manifest、config 和 layer 的压缩包,全部通过 sha256 摘要寻址。这种内容寻址设计让镜像层可以被安全地复用。Docker 自 1.10 起开始采用内容寻址的镜像 ID,正是向 OCI 规范靠拢。用户用 docker save 导出的 tar 包,在较新版本中已经与 OCI 镜像布局兼容。第三方工具如 skopeo、crane 可以跨 registry 复制镜像,其底层原理就是操作这些 OCI 结构。

经常有人把 OCI 与 CRI 混淆。CRI 是 Kubernetes 定义的容器运行时接口,面向的是高层运行时与 kubelet 之间的 gRPC 协议;而 OCI 是更底层的标准,关注单个容器的进程和文件系统。containerd 同时实现了 CRI 和 OCI 调用,这也是它能替代 Docker 直接服务于 Kubernetes 的原因。

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:abc...",
    "size": 1234
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:def...",
      "size": 5678
    }
  ]
}

三、runC 与 containerd:Docker 背后的 OCI 运行时链

runC 最初叫 libcontainer,被捐赠给 OCI 后成为官方参考实现。它体积小、职责单一,只做一件事情:加载 bundle,解析 config.json,创建 namespace、cgroups、挂载 rootfs,启动进程。runC 不处理镜像拉取、网络设置、日志这些上层能力。你可以直接在命令行中安装 runC,创建一个 rootfs,然后用 runc spec 生成模板配置,再执行 runc run 启动一个最小容器。这种直接操作的方式非常有利于理解容器底层原理。

containerd 则是一个常驻守护进程,管理容器的完整生命周期。Docker 通过 gRPC 调用 containerd,containerd 再调用 runC 或其它 OCI 运行时。在 Kubernetes 节点上,kubelet 可以直接通过 CRI 插件与 containerd 通信,不再需要 dockerd。由此可见,Docker 中的容器创建能力其实与 Kubernetes 使用的 containerd 是同一条链路。用户切换运行时后,原有的 OCI 镜像不需要任何改动,因为镜像和运行时规范已经解耦。

验证这条链路最直接的方法是查看 docker info 中的 runtime 信息。你会看到默认 runtime 是 runc,并且注册了 io.containerd.runc.v2。还可以用 docker buildx 构建一个 OCI 格式的镜像,再用 nerdctl 或 ctr 导入运行。如果这些操作都能成功,就说明镜像和运行时都严格遵循了 OCI 规范。

# 查看 Docker 使用的默认 OCI 运行时
docker info | grep -i runtime

# 直接用 runc 启动一个最小容器
mkdir -p /tmp/mycontainer/rootfs
docker export $(docker create busybox) | tar -C /tmp/mycontainer/rootfs -xvf -
cd /tmp/mycontainer
runc spec
runc run mycontainer

四、OCI 兼容性带来的实际问题与验证

当团队决定从 Docker 迁移到 containerd 或 Podman 时,最关心的是现有镜像能否继续使用。答案通常是可以,因为只要镜像满足 OCI image-spec,支持 OCI 的工具就能拉取并运行。例如 Podman 默认以 OCI 格式存储镜像,Docker pull 下来的镜像在 quay 等 registry 上同样可以被 Podman 使用。部分老旧的 Docker 镜像可能因为使用不受支持的 schema 或非法配置而失败,但这种情况已经很少见。遇到兼容性问题时,可以用 skopeo inspect 查看 manifest 的 mediaType,判断是否包含 vnd.oci 或 vnd.docker 前缀。Docker 和 OCI 的 manifest 在 schemaVersion 2 下高度相似,OCI 规范兼容 Docker 格式,反之则不一定所有 OCI 扩展都能被旧版 Docker 识别。

另一个常见误区是认为 OCI 定义了网络和存储标准。实际上 OCI 不包含 CNI 或 CSI 这类接口。容器网络由 CNI 插件负责,存储由 CSI 驱动负责。OCI 只解决两个问题:一个容器进程怎么启动,以及一个镜像怎么打包和分发。所以即使两个工具都宣称 OCI 兼容,它们的网络实现可能完全不同。用户在选择时需要区分 oci runtime 兼容与 k8s 运行时类别的差别。

验证一个运行时是否符合 OCI 规范,可以使用 OCI 官方提供的 runtime-tools 工具。它包含 runtime validation 测试,通过执行一系列命令检查 runtime 是否正确实现了规范要求。也可以自己制作一个简单的 rootfs,用 runc spec 生成配置后,尝试用目标运行时启动。例如把 config.json 和 rootfs 复制到另一个目录,再调用 crun 或 youki 运行。只要能正常启动并看到相同输出,就说明这些运行时在 OCI 层面是可互换的。

Docker开放容器计划OCI规范修改时间:2026-10-06 09:09:58

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1006/66392.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。