转载:https://developer.aliyun.com/article/673009

前言

Docker已经推出了5年,在这5年中它极大的改变了互联网产品的架构,推进了新的产品开发、测试和运维方法。但是它自身也在激烈变化中。特别是最近2年随着Docker开源项目的不断演化,Docker内部结构发生了翻天覆地的变化。作为一个容器平台的使用者,可以不用关注具体的Docker演进细则,但是必须明白Docker的衍化会对自己的PaaS平台带来什么样的影响(如果您对Docker技术细节不关注,你可以直接看第2章和最后两章)。本文材料来自于Docker社区,对Docker最近几年的变化趋势做出了总结。同时在结尾处给出了基于k8s PaaS平台在底层容器上选型建议。 

演进方向

 
图2-1 Docker结构图

这里先把结论抛出来,Docker这几年的架构演进方向:

1、原有引擎功能下沉入containerd,containerd向着独立于Docker 作为通用容器运行时工具方向演进

2、swarm功能整合入引擎,swarmkit模块不断弱化,最终将被引擎吸收

3、引擎内部功能不断解藕出新模块,同时新功能不断加入Docker 引擎。

一言以蔽之:containerd核心化,引擎集群化。

背景

Docker公司在集群管理服务编排工具竞争上落败

Docker公司在2015年Docker 1.9推出了自己的集群管理服务编排工具swarm,刚开始swarm作为一个独立的工具,在Docker 引擎之外。但是从Docker 1.12开始Docker公司将swarm整合入了Docker引擎。至此Docker swarm作为一个完整的服务编排工具和谷歌主导、红帽支持的kubernetes社区直接冲突。于此同时Docker公司在2015开启了自己的商业化之路,开源社区为了避免Docker公司商业化过程中将Docker沦为绑架社区的工具,所以顺势推出了多个Docker替代方案例如rkt。kubernetes社区推出了CRI-O标准,只要是遵从此标准的容器运行时都可以被K8s支持。一时间Docker大有被主流社区抛弃之势!经过2年和K8s的竞争时间来到2017年,Docker swarm已经在事实上彻底落败,Kubernetes社区已经成为开源项目中热度最高的项目。为了应对如此多的不利因素,Docker公司在2017年将自己主导的containerd捐献给CNCF基金会(k8s是旗下的子项目);并且将更多的Docker引擎的功能下沉到Containerd中。借此避免自己在开源社区中被边缘化。

容器世界的标准化不断推进

