近几年,Kubernetes 已经成为自有机房、云上广泛使用的容器编排方案,最广泛的使用方式是 Kubernetes+Docker。从 DevOps 人员的角度,一面用 kubctl 命令、k8s API 来操作集群,一面在单机用 Docker 命令来管理镜像、运行镜像。


单独用 Docker 的情况,在一些公司的场景里面也是有的。一种场景是“只分不合”,把一台机器用 Docker 做资源隔离,但是不需要将多容器“编排”。单独用 Kubernetes,下层不是 Docker 的情况,并不算很多。


Kubernetes 和 Docker 的关系,简单来说,有互补,也有竞争。在一般的认知中,Kubernetes 和 Docker 是互补关系:


· Dockers属于下层——容器引擎;

· Kubernetes属于上层——编排调度层。


Docker 源于 Linux Container,可以将一台机器的资源分成 N 份容器,做到资源的隔离,并将可运行的程序定义为标准的 docker image;Kubernetes 则可以把不同机器的每份容器进行编排、调度,组成分布式系统。


Kubernetes 和 Docker 并不完全是“泾渭分明”的互补关系,它之间有重叠部分,也可以说成是竞争,主要在于几个点:



系统三大移植资源是计算、存储、网络,从Kubernetes角度Docker属于“Runtime(运行时)”,也就是计算资源;但是Docker技术体系里面,本身也包括存储层、网络层。上下层职责的重叠,也可以看作竞争。

Docker原本有个原生的调度引擎——Swarm,几年前在调度编排领域,还是Kubernetes、Mesos、Swarm三者并存,Kubernetes最终胜出,但Docker仍有“继续向上做一层的意愿”。


Kubernetes决定弃用Docker,到底会影响到谁?_docker


Kubernetes 在如何使用 Docker 方面,存在争议和变数。kubernetes 1.20 ChangeLog 中所谓要废弃 Docker 的传言,也是无风不起浪。换句话说,即便 Kubernetes 一直用 Docker,也不是用 Docker 的全部,多少是不一样的。


Kubernetes决定弃用Docker,到底会影响到谁?_docker_02


而且,“弃用 Docker”这个词本身有多重的含义,Docker 并非一个单层软件,Kubernetes 1.20 启用 dockershim 并不代表弃用了 Docker 的全部,仍有 containerd 可以对接 docker。

Kubernetes 有 CRI、OCI 两个容器标准


在目前广泛使用 kubernetes 与 Runtime 的桥接方案,CRI(Container Runtime Interface)与 OCI(Open Container Initiative)是“套娃“关系。Kubernetes 的 kubelet 调用 CRI,OCI 的实现者然后再调用 OCI。


下图也说明了 CRI 与 OCI 的关系:


Kubernetes决定弃用Docker,到底会影响到谁?_守护进程_03


从 Kubernetes 的角度,CRI 是与 CNI(网络)、CSI(存储)相同层级的接口。


OCI 是个自下而上的标准,也就是从实现抽象出接口,它是 Linux Foundation 主导的。Docker 实现的核心 RunC,也就是 OCI 的典型实现、标准实现。


CRI 是个自上而下的标准,源于 Kubernetes 对移植层(运行时)的要求。


容器引擎层自下而上定义 OCI,容器编排层自上而下定义 CRI,这也让它们出现了“套娃“运行情况。


在 Kubernetes 的 dockershim、cri-containerd、cri-o 三种实现中,RedHat 推崇的 cri-o 已经比较主流,它虽然仍是“套娃“,但已经比较精简。


Kubernetes决定弃用Docker,到底会影响到谁?_docker_04


下面是从 kubernetes 集群运行的全景图看 cri-o 的位置:


Kubernetes决定弃用Docker,到底会影响到谁?_守护进程_05

Docker 本源于 Linux Container


Docker 作为容器引擎,其实现的基础是 Linux Container——从内核到用户空间的机制。


