前言
容器技术很早就有了,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:(垫片)containerd 每次都会启动一个新的 docker-containerd-shim
进程来创建容器,让这个进程成为容器的父进程。这样的好处,一方面可以跟 containerd 解耦(不至于一个 containerd 挂了所有容器跟着挂)另一方面当容器的 pid=1 进程退出了可以接管容器的子进程进行清理工作。他直接通过指定的三个参数:容器id,boundle目录(containerd的对应某个容器生成的目录,一般位于:/var/run/docker/libcontainerd/containerID),运行时二进制(默认为runc)来调用 runc 的 api 创建一个容器。
CRI 接口
CRI(Container Runtime Interface 容器运行时接口),kubelet 调用容器运行时的 grpc 接口。早期 kubernetes 直接通过硬编码的方式支持 docker,后面 Kubernetes 为了支持更多更精简的容器运行时,Google 就和红帽主导推出了 CRI 标准。
- dockershim:CRI 标准推出早期影响力有限,很多容器运行时不会主动去实现 CRI 接口,于是有了一层 shim(垫片,适配层)。又因为 docker 的地位很高,所以 dockershim 直接被内置在 kubelet 中。但是 kubernetes 1.21 版本已经将其标注为废弃接口,此事件一顿引起社区对 docker 未来的担忧。但从另一个角度看,docker 将自己的核心功能整合开源了 containerd,通过 containerd 可以直接操作容器的整个生命周期。而且现在 containerd 是社区标准实现,所以 k8s 废弃 docker-api,改为直接对接 containerd 无可厚非,kubernetes 的开发者相同的一个功能点不用往2个地方都去兼容,整个调用链路也会缩短。
- CRI-containerd:最早 containerd 还会去适配其他系统(swarm) 没有直接实现 CRI,所以实现的任务就交给 cri-containerd 这个 shim。 containerd 1.1 版本后就去掉了 CRI-Containerd 这个 shim,直接把适配逻辑作为插件的方式集成到了 containerd 主进程中。
- CRI-O:专注于 kubernetes 运行容器的轻量级 CRI 接口实现,由 redhat 发起并开源且由社区驱动的 container-runtime,其主要目的就是能够取代 docker 作为kubernetes集群的容器运行时。他只能配合 kubernetes 使用,不能像 docker功能一样全能独立运行管理容器。
链路调用关系演进
一开始
kubectl -CRI-> dockershim -> docker -> containerd -> containerd-shim -> runc
去除 docker
kubectl -CRI-> cri-containerd -> containerd -> containerd-shim -> runc
cri-containerd 提炼到 containerd 里面
kubectl -CRI-> containerd -> containerd-shim -> runc
小结
- 我们如果要使用容器,不一定非要用 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"
发表评论 取消回复