Docker公司在2013念推出Docker后,极大的颠覆了这个行业,也推进了业务容器化过程。2015 Docker公司主导之下社区推出了容器的第一个行业标准OCI标准(开放容器协议)。彼时Docker公司推出了第一个OCI标准的容器运行时runc。runc作为第一个oci标准运行时(runtime),只是一个参考实现,仅仅承担容器与主机之间的交互。容器运行状态检查、监控,容器生命期管理,io管理、信号传递等一些列容器运行必不可少的功能却“无处安放”。所以Docker公司将Containerd定位为一个生产环境下的OCI 标准运行时。它承担了runc所缺少的大部分容器运行必要功能:生命期管理,io管理,信号管理。在2017年的时候OCI v1标准发布,Docker公司将Docker镜像格式捐献给了OCI协议。所以在2017年发布的Containerd1.0中存储管理这些原来由引擎承担的功能也进入了Containerd(网络管理功能,在https://containerd.io路线图中被列为roadmap,但是在2016年12月份Containerd的主要维护者投票中,网络功能不被列入containerd的功能范畴 而继续交给上层完成,在github containerd的readme中2017 1月12日正式将网络部分功能从containerd 维护范畴中删除)。

Containerd

Containerd在Docker 1.11中才正式出现,刚开始时0.x版本;2017年才推出了1.x标准。如上文所说,Container d作为一个生产环境可用的Oci 实现,它利用了OCI 运行时和镜像格式.下图展现了Containerd对自己在社区中地位作出了诠释

 
图2-1 Containerd在Paas社区上的定位

可以看到Containerd作为PaaS工具的通用容器运行时适配层,它利用已有的oci运行时(Containerd使用runc作为运行时,在windows上则是hcsshim),屏蔽底层操作系统的差异;为Paas提供通用的容器支撑。从这个图可以看到Containerd计划支持所有现有应用广泛的Paas平台工具。现在可以确认的是AWS ECS,k8s,Docker上使用containerd。Mesos和cloud foundry今天(2018年9月)尚未确定。

下图为Containerd 1.x的架构图

 
图2-2 Containerd1.x架构图

从此架构图可以清楚的看到Containerd对上提供grpc接口方式的api,而Metric api是度量功能使用的。所有的编排工具容器适配层都可以使用grpc api作为containerd的客户端,使用containerd操作容器。

Distribution用于容器镜像的pull和push动作(这部分出现在Containerd中完全是因为oci v1标准推出Docker公司将自己镜像格式贡献了出去,所以containerd理所当然需要对镜像进行管理了)。Bundle(在docker的语景里是容器运行的目录集)子系统用于容器存储管理它的作用就是原来的graphdriver,它提供将容器镜像拆解成容器运行时刻需要的Bundle。Runtime子系统用于容器执行和监控,就是它直接操作runtime,传递和接收信号(signal),中转fifo,记录日志。Content、Metadata和Snapshots是存储管理组建,Excutor和Supervisor是执行体组建。整个系统通过Event事件驱动。

根据github上containerd的介绍containerd项目工作内容集中在如下几个领域上:

1、执行:容器创建、运行、停止、暂停、恢复,exec,信号传递、和删除。

2、cow 文件系统支持:在overlay,aufs和其他cow文件系统上内置了存储功能

3、度量系统

4、发布:容器镜像的pull和push,镜像的管理和获取

下面内容不作为containerd项目的工作范畴:

1、网络:网络的创建和管理由高层来完成

2、build:镜像的构建

3、volumes:volume管理:mounts,bind等针对volume的功能应该有高层来完成

4、logging

此处需要说明一下网络曾经作为containerd社区争论的焦点。但是在16年年底的社区维护者投票中多数人支持网络不留在containerd中,因为按照大多数维护者的认识网络过于复杂,而且网络设置常常需要跨越节点。这部分功能由containerd的客户端(Docker Engine 或k8s)做更合适。

这里顺便介绍一下Containerd版本兼容规则:Containerd同一个大版本下的连续两个小版本是兼容的。例Containerd1.1.0和1.2.0却是兼容的,1.0.0和1.2.0却不保证兼容。

Docker的演进

下图介绍了containerd在1.11之前(不含)的Docker架构

 
图3-1Docker1.11(不含)之前的架构

可以看到在Docker1.11之前,没有containerd模块,由libcontainer直接操作主机os接口。

下图介绍了在Docker 1.11--Docker 17.10之间的docker架构

 
图3-2 Docker 1.12-17.10之前(含)架构

从图3-2看到这一时期的Docker架构变化就是引入了Containerd和runc,由Containerd完成容器生命期管理。

下图列出了Docker 17.11(Docker 17.12为真正的stable版)开始的架构

 
图3-3 docker 17.12以后架构

需要注意的一点图网络部分并不在containerd中,仍然在docker engine里。

Docker 17的具体架构演进

这里介绍的内容均来自于Moby社区的roadmap和Docker\docker-ce 的分析。

17.06---17.10的路线图描述此一时期,moby社区(引擎)的主要工作是:

1、插件功能的提升:方便插件的发布(通过registry以docker镜像方式发布),解决插件开发的共性问题(插件任何时候的需要active,在用户容器启动之前就start,以及插件写在困难)

2、引擎内部解藕:api已完成重构,builder实现在daemon中已完全独立。

3、提升引擎集群管理能力:当前跨节点网络(overlay网络)和节点发现已经整合到引擎里。但是引擎尚不能不依赖于swarmkit完成task调度

4、cli从engine中独立出来(这一点源自于github moby代码分析)。

17.11--18.03 的路线描述此一时期,moby社区(引擎)的主要工作:

1、引擎使用Containerd1.0

2、引擎内部解藕,计划整合buildkit工具

Docker架构演进大事记

1、Docker 1.9 推出swarm,作为独立工具,用于集群管理和服务编排

2、Docker 1.11 推出containerd和runc。

3、Docker 1.12 swarm进入引擎

4、Docker 17.06 引擎社区更名为moby,do c ke r社区版本更名为docker-ce(类似于红帽的fedora和rhel)

5、Docker 17.12 Docker正式引入containerd 1.0

6、Docker 18.06 正式在engine里加入了buildkit,在设置一个环境变量后可以使用buildkit完成docker build过程。

Docker 18.06.1正式将containerd 1.1引入docker。

k8s社区对Docker 17.03之后版本态度

在Docker 17.03后Docker因为moby和containerd等原因版本变动比较大,我们可以看到k8s r11发布后的2018年9月仍然没有将Docker 17.03以后(不含)版本作为k8s的兼容Docker版本。从社区的讨论来看社区已经推荐将containerd直接对接cri,完成k8s的集成。见https://github.com/kubernetes/kubernetes/issues/42926,其中cpuguy83(此人为moby社区的主要维护者)推荐直接使用containerd替代docker 17.03以后的版本对接k8s。本来docker在k8s社区中的兼容性测试由k8s sig-node 工作组完成,但是通过k8s讨论可以看到sig-node并没有计划做docker 17.03以后docker的兼容性测试。

最新消息是2018年9月27日k8s出r12 rc的时候,kubeadm里已经加入了对docker18.06的支持,且完成了ci测试。12 rc 文档里将docker17.12,18.03,18.06之后列入支持表。但在k8s中 sig-node工作组负责底层容器接口,docker在k8s版本的兼容性测试本应由此工作组完成,但是sig-node对于docker 17.03版本以后docker版本的态度依然冷淡,一直未列入明确的工作计划中。sig-node工作组两位主席是谷歌和红帽的,它们对于cri更感兴趣。在2018年5月,sig-node和containerd社区共同完成了cri-containerd合入containerd1.1的工作,并发布了containerd 整合到kubenetes的GA。完成此部分工作后,k8s驱动containerd的结构更简单明确。下图介绍了docker,containerd在k8s上的架构图:

 
docker在k8s上的架构图
 
containerd1.1在k8s上的架构图

从上面两幅图我们可以看到containerd1.1在k8s上拥有更简单的结构图,驱动更为简单。而且根据k8s社区的测试,直接使用containerd替代docker可以获得容器启动时间、内存消耗和cpu消耗减少的红利。上述结论来自于:

https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/

所以sig-node工作组对docker 高版本不感冒。目前多方力量博弈,未来k8s下层的runtime花落谁家还再观察。

 
kubelet调用docker容器的方式

docker-manager是老的kubelet介入docker的方式。

cri从k8s 1.6开始正式进入k8s

cri直接介入containerd是从18年4月,containerd1.1开始

PaaS平台选型建议

如果你正在对基于k8s的PaaS平台进行生产环境选型,我建议你使用Docker17.03,因为它成熟稳定且k8s r9,r10和r11做过稳定、兼容性测试。如果你喜欢尝试新事物,我建议你跳过Docker17.03之后,直接在kublet上使用containerd1.1。如果你喜欢docker新版本,那么你可以尝试docker18.06,因为Docker17.12是Docker变化最剧烈的一个版本稳定性不好说,且kuberadm中r12 rc里加入了对18.06的支持所以用最新的好了。而且更关键的一点docker 18.06.1使用containerd 1.1,它支持一个特性:上层容器控制平台的namespace隔离,简单点说就是docker和k8s均可以在同一个节点上操作同一个containerd,且相互隔离不可见。如此可以预留选择传统k8s+docker组合时刻,保留将来切换成k8s+containerd组合的可能性,进而为自己的框架保持演进的灵活性。

最新文章

  1. artDialog 配置参数
  2. 『c++』 模板(template)--- 参数化多态性
  3. 解决Eclipse快捷键被其他软件占用
  4. hdu 4539(状态压缩dp)
  5. wechat server的配置
  6. Win7下Solr4.10.1和MySql的整合(索引与搜索)
  7. Android应用程序资源的查找过程分析
  8. android.view.WindowManager$BadTokenException: Unable to add window — token null is not for an applic
  9. Java回调函数的理解
  10. 2015 多校联赛 ——HDU5301(技巧)
  11. (九)UIScrollView和PageControl的分页
  12. ABAP其实也是挺好的语言
  13. Eureka 2.0 开源流产,真的对你影响很大吗?
  14. 如何在phpstorm中查看yaf框架源码
  15. 【ERROR】no matching function for call to 'std::basic_ifstream<char>::basic_ifstream
  16. IO流(10)复制多级文件夹
  17. eval、exec、execfile
  18. iOS中 Proxy和的delegate区别
  19. mysql TO_DAYS()函数
  20. xshell ssh 上传文件

热门文章

  1. 关于如何在C#中调用C++的DLL,以及如何在C++中调用C#的DLL
  2. GO语言基础 为什么我要学习Golang以及GO语言入门普及
  3. go_xml_learn
  4. 9、手写一个starter
  5. 你的 GitHub 年度报告「GitHub 热点速览 v.22.52」
  6. vue多界面开发
  7. 通过Terraform创建GCP Pubsub
  8. CentOS7.6系统安装和网络配置
  9. angular2-qrcode 引用报错 error NG8001: 'qr-code' is not a known element:
  10. vue基础之keep-alvie保持历史页面数据不变,切换页面后数据不变keep-alvie