kubernetes移除Docker?

标签: | 发表时间:2020-12-16 08:37 | 作者:
出处:https://mp.weixin.qq.com

两周前,Kubernetes在其最新的Changelog中宣布1.20之后将要弃用dockershime,也就说Kubernetes将不再使用Docker做为其容器运行时。

Dockershim deprecation Docker as an underlying runtime is being deprecated. Docker-produced images will continue to work in your cluster with all runtimes, as they always have.

这一消息持续发酵,掀起了不小的波澜,毕竟Kubernetes+Docker的经典组合是被市场所认可的,大量企业都在使用。看上去这个“弃用”的决定有点无厘头,那么为什么Kubernetes会做出这样的决定?这样做的原因又是如何?又会带来那些影响呢?今天,咱们就来掰扯一下。


首先,看一下目前在Kubernetes上如何使用Docker运行时来创建一个容器,如下:


  1. Kubelet 通过 CRI (Container Runtime Interface)接口调用 dockershim,来创建一个容器。从图上不难看出kubelet的这一步调用,是自己在调用自己,也确实如此,这是因为dockershim的代码目前是内嵌在 Kubelet中的,所以请求的发送和接收都是Kubelet;

  2. dockershim收到请求后,会转换成Docker API请求发给Docker Daemon去创建一个容器;

  3. DockerDaemon收到后,在将请求发送给containerd创建一个容器

  4. containerd收该请求后,会创建一个叫做containerd-shim的进程,对容器的操作统统交给containerd-shim去完成;

  5. containerd-shim再调用runC来实现容器的的启动

  6. runC完成容器的启动后便会退出,containerd-shim会成为容器的父进程


所以不难看出,一旦从kubelet中移除dockershim,上述流程中的第一步就会无法完成,创建容器的请求自然就无法发送到Docker daemo上,真可谓釜底抽薪,一招毙命。不过,这个流程确实繁琐,要在CRI,dockershim,docker daemo之间绕一下,聪明的你肯定会对此产生各种疑问,“为什么kubelet不直接去调用containerd呢?这个CRI又是什么呢?为什么kubelet不能直接发给Docker Dameon呢? 如果在Kubernetes上使用rkt又应该怎么做呢?”


有道是有人的地方就有江湖,有利益,有帮派,有明争暗斗。想当年kubelet想要创建容器直接跟Docker Daemon说一声就行,而那时containerd还没出生,Docker Daemon自己调一下libcontainer这个库就可以让容器跑起来。但随着容器市场的逐渐火热,每个厂家都想扎进来,“这大蛋糕可不能让Docker一家吃完啊,倒不是馋那一两口蛋糕,主要是考虑到胆固醇太高对Docker的身体不好,所以大家应该踊跃的为Docker分担一下”。Docker也知道众人拾柴火焰高的道理,这把大火能否将传统技术厂商的城池化为灰烬,成为吾之沃土,靠一个人是远远不够的,于是振臂高呼“我要健康,我要放火”,接着就联合各路的带头大哥,鼓捣出一个OCI标准,用来规范容器市场,营造更为和谐的容器生态环境。而且Docker为了符合OCI标准,更是以身作则,直接挥刀自宫,把xx切了,额。。。错了,是把runtime及其管理功能从Docker daemon中剥离了出来,随后Docker又把libcontainer封装了一下,变成runC,做了投名状,捐给了OCI。


Docker所作的可谓仁至义尽,但还是有人不满足,CoreOS还想搞事,也想成为Kubernetes的默认runtime,与Docker并驾齐驱。Kubernetes也在考虑我不能和某一家的容器技术栈绑死,用户的口味也各异,连区区豆腐脑都有甜咸之分,我这高科技产物也应该满足用户的差异化需求,再加上Google和CoreOS的亲密关系,结果就真给合到kubelet里了,从而实现了对多个容器引擎的兼容,但这事费力不讨好,每次更新kubelet都得考虑Docker和rkt,负责维护kubelet的SIG Node小组越做越难受,直接掀了桌子。

‍‍