Linux Container 可以分成两个部分,内核里面的 cgroup,用户空间的 lxc。Docker 最初实现的时候,也是完全基于 Linux Container 的,基于 lxc 做更上层的东西。


这张很多人认为“与事实不符“的图,其实代表了过去:


Kubernetes决定弃用Docker,到底会影响到谁?_linux_06


在 Docker 的发展过程中,最终启用了 C 语言写成 lxc,换成了 go 语言写成的 libcontainer。


下面的图也不是很新,但它更能表示 Docker 后续典型的架构,这里面已经没有了 lxc。


Kubernetes决定弃用Docker,到底会影响到谁?_守护进程_07


然而,万变不离其宗,Docker 实现的本源,还是 Linux Container。即便不用 lxc,当仍要用内核的 cgroup,并且模式也是类似的。

Kubernetes 最终如何桥接容器


从纯技术的角度,与其讨 Kubernetes 与 Docker 关系,不如讨论 Kubernetes 与最终容器实现层的关系。因为 Docker 这个名词,在不同的时候,有着不同的内涵、外延。


下面是 Docker 的简图:


Kubernetes决定弃用Docker,到底会影响到谁?_docker_08


从软件模块的角度,图中的 docker Engine、cri-containd、containd-shim、runC 都属于 Docker 体系的软件。


下图中的紫、橙、红三种颜色,代表了 dockershim、cri-containerd、cri-o 三种 CRI 的典型方式——流程在逐渐缩短,这也是 CRI 实现的一个演进过程。


Kubernetes决定弃用Docker,到底会影响到谁?_守护进程_09


如果是 kubelet 的 dockershim 模式(紫色),流程是这样的:


· kubelet从CRI的gRPC调用dockershim,二者在同一个进程

· dockershim调用docker守护进程

· docker守护进程调用containerd;containerd调用containerd-shim(有时名为docker-containerd-shim守护进程)完成创建容器等操作

· containerd-shim访问OCI的实现runC(命令行可执行程序)


如果是 kubelet 的 cri-containerd 模式(橙色),流程是这样的:


· ​kubelet从CRI的gRPC调用cri-containerd;

· ​cri-containerd调用containerd;containerd调用containerd-shim(同上)

· ​containerd-shim调用RucnC (同上);


在很多人的印象中,如果不用 docker 守护进程,就相当于“弃用 docker“,这其实也就是从 dockershim 到 containerd 的变化。从另一个角度来说,containerd 这个守护进程,也是 docker 组织做的。


如果是 kubelet 的 cri-o 模式(红色),则更加简练:


· ​kubelet从CRI的gRPC调用cri-o;

· ​cri-o调用OCI的实现runC


如果以 kubelet 调用 CRI 为起点,OCI 的 runC 调用为终点,三种模式经历的可执行程序分别是:


· dockershim模式:dockershim(*)->dockd->containerd->containerd-shim

· cri-containerd模式:cri-containerd(*)-> containerd->containerd-shim

· cri-o模式:cri-o


dockershim 模式有 3 个可执行程序,dockershim 一般与 kubelet 同进程;cri-containerd 模式有 2-3 个可执行程序,cri-containerd 可与 containerd 同进程;cri-o 模式只有 1 个可执行程序。


显然在这种 Red Hat 推崇的 cri-o 模式下,Docker 体系的 containerd 也用不着了,只剩 runC 这个命令行的程序。runC 也是用 go 写成的,里面有调用 libcontainer。


当 Docker 萎缩到这个地步,其实也只剩 Linux 内核里面 cgroup、namespace 功能的封装了。


总结来说,由于老技术实现的惯性,在生产环境大量使用的经典 Kubernetes+ Docker 方案依然运行,且运维已经成熟,不会很快升级。对于开发人员、企业,对于 K8S API 的使用频率、变数,远远大于 Docker API,至于 Kubernetes 和 Docker 的桥接,更不用关心。因此,即便“彻底弃用 Docker”,对开发者与企业的影响也非常有限。

​​



- END -

Kubernetes决定弃用Docker,到底会影响到谁?_linux_10