背景
Kubernetes在v1.20提出Dockershim Removal Kubernetes Enhancement Proposal
kep就有计划将dockershim模块从kubelet中移除,经过几个版本的迭代,在kubernetes 1.24发布的时候彻底移除掉dockershim。 dockershim 模块存在于kubernetes的kubelet中,kubelet通过dockershim来对接docker创建容器。其中的关系图一所示
其工作流为当pod调度到某个节点,该节点的kubelet list-watch到了pod,则会触发pod创建的过程,pod创建的时候会通过CRI来调用dockershim的方法,之后dockershim调用docker提供的api,完成相关容器的创建命令的下发。之后docker通过调用containerd完成最终container的创建任务。
为了更好的推动kubenretes以及CRI的发展,kubernetes提出了移除dockershim的kep。主要是基于以下几点考虑:
历史包袱:早期kubernetes版本,只支持docker engine一种特定的container runtime, docker engine本身并没有支持CRI接口规范,所以kubernetes project中包含了特定的代码来做这种转化,使得dockershim代码变成了kubernetes一部分。
CRI规范推进以及kubernetes自身的发展:随着kubernetes发展,维护dockershim模块变成了一种巨大的负担。未来随着newer CRI runtime中将会引入以及cgroups v2以及user namespaces等新特性的支持,涉及到大量dockershim的兼容工作要做,移除dockershim对于未来推动CRI发展至关重要。
解决方案
Completely remove in-tree dockershim from kubelet by dims · Pull Request #97252 · kubernetes/kubernetes (github.com) 中彻底移除了dockershim的代码,如何需要升级到>1.24v的k8s,则将不能直接将docker作为默认kubelet的engine。移除dockershim之后,我们可以采用的常见的替代方案,通过下图的对比就可以清晰的几种差异
cri-dockerd方案
cri-dockerd由mariadb开源贡献,类似与将kubelet中的dockershim模块由cri-dockerd来承担,实现了通过CRI与kubelet交互,与docker api进行交互,对于仍然想使用docker来创建容器的一个可行的替代方案。但是缺点也很明显,调用链更长,也就意味着整个创建容器的过程并不是很高效,而且故障定位更加的困难。
Containerd方案
作为一个比较推荐的方案,调用链路更加的短和高效,并且containerd也是作为docker的后端广泛的验证,可靠性有一定的保障,社区更加的活跃,对于runc和kata-container容器支持的挺好。
CRI—O方案
CRI—O是Redhat联合IBM, Intel, SUSE 以及其他厂商提出的支持CRI container runtime, openshift默认支持的CRI-0。其是另外一种高层次的container runtime,类似于containerd,同样实现container Runtime interface(CRI)。它支持从仓库拉取容器image,以及启动一个低层次的runtime来运行容器进程。
容器应用改造
采用containerd或者CRI-0方案,彻底脱离了docker,但是对于存量的容器系统应用可能依赖docker,所以社区在废除dockershim给出了很多建议让用户去判断你的容器化应用是否依赖于docker,如果依赖于docker则需要去对应用本身的改造,可以从以下几个方面判断是否依赖于docker。
kubernetes平台中的应用是否存在特权pod,该类型的pod有可能会执行docker的命令、调用docker提供的api、restart docker服务或者修改docker相关配置。
是否配置过docker的配置 /etc/docker/daemon.json,例如配置私有镜像仓库或者image mirror,需要做相应的调整
判断在kubernetes平台之外,运行在物理机上的脚本或者其他运行,是否会去执行docker命令,这些可能包括
ssh 到node上执行的运维命令
node启动脚本
监控或者安全相关的agent,平台组件容器
第三方提供的工具的操作是否涉及到上面提到的特权操作
确保整个平台没有对dockershim行为的间接依赖。例如有些工具可能被配置为对特定的docker行为做出反应,例如,对特定的指标发出警报,或搜索特定的日志消息,作为故障排除说明的一部分。如果您配置了这样的工具,那么在迁移之前在测试集群上测试其行为。
按照上述提示,去评估应用以及kubernetes平台是否依赖于docker,如果依赖则建议对其改造,支持containerd或者CRI-O。
集群升级
实际适配改造的过程中,我们会发现一些应用可能是第三方供应商提供,适配改造需要一定的时间,针对这种情况,则需要在集群中既要支持containerd/CRI-0,也要能够采用cri-docker来部署对于依赖docker的应用,则我们对于原集群进行升级的时候,可以采用如下的流程策略,这里以k8s 1.23升级到k8s 1.24来进行说明,这里的k8s集群是通过kubeadm来构建出来的
当前集群是1.23版本,采用kubelet,dockershim的方式对接docker, 由1个master和3个node组成的k8s集群,3个node分别是node1、node2、node3。
其上部署demo应用,yaml如下
apiVersion: apps/v1 kind: Deployment metadata: name: demo labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 |
需要将该集群升级到1.24版本,采用containerd方案,对于docker依赖的应用采用cri-docker的方案
首先
Step1: 在现有集群中加入两个节点node4/node5,node4、node5采用cri-docker与kubelet对接,其上只承载对于docker有依赖的应用。node4、node5通过label组成一个特殊的资源池,并加上taint,加上taint是为了不允许非依赖的docker的应用部署。
[root@node1 archos]# kubectl label node node4 ake.io/container-runtime=cri-dockerd node/node4 labeled [root@node1 archos]# kubectl taint node node4 ake.io/container-runtime=cri-dockerd:NoSchedule node/node4 tainted [root@node1 archos]# kubectl label node node5 ake.io/container-runtime=cri-dockerd node/node5 labeled [root@node1 archos]# kubectl taint node node5 ake.io/container-runtime=cri-dockerd:NoSchedule node/node5 tainted |
Step2:将依赖docker的应用迁移到cri-dockerd的资源池中,通过在demo应用中增加node亲和性以及tolerations信息,如下所示
apiVersion: apps/v1 kind: Deployment metadata: name: demo labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: ake.io/container-runtime operator: In values: - cri-dockerd tolerations: - key: "ake.io/container-runtime" operator: "Equal" value: "cri-dockerd" effect: "NoSchedule" containers: - name: nginx image: nginx:1.14.2 |
下面采用驱逐的方式对k8s集群从1.23版本升级到1.24版本
Step3:首先升级master节点,升级过程中完成cri的切换,使用containerd方案
Step4: 升级原资源池中的node,升级过程中完成对于cri的切换, 升级node过程中首先分批次驱逐node上所有的pod,完成pod驱逐之后,则升级其上的组件,升级到k8s 1.24版本
Step5: 升级cri-docker资源池,升级node过程中首先分批次驱逐node上所有的pod,完成pod驱逐之后,则升级其上的组件,升级到k8s 1.24版本。
至此整个k8s集群已经升级到1.24版本,集群默认采用containerd,对于依赖于docker的容器化应用,通过调度规则调度到cri-dockerd的资源池。
总结
dockershim的移除在k8s 1.24是一个重大的调整,本文详细介绍了当前可选的解决方案以及社区相关的建议,便于更好的应对这个变化。相信dockershim从kubernetes主干代码的移除,能够更加激发CRI领域的创新,并且kubenretes的整体架构以及代码变得更加的优雅。
责任编辑:kj005
文章投诉热线:156 0057 2229 投诉邮箱:29132 36@qq.com