这活还得继续干,不过得换个思路,干脆把kubelet对容器的操作抽象成一个接口,kubelet只要和这个接口交互就行了,Docker,rkt等容器项目提供一个该接口的实现并暴露给kubelet不就妥了!于是Kubernetes在1.5推出了CRI,有了CRI接口后kubelet就不再直接和容器运行时Say Hi了,而是与CRI进行通信,从而实现了平台和容器运行时的解耦。响应CRI的组件称为CRI shim,它主要实现CRI规定的每个接口,然后把请求转换成对后端容器,比如Docker或rkt的请求或者操作。


这个CRI接口只是Kubernetes自家标准,而当时Kubernetes也没有现在今的地位,所以Docker觉得“凭啥你一个平台说风就是雨?”,不用你,我还有Swarm,并未立即针对CRI进行相应的开发。


Anyway,无论容器厂家们怎么来实现,容器运行时的三层抽象此时已经很清晰了,如下:

Orchestration API -> Container API -> Kernel API


具体一点就是:

Kubernetes API -> CRI-runtime > OCI-runtime


那么在Kubernetes中所划分的CRI-runtime/OCI-runtime都有那些呢?

  • cri-runtime:  containerd/CRI-O

  • oci-runtime:  runC/Kata/gVisor


下图很清晰的解释了这三者是如何协同工作的:



但如今Kubernetes的市场表现相当亮眼,占有率一度接近8成,而Swarm的表现就相当的一般了。按理说都这样了,得认怂,不能硬刚,毕竟人家拳头大啊。但Docker到现在都没有实现对CRI支持,依旧通过dockershim这样一个桥接服务来实现。你是不是觉得Docker的头太铁了,非要撞到南墙才肯回头?其实也不是,这里就要谈谈CNCF和containerd了。


我们知道Kubernetes的主力推手CNCF,是由Google牵头一众厂商于2015年成立,而在此之前Google曾向Docker表达了足够的“善意”,希望能够“手牵手,一步两步三步四步望着天,看星星,一颗两颗三颗四颗连成线”,一起给Docker项目开发一个中立的运行时,但彼时的Docker一家独大,压根不考虑这个“自残”的建议,没鸟Google。另一家知名的开源软件公司Redhat也曾因Docker强推Swarm的关系与其产生嫌隙。而和Docker有瓜葛的这两位,其实在2014年就达成了战略合作关系,现在Kubernetes所力推的,用于替换Docker运行时的CRI-O就是由Redhat开发,Redhat恰巧也是CNCF的创始会员。这局面,甚是有趣!鲁迅曾说过“和敌人的敌人交朋友,就像烧烤配啤酒”,看来Docker没有好好读鲁迅先生的书。



Kubernetes最初的时候使用Docker作为运行时,一是因为Docker拥有大量的用户,考虑到技术惯性,能够很容易的获得这部分用户;二是当时也没有其他的选择了,所以你才能看到kubelet中有dockershim的代码。但随着容器技术的快速发展,以及CRI的出现,Docker已经不在是唯一的选择了。Docker也考虑是否要实现CRI,但毕竟Docker本身包含了太多功能,如果仅仅作为一个运行时,说好听点是“大材小用”,说直白点是“你不够纯”。


前面我提到过,为了符合OCI标准,Docker daemo拆分出了runC以及containred。显然,containerd作为一个单纯的high-level容器运行时更贴合Kubernetes的需求。在2017年Docker把containerd年捐给了CNCF,随后一年Kubernetes开始支持containerd作为容器运行时管理器,2019年containerd从CNCF毕业,所以单从技术上看,此时的containerd已经可以作为Kubernetes的容器运行时了,替换Docker运行时的条件已经成熟。这么一看,在Docker上去实现对CRI的支持确实没啥必要,这应该就“头铁”的原因吧。BTW,我不是阴谋论者,但这一步一步的掏空Docker怎么看都像一个局啊!



另外,在2017年,迫切渴望盈利的Docker公司做了一个重要的决定,宣布将原来开源的Docker项目更名为Moby,交给社区维护,自己仍然持有Docker的注册商标,这是什么骚操作呢?说白了,世上再无Docker的开源项目,无论是Docker EE还是CE,都属于是Docker公司的商业产品。这样一来,多年来所积累的庞大用户团体和资源顷刻间转移到Docker公司的商业产品上。



