“ Docker support in the kubelet is now deprecated and will be removed in a future release. The kubelet uses a module called "dockershim" which implements CRI support for Docker and it has seen maintenance issues in the Kubernetes community. We encourage you to evaluate moving to a container runtime that is a full-fledged implementation of CRI (v1alpha1 or v1 compliant) as they become available. (#94624, @dims) ”
随着Kubernetes 1.20的发布,关于“kubernetes不再支持Docker!Docker不能用了!以前的Docker镜像不能用了!”等声音不绝于耳,事实真的是这样吗?
Mobvista 集团副总裁兼首席架构师
深入细节
要了解事情的真相,就要深入其细节。那就让我们来看看于此相关的细节吧。
1. 关于容器
容器 = cgroup + namespace + rootfs + 容器运行时
cgroup:资源控制
cgroup 是 control group 的简称,是 Linux 内核提供的一个特性,用于限制和隔离一组进程对系统资源的使用,如:CPU,内存的使用等。
namespace:访问隔离
Namespace 是将内核的全局资源做封装,使得每个namespace 都有一份独立的资源,因此不同的进程在各自的namespace内对同一种资源的使用互不干扰,例如,hostname,进程ID和用户组等在各个namespace里都是独立的。
rootfs:文件系统隔离。镜像的本质就是一个rootfs文件
容器运行时:生命周期控制
2. 关于Docker
其实与很多人的认识不同,Docker本身并不是容器,它是创建容器的工具,是容器运行时。想要搞懂Docker,其实看它的两句口号就行。
"Build, Ship and Run"
"Build once,Run anywhere"
3. 关于Kubernetes
Kubernetes是一个容器编排平台,用于容器应用的自动化发布,伸缩和管理。
那么Kubernetes是如何实现容器管理的呢?
如我们所知container/pod是运行在node上的,kubernetes在每一个node上都有一个kubelet用于管理node的container/pod。所以,最直观的想法就是kubelet直接调用一个容器运行时(container runtime),如Docker去创建和管理node上的container。
但是这样的简单连接会带来一个问题,如果Kubernetes要去支持更多不同的容器运行时实现, 就要为不同容器运行时开发不同的kubelet去适配。为了解决这个扩展性问题,Kubernetes 1.5里引入了CRI(Container Runtime Interface)。CRI定义了kubelet支持的容器运行时的标准接口(一组gRPC调用),这样就变成了容器运行时要通过支持CRI来主动适配Kubernetes。
另一方面,Docker也在发生着改变
为了避免容器的生态分裂为“小生态王国”,确保一个引擎上构建的容器可以运行在其他引擎之上,2015年由多家公司共同成立的项目OCI (Open Container Initiative),并由linux基金会进行管理,致力于容器运行时标准的制定。
Docker从原有的libcontainer中演化出了支持OCI的runC。容器运行时管理也从Docker Daemon中抽离出来,放到了一个叫containerd的进程中,containerd是一系列容器操作的facade,并最终通过runC来完成容器的操作。由此最终kubernetes和docker的关系变成了下面这样。内置在kubelet中Docker shim是为了让Docker Daemon适配CRI标准。
从上图大家发现Containrd已经是一个容器运行时了,那么Docker Daeamon显得冗余,这样Kubernetes就可以进行1.20版本中提到的简化。
这样的结构将变得更加简化且合理,containerd的适配也通过在其中增加CRI-plugin来实现了,这样containerd就变成了一个支持CRI的容器运行时了。
传说中的Docker继任者
在一片Docker被放弃了的呼声中,大家听到最多还有CRI-O和Podman,他们似乎是Docker的继任者。
首先,我们来看看CRI-O,由上面的内容可以知道其实,和kubernetes协同工作并支持现有的标准容器,就需要一个容器运行时能够桥接CRI和OCI,那么整个架构就可以大大简化,Redhat推出的CRI-O就是这样情况定制的容器运行时。
Podman是Redhat公司推出的容器管理工具(CRI-O并没有提供创建镜像,推送镜像至镜像库等功能),Podman起初是CRI-O的一部分,后来单独分离出来叫做libpod,使用Podman的命令几乎和docker类似,事实上podman可以说兼容了docker的CLI,您甚至通过alias docker=podman来简单的替换Docker。
结论
Docker并没有被抛弃,未来kubernetes实际要去除的是对现有Docker运行时(Docker Daemon)的支持,通过去除了kubelet中Docker Shim来实现。这是kubernetes的一种标准化和简化,同时,应该注意到Docker实际在这些相关标准的制定中一直以来起着非常重要的作用。并且Docker给出的相关参考实现,如containerd,runC将继续被使用。
Docker运行时1.20中只是deprecated而不是removed,即Docker运行时可以正常使用。
即使在1.22版本kubelet移除docker shim后,docker 镜像还是可以使用的(docker镜像是符合OCI的)
这个影响主要是运维和管理,对于开发的影响极小。即使要替换为podman,podman也是docker cli兼容的。