Docker为何未在生产环境中取得广泛成功?
Docker的发展势头一天比一天强劲,它显然在试图解决实际的问题。然而,对如今许多的生产环境用户来说,没有出现优点压倒缺点的局面。在开 发、测试和持续性集成等环境下,Docker在让容器吸引广大开发人员方面确实有上佳的表现,不过它还没有颠覆生产环境。按照DockerCon 2015的“生产环境下的Docker”这一主题,我想公开讨论Docker想在生产环境使用场合下得到广泛采用还没有克服的种种挑战。这里提到的问题没 有一个是新问题,它们都以某种形式出现在GitHub上。大多数问题我已经在大会演讲中或与Docker团队交流中讨论过。本文倒不是要明确指出什么不再 是问题:比如说,新注册中心(registry)克服了旧注册中心的许多不足。本文并没有提到仍然问题重重的许多方面,不过我认为下面这些问题是近期内需 要解决的最重的问题;只有解决了这些问题,更多的企业组织才能够迈出一大步,在生产环境中运行容器。我在电子商务公司Shopify运行Docker的经 历对本文有很大的影响;一年多来,我们一直在容器上大规模运行核心平台。由于像Docker这样发展这么迅猛的技术,不可能一切都保持现状。如果你发现不 正确之处,务必联系我。
映像构建
为大型应用程序构建容器映像依然是个挑战。如果我们要依赖容器映像用于测试、持续性集成和紧急部署,就需要在不到1分钟的时间内将映像准备就绪。 Docker文件(Dockerfile)让这对大型应用程序来说几乎不可能。虽然Docker文件易于使用,但是位于过高的抽象层,无法支持复杂的使用 场合:
- 带外缓存,面向特别错综复杂的、针对特定应用程序的依赖项;
- 在构建时访问密文(密码、密钥和相关内容),又不将它们提交给映像
- 全面控制最终映像中的层
- 并行处理构建层
大多数人并不需要这些功能,但是对大型应用程序而言,其中许多功能是快速构建映像的先决条件。Chef和Puppet等配置管理软件使用广泛,但 是让人觉得用于构建映像过于笨拙。我打赌,在今后十年内,现有形式的这类系统会因容器而逐渐退出历史舞台。然而,许多应用程序依赖它们来配置、部署和编 排。Docker文件无法真实地记录下现在由配置管理系统管理的复杂性,但这种复杂性需要在某个地方加以管理。在Shopify,我们最后使用 docker commit API,从头开始构建了自己的系统。这个过程很麻烦,我希望这一幕不会出现在任何人身上,我很想摆脱这种局面,但是我们又不得不扫除障碍。很少有人会花这 么大的力气去管理用于生产环境的容器。
这个领域会出现什么情况不得而知;目前在这个领域,开展的研究工作并不多(一个例子是dockramp,这是另一种打包器)。Docker引擎会 在将来有所改进,将构建基本步骤(添加文件和设置入口点等)与客户端(Docker文件)分开来。为版本1.8所做的合并工作已经让这变得更容易,为配置 管理工具厂商、业余爱好者和公司进行试验尝试创造了条件。考虑到配置系统的历史还很短,认为一种标准有望搞定这个问题(就像运行时标准那样)是不切实际 的。什么时候可以实现可扩展的映像构建,相当不明朗。据我所知,没人在积极迭代,很遗憾这种现状已维持一年多了。
垃圾收集
每个部署的重大Docker系统到头来要编写垃圾收集器,以便清除主机上的旧映像。使用了各种启发式方法,比如清除超过X天的旧映像,在主机上最 多执行Y个映像。Spotify最近开放了其系统的源代码。我们还在很久以前就编写自己的垃圾收集器。我能明白为此设计一种易预测的用户界面(UI)有多 难,但是这又是核心中绝对需要的。当生产环境的机器嚷着要存储空间时,大多数人无意中发现要求收集垃圾。最后,你会遇到同一映像,Docker注册中心因 庞大映像而溢出,不过这个问题已列在了发行版路线图上(详见https://github.com/docker/distribution/blob /master/ROADMAP.md#deletes)。
迭代速度和核心状态
Docker引擎致力于1.x版本的稳定性。在版本1.5之前,降低准入门槛以便在生产环境得到采用方面所做的工作不多。开发容器的公众心理模式 对Docker的成功而言必不可少,Docker害怕破坏这种模式是有其道理的。如果用户体验(UX)方面的每个变化经历的过程时间过长,迭代速度难免受 到影响。自版本1.7起,Docker开始发布试验性版本,以网络和存储插件带头。这些功能特性被明确标为“未准备用于生产环境”,可能会从核心中取出或 者随时经历重大变化。对于早已看好Docker的公司来说,下面这个是好消息:它让核心开发团队可以更快速地迭代开发新功能,不用担心本着最佳设计的精神 而破坏次要版本之间的向后兼容性。公司仍然很难改动Docker核心,因为它需要分支――这是导致最终失败的行为和维护负担,或者需要得到上流接受;对于 值得关注的补丁来说,这常常很耗费人力。自版本1.7起,宣布插件后,解决这个问题的策略就很明确:让每一个固执己见的的组件都可以插入,最后显示了“带 电池而且可以更换”这种理念的成果,这种理念最早是在2014年的DockerCon欧洲大会上提出来的(不过相当模糊)。在6月份的DockerCon 大会上,很高兴听到这归入到“管道”(Plumbing)这个大主题来探讨,作为核心开发团队的重中之重。虽然未来终于大有希望,但是这在今天仍然是个痛 点,就跟过去两年一样。
日志
日志是表明有望得益于之前变化的一个方面的例子。这并不是引起强烈关注的问题,却是普遍性的问题。目前没有理想的、普通的解决方案。日志到处都 是:尾部日志文件、容器里面的日志、通过挂载发送到主机的日志、发送到主机syslog的日志,通过fluentd(开源数据采集器)等工具来暴露日志, 从应用程序直接发送到网络的日志,或者发送到文件的日志,让另一个进程将日志发送到Kafka。在版本1.6中,支持日志驱动程序的功能已并入到核心中 (https://blog.docker.com/2015/04/docker-release-1-6/);然而,驱动程序在核心中必须得到接受 (这并非易事)。在版本1.7中,已并入了试验性支持进程外插件的功能,但是让我失望的是,它并不随带日志驱动程序。我认为,版本1.8会计划添加这项功 能,但是在官方记录中找不到这项。到那时,厂商们就能够编写自己的日志驱动程序。社区内部的共享将轻而易举,大型应用程序再也不必求助于设计定制的解决方 案。
密文
迁移到容器的人大多数依赖配置管理,在机器上安全地配置密文;然而,继续沿着配置管理这种老路子配置容器中的密文很笨拙。另一个办法就是将密文与 映像一同分发,但是这带来了安全风险,而且很难在开发、持续性集成和生产环境之间安全地回收映像。最纯粹的解决办法就是通过网络访问密文,让容器的文件系 统保持无状态。就在不久前,这方面还没有任何面向容器的机制;不过最近,两家颇令人关注的密文代理系统 Valut(https://vaultproject.io)和Keywhiz(https://github.com/square /keywhiz)开放了源代码。在Shopify,我们一年半前开发了ejson(ejson是一种简单的库,用嵌入在JSON文件中的公钥加密该文件 中的所有值,详见https://www.shopify.com/technology/26892292-secrets-at-shopify- introducing-ejson),以解决这个问题,从而管理JSON文件中非对称加密的密文文件;然而,它就所运行的环境有一些假设,因而让它与密 文代理系统相比,不是很理想的一般性解决方案(如果你很好奇,可以参阅这篇文章https://www.shopify.com/technology /26892292-secrets-at-shopify-introducing-ejson)。