其实Docker想盈利,谁都能理解,但依靠开源软件赚钱本身就是一件难事,成功者寥寥无几,Redhat能成是因为手上有个OS,但Docker没有啊,而且云原生时代的OS,目前看恰恰就是Kubernetes。更何况容器所采用的cgroup,namespace,aufs,overlay2等技术,都是Linux Kernel所提供的能力,并不是Docker独创。另外,Docker能如此快速的发展壮大,离不开社区多年以来的贡献,但这手分的一点都不graceful,本以为能“我挥一挥衣袖,不带走一片云彩”,Docker却“我改一改名,把项目全部带走”,如此激进的做法,伤了人心,丢了人心。


 


从此,Docker告别了开源,这自然与强调技术开放的Kubernetes站在了两条道上,“道不同不相为谋”。所以,去除dockershim的举动看似突然,实则早已埋下伏笔,有技术上的可能性,也有商业上的利益驱使,更有价值观上的不同。


后面的故事我们就都知道了,Kubernetes社区表明由于维护dockershim对于开发以及运维人员来说是一项繁重的任务,所以在1.20中正式弃用dockershime,不在支持Docker作为运行时,建议大家使用包含CRI完整实现的容器运行时。听上去有理有据,合情合理,但我相信真实的情况应该是这样:



仅供娱乐,别当真


那么Docker运行时没了,在Kubernetes中还能使用那些运行时呢?我们知道Runtime负责提取和运行容器镜像,而Docker只是众多容器运行时中的一种,还有很多选择,比如Kubernetes所提到的CRI的完整实现containerd以及CRI-O,如下图:




相对于dockershim的方案,这两种方案确实要简洁很多。第一种,就是kubelet直接调containerd,如果之前使用Docker,那么迁移到containerd应该是个不错的选择;第二种,CRI-O是Kubernetes的运行时,它的目的式绕过现有的机制,直接操作Linux容器,但在稳定性上目前可能无法满足商用的需求。


如果你担心以后无法使用Docker镜像,也Duck不必。因为Docker镜像是符合OCI标准的,对于Kubernetes来说,只要镜像符合OCI标准,就OK,其他的runtime也是如此。


如果用户近期不想替换运行时怎么办?在1.20上仍然可以使用Docker作为runtime,只不过在启动kubelet时会出现一条告警。直到2021年末Kubernetes才会在1.23版本中将完全移除dockershim。如果你很固执,在1.23后仍然像继续使用Docker,部署一个dockershim呗,自己去集成起来,而且Mirantis和Docker也会合作出一个开源的dockershim组件。


综上,这个移除会有影响,但有限,并不是毁天灭地。相反,商业化的Docker被移除,对于云原生技术发展可能会起到更为正面的影响,推动其他开源容器项目的发展。


好了,就扯到这里了,下次咱们再聊聊容器运行时。


参考资料:

https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md#whats-new-major-themes

https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/

https://kubernetes.io/blog/2020/12/02/dockershim-faq/

相关 [kubernetes docker] 推荐:

kubernetes移除Docker?

- -
两周前,Kubernetes在其最新的Changelog中宣布1.20之后将要弃用dockershime,也就说Kubernetes将不再使用Docker做为其容器运行时. 这一消息持续发酵,掀起了不小的波澜,毕竟Kubernetes+Docker的经典组合是被市场所认可的,大量企业都在使用. 看上去这个“弃用”的决定有点无厘头,那么为什么Kubernetes会做出这样的决定.

docker/kubernetes国内源/镜像源解决方式

- - Xinkun Blog
最近在使用kubeadm时,被各种连接不上搞到崩溃. 这里统一整理了国内的一些镜像源,apt源,kubeadm源等,以便查阅. Azure China提供了目前用过的质量最好的镜像源. 而且都支持匿名拉取,也就是不需要登录. 这里,我开发了一个小的脚本azk8spull,这个脚本可以自动根据镜像名称进行解析,转换为azure的mirror镜像源域名.

