三年后,我们从 Docker 转到了 RKT
yiyilove
8年前
<p><strong>导言</strong><br> 在 Swarm 被纳入 Docker 1.12后,Swarm 与 K8S 之争日趋白热化。本文作者 Adriaan de Jonge 身为 Xebia CTO ,专精 DevOps 及持续交付,曾为 Docker 摇旗呐喊三年的老司机,如今开始易帜。<br> <br> 现在即使是最酷的产品也绑定于某个特定供应商。不管在过去的三年里,我曾多么热衷 Docker,但是现在,绑定的供应商开始动摇 Docker 在我心中的地位了。而目前他们两者之间的竞争还在持续。又或许在这个过程中会出现一个更好的选择也说不定。这篇文章就是带领大家来了解一下 Core OS 的 rkt(读音按照“rock-it”来),以及告诉你为什么从现在开始要了解 rkt。<br> <br> <strong>Docker 怎么了?</strong><br> 如果你跟我经历相似,你可能因为对 Docker 充满热情而被它的一些缺点蒙蔽了眼睛。不要误解我,我并不是说 Docker 不好。我的意思是它并没有那么完美。所以接下来让我们来看一下它的一些不足之处吧。<br> <br> Docker 越来越像以前的 Microsoft<br> 一旦一家公司意识到它有着自己的垄断权,他们就会开始做出垄断行为。一如微软曾经试图通过在 windows 中安装 Internet Explorer 来排挤 Netscape,现在 Docker 正在尝试将 Swarm 融入到 DockerCore,以此来打击 Kubernetes,Mesos,Marathon 和 Nomad。<br> Docker 确实有简化 Swarm,使它轻松被广大 Docker 用户接受的优点。如同微软确确实实提升了 Internet Explorer6.0的性能。MSIE6浏览器突出了微软的优势,所以他们在5年内都没有继续开发了。<br> 想象一下 Docker 跟 Swarm 结合的结果是什么……想象一下你的下一个任务就是移动到 Docker:当需要选择一个最好的调整程序时,在你选择 Kubernetes,Mesos/Marathon,Nomad 之前,你首先要理清楚的就是 Swarm 的不足之处是在哪里。已经有了 Swarm,那么为什么在这个基础上还要安装其他的调度程序呢?<br> 我希望 Docker 能够提升 Swarm 的性能,在修改这一点上,希望 Docker 做得比微软(修改 MISE)要好。但是即使是现在,Kubernetes 在很多方面也都是领先于 Swarm 的。随着 Kubernetes 的持续开发,Swarm 已经远远落在后面。虽然 Docker 能够让人轻松使用调度程序,但是在我看来,他们还是应该跟 Docker 核心分开。<br> <br> <strong>“Docker 的架构从基础上来看就是有瑕疵的”</strong><br> Docker 的核心就是 Daemon 程序,这个程序是 Docker 开始运行的起点。Docker 可执行文件仅仅只是一个 REST 代理,这个代理要求发请求给 Docker daemon 来完成它的工作。Docker 的评论家指出,这很不符合 Linux 的方式。<br> 它的痛点在于你是否使用类似 systemd 这样的初始化系统。因为 systemd 并不是针对 Docker 设计的,所以当你尝试开启一个 Docker 程序的时候,你其实也就是开启了一个 Docker 代理程序,而这个代理程序向 Docker daemon 请求开启真正的 Docker 容器。在这里还是有一个风险的,就是当 Docker 容器还在运行的时候,Docker 代理运行失败了。在这样的情况下,systemd 得出结论,程序已经停止,并且重启 Docker 代理——于是创建第二个容器(是的,你还是可以继续处理工作,但是已经是无关紧要的了)。<br> 大概一年之前,我把 systemd 当成是一个简单的 Docker 调整程序来调查。我遇到了同样的危机,或者说将 Docker 和 systemd 结合的问题。那时候,我觉得这些是 systemd 的原因,而不是 Docker 的缺点。我那时候还想,会不会 systemd 并不是针对“Docker 本地”来设计的。<br> 现在,我才了解到,可能 Docker 才是那些问题的症结所在,而不是 systemd 的问题。就像上文中提到的,Docker 并不符合 Linux 的风格,而也正因为如此,Linux 工具跟 Docker 也协作得不是很好。所以是谁错了呢?是新来的 Docker,还是已经存在了多年的 Linux 工具呢?CoreOS 的 CEO,Alex Polvi说:“Docker 的架构从基础上就有瑕疵。”<br> <br> <strong>Docker 创建程序,陷在了第二个阶段</strong><br> Docker 最好的功能之一就是 Dockerfiles 的引入,你可以在构建 Docker 镜像时保持版本控制。这里唯一的问题是在 Docker 的路标中 Dockerfile 语法冻结很长时间了。这就意味着在过去的一年半以来 Dockerfile 格式并没有依据社区的良好建议而进化。<br> 当然,在某种程度上,我们需要一个稳定的格式,但是只有当格式完全成熟的时候。在这里举个例子,就是 Dockerfile 缺乏的地方,考虑到 Kelsey Hightower 在他博客《12 Fractured Apps》中提到的:<br> “记住,我们要运送artifact,而不是编译环境。”<br> 事实就是,Dockerfile 格式并不能很好地支持这个区别。考虑到要构建一个可执行的 Golang:可执行的结果可能只有两百万字节大小,但是创建的环境有几百兆字节。当然,你也可以在本地系统上构建镜像。你无法利用 Docker Hub 中的自动化构建环境通过一个简单的 Dockerfile 优雅的构建出一个小的 Golang 镜像。社区有个关于扩展 Dockerfile 格式的提议就能很好的支持上述原理,但是由于 Dockerfile 格式的冻结该提议也被搁置了好几年。<br> <br> <strong>那么,rkt 是如何缓解这个状况的?</strong><br> 简而言之,rkt 现在给 Docker 提供了更好的解决办法。它拥有一套更加 Linux 的架构。这个强劲的对手会保持自己的垄断作风。<br> 具体一点的答案就是:2014年年底,Core OS 宣布,这个有竞争力的容器平台 Rocket(后来简写并改名成 rkt)的诞生。虽然 rkt 在发布之后最初几周里得到了很高的关注度,但是后来却销声匿迹了。Core OS 还是将 rkt 作为 Docker 的可替代工具来开发,后来在2016年2月 rkt1.0版本发布的时候才回归大众视野。<br> 现在 Docker 宣布在 Docker Engine1.12中已经包含了 Swarm,那么是时候正视 rkt,让它作为 Docker 的可执行方案了。那在未来它会替代 Docker 吗?从 Docker 切换到 rkt 难度大吗?<br> 让我们来看一看 rkt 寻找答案吧……<br> <br> <strong>rkt 能够运行 Docker 镜像</strong><br> 假设现在你想要用 rkt 来替代你的 staging 以及产品系统,同时又想让你所有的开发系统都继续运行......在这个案例中,你可以只在你的运行系统上将 Docker 替换成 rkt。但严格来说,这并不是一个随随便便的替换。毕竟,架构是不一样的——但是我们会努力往一样的方向发展的。另一方面,为了在 rkt 上运行 Docker 容器而去学习新的命令行指令也不会太难。<br> 在你最爱的云提供商上打开 Core OS 实例,并打出以下代码:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/0aa0c50138af7fd83cb581c1bf3fb24d.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/0aa0c50138af7fd83cb581c1bf3fb24d.png" width="627" height="89"></a></p> <p>或者用你最爱的 Docker 镜像来替代 nginx。在底层,rkt 将 Docker 转换到ApplicationContainer(appc)格式。<br> 这也就意味着你不需要 Docker 来运行 Docker 镜像了。而且也意味着你可以重新使用 Docker 创建的东西,在这个过程中不需要忍受迁移带来的伤痛——而不是学习 rkt 的命令行语法。<br> 让我们来一睹命令行的单个部分:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/4d10b7afb193404f6bf4a4526356ca0d.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/4d10b7afb193404f6bf4a4526356ca0d.png" width="633" height="74"></a></p> <p>如果你没有忽略这部分,那么rkt就会拒绝启动你的镜像,因为它找不到签名(.asc file)来确认 Docker 镜像的完整性。rkt 默认设置下是安全创建的。在这个例子中,这也就意味着你可以通过提供合适的签名来省去一些命令的输入。<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/e2a9b385b24a9c0a5525557beba71598.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/e2a9b385b24a9c0a5525557beba71598.png" width="633" height="76"></a></p> <p>就比如在 Docker 中,你需要明确地暴露端口到外部。不像 Docker,rkt 端口已经被命名,而不是标记数字。如果这是一个原生的 rkt 镜像(或者需要精确的appc),那么它读起来很可能是这样的:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/bf7e7ecce19b97447230d21c20183fd6.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/bf7e7ecce19b97447230d21c20183fd6.png" width="630" height="66"></a></p> <p>然而,既然 Docker 没有命名的端口,那么被暴露的端口就会被自动命名为<number>-<protocol>。这也就意味着,如果你只能显示暴露端口的话,就使用 Dockerfile 中的 EXPOSE 关键字:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/c6ce51bbe5e00ca14ebe1bd1b854a7d0.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/c6ce51bbe5e00ca14ebe1bd1b854a7d0.png" width="635" height="72"></a></p> <p>镜像期望存储在默认的 Docker 仓库中(Docker Hub)。除了这个例子,还有个更长的 URL 指向另一个 Docker 仓库(docker://)或者包含镜像的通常的 web 网站(https://),但是之后你就不再运行 Docker 镜像了。<br> <br> <strong>Rkt 有着更加简单的架构</strong><br> 在 rkt 中是没有 daemon 进程的。Rkt 命令行工具做了所有的工作。来看从CoreOS 网页借鉴的图片:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/0548201c6575037eb2b800e7acc79ac6.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/0548201c6575037eb2b800e7acc79ac6.png" width="655" height="367"></a></p> <p>跟 Docker 不同,如果你使用 systemd 来启动 rkt容器,你实际上就是在监控容器进程,而不是监控代理程序,然后由代理程序连接到 daemon,并由 daemon(直接或者间接——依赖于你的 Docker 版本)来启动容器。<br> 另一方面,你不能这么写:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/01e2cf49c8f5b49de3fc86be550be1a1.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/01e2cf49c8f5b49de3fc86be550be1a1.png" width="631" height="77"></a></p> <p>像 Docker 代理一样 daemon 化进程。而且必须要运行一个初始系统来 daemonize 进程。比如,你可以这样运行:<br> </p> <p style="text-align: center;"><a href="https://simg.open-open.com/show/d646d8fe149858e4d35a38c80d225358.png" rel="lightbox"><img alt="三年后,我们从 Docker 转到了 RKT" src="https://simg.open-open.com/show/d646d8fe149858e4d35a38c80d225358.png" width="639" height="77"></a></p> <p>同样,你无法从远程机器(比如 Docker 代理)运行 rkt 命令行。再有,你也可以将它作为安全功能考虑。<br> <br> <strong>Rkt 为镜像遵从开放标准</strong><br> 现在,rkt 允许你使用 Application Container(appc)或者 Docker 镜像。在不远的将来,Open Container Initiative(OCI)格式将会被加入,我们会朝那个方向走的。<br> 容器镜像拥有开放标准的好处就是,它允许开源社区提供多种创建镜像的方法,不仅仅局限于 Dockerfile 格式。<br> 构建 appc 镜像的默认方式就是使用命令行工具,叫做 acbuild。说实话,喜欢 acbuild,还是喜欢 Dockerfile 格式,这真的只是个人口味问题。<br> 好处就在于它天生就跟 Linux 原则距离更近。<br> 而最大的好处就是开放格式允许可替代的构建机制。比如,考虑到全能创建工具 dgr 或者 Golang 指定创建工具 goaci。<br> 一旦 OCI 格式可用,就会有更多可能,但是现在,我们还是需要等待。<br> <br> <strong>Rkt:我们到达目的地了吗?</strong><br> 如果你现在就想要开始使用 rkt,那么你在使用道路上会有一些磕绊。虽说你可以在磕磕绊绊之中找到方向,但是不得不承认的是,在我写这篇文章的时候(也就是现在),说 rkt 一切都已经准备妥当还为时过早。不过,我相信,只是时间问题。<br> <br> <strong>OCI 镜像格式还没有准备好</strong><br> 就像在上文中提到过的那样,rkt 支持 Docker 镜像格式,而且跟 Docker 仓库互相沟通联系。如果你能够坚持使用 Docker 镜像格式,那么相信它,它会运行得很好。<br> 但是,如果你是个吹毛求疵的人——像我似的——你就没办法容忍在使用 Docker 的时候,你还无法使用命名的端口。所以,你就会想要使用 appc 容器。appc 容器是可以自由使用的。<br> 但是你要怎么上传 appc 容器给 Core OS 解决方案到 Docker Hub——quay.io?我自己是还没有找到这样的方法。<br> 关于 appc 格式最好的一点就是,它并不是跟特定的 Docker 仓库相联系。反而,你可以在普通 http 服务器上,或者是在本地文件系统宿主镜像。你可以丰富包含元标签的 HTML 文件的原数据。<br> 一旦 OCI 镜像格式达到,rkt 才有可能真正 take off,变得足够成熟,准备足够充分来被接受,作为每个人心中的标准——包括 Docker。<br> <br> <strong>Nomad&Kubernetes 还没有完全成熟</strong><br> 为了在产品中运行容器,在某种程度上,你需要一个调度程序来控制运行什么程序,在哪里运行。目前,Kubernetes 和 Nomad 都支持 rkt。但是这种支持并没有大家期望得那样成熟。<br> Kubernetes 支持 rkt 是从积极开发的状况下来说的。它有最小文档以及一系列已经知道了解的问题。Nomad 支持标记试验,但是不支持动态端口。<br> <br> <strong>对于其它平台来说就不那么轻便</strong><br> 好在 rkt 不仅仅支持 CoreOS。你可以在多个平台上,比如分布式 Linux,Debian,Ubuntu 以及 Fedora 上安装 rkt。<br> 如果你想在你的 Apple/Windows 开发机上运行 rkt,你当然可以在像 virtualBox 这样的虚拟层运行。但是,这些设备没有 Docker 的工具盒那么好用——特别是最新的 Docker Mac/Windows 测试版,这也就给了你一种 native 的感觉。要承认的是,这可能就是 rkt 架构上的缺点,在这点上,可执行的 rkt 已经做了所有的工作,而不只是作为一个 REST 代理。<br> 如果你想要在非 Linux 机器上开发,最好的办法就是仍然在本地用 Docker 镜像进行处理,并且在你转到 staging 和生产的时候,要将这些转化为 appc 镜像。<br> <br> <strong>结论</strong><br> 虽然这么说还很早,但是 rkt 现在已经变成 Docker 的一个可执行方案。如果你不需要 Kubernetes,Nomad 的动态功能,以及更多像 systemd,fleet 这样的静态选项,来满足你的调度准则,那么你现在就可以将你的 staging 和产品服务器转移到 rkt 了。<br> 相信再有多一点的时间,Docker 和其它容器平台间会有真正的互操作性,以 OCI 镜像的形式出现。同时,允许 Kubernetes 和 Nomad 支持 rkt 的发展,然后 Docker 会跟 rkt 容器平台会一样可交换。<br> 那现在有必要摒弃 Docker 吗?不,没有必要。除了这篇文章中提到的一些 Docker 的缺点,Docker 还是个有着很多开发工具,调度程序,编排的巨大生态系统创新平台。重要的是,我们要有足够多的选项。现在 Docker 有很多的竞争对手来保持清醒。</p> <p> </p>