前言
容器技术很早就有了,Docker 是目前最广泛的容器引擎技术, 使用 Linux Cgroup namespace 等技术分隔进程。为了更好的规范容器技术的发展,Docker、CoreOS 和容器行业中的其他领导者在 2015年6月共同发起了 Open Container initiative(OCI) 基金会。OCI 基金会领导社区进行制定了相关规范,主要包括:
- 镜像规范(image spec)
- 运行时规范(runtime spec)
Docker 在容器社区的贡献
在 OCI 基金成立后,Docker 将自己 libcontainer 实现移动到 runC 并捐赠给了 OCI。此时容器社区的运行时规范
有了第一个参考实现。runC 是一个轻量可移植的容器运行时,实现了容器的启停、资源隔离等功能。
2016 年,Docker 开源并将 Containerd 捐赠给了 CNCF,Containerd 几乎攘括了单机运行一个容器运行时所需的一切:执行、分发、监控、网络、构建、日志等。
从上图可以看出:containerd 向上为Docker Daemon 提供了gRPC接口,使得 Docker Daemon 屏蔽下面的结构变化,确保原有接口向下兼容。向下通过 containerd-shim 结合 runC,使得引擎可以独立升级,避免之前 Docker Daemon升级会导致所有容器不可用的问题。
dockerd(从 Docker 1.11 开始 docker Daemon 改为 dockerd) 本身实属是对容器相关操作的api的最上层封装。
containerd-shim:(垫片,可以理解为兼容方案)每启动一个容器都会起一个新的 docker-containerd-shim
进程,他直接通过指定的三个参数:容器id,boundle目录(containerd的对应某个容器生成的目录,一般位于:/var/run/docker/libcontainerd/containerID),运行时二进制(默认为runc)来调用 runc 的 api 创建一个容器。
CRI 接口
kubelet 调用容器运行时的 grpc 接口
- dockershim:kubernetes 对接 docker api 的 CRI 接口适配器,kubernetes 1.21 版本已经将其标注为废弃接口,此事件一顿引起社区对 docker 未来的担忧。但从另一个角度看,docker 将自己的核心功能整合开源了 containerd,通过 containerd 可以直接操作容器的整个生命周期。而且现在 containerd 是社区标准实现,所以 k8s 废弃 docker-api,改为直接对接 containerd 无可厚非,kubernetes 的开发者相同的一个功能点不用往2个地方都去兼容。
- CRI-containerd:通过 containerd 中的 CRI 插件实现了 CRI 接口,让 containerd 可直接对接 containerd 启动容器。当前最广泛的 CRI 接口实现。
- CRI-O:专注于 kubernetes 运行容器的轻量级 CRI 接口实现,由 redhat 发起并开源且由社区驱动的 container-runtime,其主要目的就是能够取代 docker 作为kubernetes集群的容器运行时。他只能配合 kubernetes 使用,不能像 docker功能一样全能独立运行管理容器。
小结
- 我们如果要使用容器,不一定非要用 docker,因为有多种容器运行时。
- docker 跟其他容器运行时相比功能比较全,但是也比较重。
- docker 已经将自己的核心技术封装成 containerd ,并开源出去了。docker daemon 也只是调用 containerd 的一层薄薄的封装 + 镜像、存储卷的一些功能。
- docker 默认的容器运行时是 runc,但是只要符合 oci 的 runtimespec 规范都是可以的。启动 Docker Daemon 时增加
–add-runtime
参数来选择其他的运行时实现。
docker daemon --add-runtime "custom=/usr/local/bin/my-runc-replacement"