Kubernetes 弃用 Docker 后如何切换到 Containerd

- - 掘金 架构
Kubernetes 从 v1.20 开始 弃用 Docker,并推荐用户切换到基于 容器运行时接口(CRI)的容器引擎,如 containerd、cri-o 等. 如果你使用了云服务商提供的托管 Kubernetes 服务,那你不用担心,像 GKE、AKS 等云服务商都已经在新版集群中把默认的运行时切换到 containerd.

Kubernetes组件问题排查思路 – 十点运维吧-Linux|Kubernetes|Docker|Prometheus|Python|Golang|云原生|SRE

- -
Kubernetes的基础组件就像一栋房子的地基,它们的重要性不言而喻. 作为Kubernetes集群的维护者,经常会遇到组件的问题,那平时是怎么去定位解决的呢. 这里简要分析一下我的排查思路. 通过集群的状态,找到故障的节点或者组件. 使用pprof分析组件的具体性能. Kubernetes的基础组件不多,而且部署也非常简单,所以在定义范围的时候还是很容易的,比如我们在使用.

[分享创造] Vesta: 一个 Docker 和 Kubernetes 配置安全的快速检查工具

- - V2EX
伴随着容器技术的快速发展,容器安全问题也逐渐成为企业所关注的话题,越来越多的公司以及个人开发着选择将他们的服务迁移到云上. 目前市面上的容器扫描或容器配置检查的产品大部门都需要进行繁琐的环境配置,同时对机器性能也有着比较高的要求,而开发者或安全测试者或许只是需要扫描少数的镜像或者配置,繁琐的配置和高昂的机器费用对他们来说难以承担,导致安全检查的效率不佳.

Docker & Flatpak

- - IT瘾-dev
目前最流行的技术莫过于Docker,Docker和Docker衍生的东西用到了很多很酷的技术,目前deepin应用软件发布转变成flatpak,这些看似风牛马不相及的技术方案,实际都使用了一个共同的底层技术——Namespace,假如没有namespace支持,这些技术实现都将成为空中楼阁. 一句话总结,无论是Docker、sysmted-nspawn还是flatpak,都是在namespace基础上,针对不同的场景,生出的不同的解决方案.

Kubernetes & Microservice

- - 午夜咖啡
这是前一段时间在一个微服务的 meetup 上的分享,整理成文章发布出来. 谈微服务之前,先澄清一下概念. 微服务这个词的准确定义很难,不同的人有不同的人的看法. 比如一个朋友是『微服务原教旨主义者』,坚持微服务一定是无状态的 http API 服务,其他的都是『邪魔歪道』,它和 SOA,RPC,分布式系统之间有明显的分界.

docker初体验之docker-tomcat

- - BlogJava-首页技术区
docker已经是现在最热的容器技术,最近也去体验了一下,在daocloud注册了一个账号,并开始本机实战docker. daocloud免费有两个容器可用,体验送T恤,邀请送书,这里我分享一个daocloud的邀请码 https://account.daocloud.io/signup?invite_code=mxeq2jkmcur37vz6ven8,daocloud是非常棒的容器云平台,使用体验好,问题响应也及时,绑定微信还送一个额外容器.

Kubernetes学习(Kubernetes踩坑记)

- - Z.S.K.'s Records
记录在使用Kubernetes中遇到的各种问题及解决方案, 好记性不如烂笔头. prometheus提示 /metrics/resource/v1alpha1 404. 原因: 这是因为[/metrics/resource/v1alpha1]是在v1.14中才新增的特性,而当前kubelet版本为1.13.

Docker应用场景

- - 灯火阑珊
Flynn:一个使用go语言编写的开源PaaS平台,目标是简化分布式环境中应用的部署和维护,可以通过git push命令,将应用部署到Docker,从而省去复杂的配置和操作. CoreOS:一种新的架构体系重新设计的Linux发型版,可以运行在既有的硬件活着云服务器上. CoreOS不提供类似yum或apt的包管理工具,用户不需要在CoreOS中安装软件,而是让程序都在Docker容器中运行.