AppC是 CoreOS 公司在2014年12月发起的社区项目,旨在设计一种新式的跨平台容器在镜像格式、运行方式和服务发现机制等方面的标准。
从官方的表态说,这个项目最初诞生的原因是,主流容器工具 Docker 正在从一个单纯的容器工具成为自成一体的生态圈。而 Docker 的中心式管理方式(由每个主机上的 Docker -d 后台进程统一控制)对于 Systemd 以及第三方的任务编排工具并不友好(具体原因稍后分析)。
因此 CoreOS 希望设计一种去中心化的、功能更纯粹、同时更关注性能和安全的应用容器,将诸如日志管理、容器调度、集群编排等工作都交给外部工具去完成。
Docker 的发起者是 DotCloud 公司,这个公司原本的业务就是做 PaaS 平台,这也决定了 Docker 的发展方向就是成为一个“大而全”的平台性质的产品。这种做法本身也符合占市场绝大多数的“大众用户”希望“一站式解决方案”的诉求。
可以这样说,两者本质的出发点和想解决的问题并不相同。因此,希望大家秉着开放和包容的心态来看待 Docker 和 AppC 的比较。而不是抱着选择“哪一个是最好的容器标准”的目的,因为这个问题可能和“哪个编程语言是最好的语言”一样,只能交给时间去定论。
现在符合 AppC 标准的容器已经有几款了(都十分的小众),不可能挨个对比。下面就只以 CoreOS 官方推出的 Rkt 容器作为与 Docker 的比较对象。以下内容都属个人测试的结果,不代表 Docker 或 CoreOS 任何一方的官方观点。
由浅入深的说。首先是最容易感觉到的一些差异。
操作命令的方式可以看到,Docker的所有命令都包含在了 Docker 这一个命令行工具中。
而 Rkt 中与镜像相关的命令是由 AppC 统一的命令行工具 actool 提供的,而容器本身的操作由各个容器自己提供,例如 rkt。
Docker 的容器停止以后还会被后台的 Docker -d 进程记录,还能够再次 restart,而 Rkt 的容器里运行的应用则更像是一个普通的应用,结束了就真的结束了。
另外也能看出,Rkt 提供的功能只是 Docker 的子集,后者在日志、镜像、管理方面提供的支持完整很多。
然后,来看一下 Docker 和 Rkt 的一个十分重要的差异。
容器进程运行方式Rkt 的每个容器进程由 rkt 命令直接 fork 出来。而 Docker 的容器进程是由用户执行的 Docker 命令行工具发送消息给后台的 Docker -d 进程,由 Docker -d 进程间接 fork 的。这咋看起来没什么区别,但是 Docker 的这种方式就给第三方的任务编排工具带来了一些困扰。
有些进程管理工具,比如 systemd 是通过 cgroup 来控制和跟踪进程的生命周期的,而 SysV 则是通过进程号和继承关系来跟踪进程生命周期。比如说当需要结束一个进程的时候,进程管理工具就会找到相应进程的所有子进程一起结束。
但 Docker 的这种进程运行模型,使得不论是通过进程树还是 cgroup 树都无法看出创建容器的 Docker 命令行与容器本身有任何关系。因此许多任务管理工具如果不对 Docker 进程进行特别对待,就无法正常的管理通过 Docker 启动的容器里的进程。
看镜像的结构Docker 导出的镜像是一个 tar 文件,里面的内容是分层的。
解压以后的每一个目录其实就是镜像的一层。
Rkt 的镜像是一个 gzip 文件,里面没有分层,直接就是所有容器中的文件的打包。
个人觉得分层以后虽然复杂了一点,但能够复用空间,其实是比较有用的。
最后来看一下 AppC 比较强调的安全性和性能方面。
安全性Docker 下载一个镜像,直接 Docker pull 了事,传输过程可加密可不加密,Docker 也不会问你是否了解这个镜像的来源。
而 Rkt 默认要求所有传输过程加密,并且下载镜像前用户必须首先添加对镜像来源签名的信任,除非用户明确指定取消验证,否则镜像即使下载了 Rkt 也会拒绝运行它。
容器性能性能方面,可以从一个侧面来说明:构建一个最小的可运行镜像需要哪些东西。
下面的 hello 这个文件是一个静态编译(无任何非系统库依赖)的程序,运行的时候会打印一个“Hello World”。
把它放到一个空白的 Docker 镜像里面。
运行容器会发现 Docker 提示找不到 Bash。
将同样的程序放到一个空白的 AppC 镜像里面。
运行容器就能够正常工作。
这一点看出 Docker 在运行容器里的任何程序的时候,实际上都会先在容器里面启动一个 Shell,再由这个 Shell 去容器执行指定的命令。而 Rkt 则是纯纯的直接运行了指定的程序,相比之下在性能和镜像内容的“信噪比”上略占优。
Q&A问:关于镜像的问题是否可以基于本地源来创建?我个人觉得本地源对于企业来说很重要。
答:AppC的镜像创建方式不太一样,现在还不支持用编写Dockerfile这样的方式创建,而是把文件放到指定结构的目录,然后直接用actool工具打包创建。
问:能支持不同的发行版?
答:AppC是跨系统的,只是一个标准。Rkt可以在任意的Linux发型版使用。
问:Rkt的最小镜像是?
答:Rkt的最小镜像可以小到里面只有一个可执行程序。
问:“信噪比”的概念不是很明白。
答: 内容“信噪比”就是说实际用户要的文件和其他辅助文件的比例。
问:Rkt容器可以起多进程吗?
答: 和Docker一样的,入口命令只能一个,里面可以后台运行多个进程。
问:“但 Docker 的这种进程运行模型,使得不论是通过进程树还是 cgroup 树都无法看出创建容器的 Docker 命令行与容器本身有任何关系。因此许多任务管理工具如果不对 Docker 进程进行特别对待,就无法正常的管理通过 Docker 启动的容器里的进程。”这里提到的任务工具对Docker进程特别对待,通常需要怎么处理,才可以方便用户的任务工具对Docker启动容器里的进程进行管理?
答: 就是说在比如结束容器进程的时候,不能通过启动容器的命令所在的pid或者cgroup来跟踪容器内的进程,而要和Docker后台服务进程去取。
问:那Rkt的日志网络等是怎么处理的呢?
答: 这个Rkt就撒手不管,让用户自己选择其他工具,比如Kubernetes或者Mesos这些框架都可以用,AppC目的就是做纯粹关注容器本身功能(环境隔离)的容器。
问:Rkt运行自己的镜像和Docker的镜像有什么区别吗?
答:镜像格式上有些区别,不过其实两者应该是很容易转换的,Docker容器到AppC容器转换的工具已经有了,反转的还没有,估计Docker现在自己是主流,也没打算做这种事情。
问:Rkt有提供Restful的API吗?
答:没有,因为要实现Restful API就必需要有一个常驻后台的进程,这样就违背了Rkt做纯粹的容器工具,并尽可能的减少对系统入侵性的设计意图了。
问:感觉 Rkt+CoreOS 和 Docker+Machine/Swarm/Compose 这两种组合都在做集群的事情?
答:是的,其实是存在一定竞争关系的。只不过CoreOS觉得Docker越做越复杂,不符合他们的应用场景,就新建了一套,顺便改进一些Docker的小毛病。但CoreOS依然会对Docker解决方案继续提供长期支持。
问:Rkt能使用Docker的镜像吗?
答:能,Rkt支持直接下载DockerHub或其他Docker Repo的镜像,只是下载后会自动转换成AppC格式存储到本地。
分享人林帆,ThoughtWorks 成都 Cloud&DevOps 小组成员,目前主要研究内容是应用容器化和CoreOS系统相关领域。近期主要文章有CSDN的《CoreOS实践指南》系列,InfoQ的《CoreOS那些事》系列,和程序员杂志2015年5月刊的《Linux容器:Docker vs Rkt》等。