我们都知道早期的k8s需要部署docker环境,k8s通过在node节点部署kubelet来调用docker的API来创建pod,只不过这里不是直接调用,而是通过一个dockershim的适配层来作为请求的转化,那为什么k8s的1.24版本后要弃用docker和dockershim呢?
首先我们看一下早期的k8s是如何使用docker创建容器的?
1.kubelet通过CRI接口调用dockershim,请求创建一个容器。
2.dockershim收到请求,转化为docker api发送到docker daemon上请求创建一个容器。
3.docker在1.12版本后,作为一个单体引擎,拆分为3个部分:runC,containers,dockerd。
Dockerd本身并不能创建容器,而是要请求contained来创建容器。
4.containers收到请求后,并不直接创建容器,而是创建一个contained-shim的进程去操作容器。
5.contained-shim在这一步调用runC这个命令工具来启动容器。
6.runC启动完容器后会直接退出,containerd-shim作为容器进程的父进程,负责收集容器进程的状态上报给 containerd。
这里声明一下什么是容器运行时?
容器运行时分为高层运行时(contained)和低层容器运行时(runC),高层运行时主要工作时拉取和解压镜像,低层运行时负责容器的生命周期管理。
综上可以看出,dockershim和docker在k8s创建容器的过程中,只是起到了一个翻译和连接的作用。kubelet和containerd之间直接通信是k8s想做的。containerd从docker中拆分出来捐献给CNCF,并且containerd通过集成CRI plugin对k8s的CRI完成了实现。使得kubelet可以和containerd直接通信。
总的来说,早期的k8s因为docker的热门而选择兼容它,后期的k8s因为dockershim高昂的维护成本以及想要更多的cri插件而选择弃用docker。也有一点儿“渣男”的味道了。