>
现在一说到“容器”,几乎所有人首先想到的就是Docker。
Docker作为目前最主流的容器标准,掩盖了许多前辈和后续者的光辉。事实上,Docker既不是第一个容器类产品(OpenVZ、Lxc等都远远早于它),也不会是最后一个。今天我们来聊一个最近有点火的新容器标准:Appc。
Appc( https://github.com/Appc/spec )是 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 则是纯纯的直接运行了指定的程序,相比之下在性能和镜像内容的“信噪比”上略占优。
如果对Appc和Rkt容器感兴趣,可以参考我在InfoQ的这篇文章:
http://www.infoq.com/cn/articl ... rt-01
稍后放出