容器技术的发展历史
# 1. 盛极一时的 PaaS 技术
把时间拨回到 2013 年,2013 年的后端技术领域,已经太久没有出现过令人兴奋的东西了,相比于如日中天的 AWS 和盛极一时的 OpenStack,以 Cloud Foundry 为代表的开源 PaaS 项目,却成为了当时云计算技术中的一股清流。Cloud Foundry 项目吸引了一大批国内外技术厂商,开启了以开源 PaaS 为核心构建平台层服务能力的变革。
事实上,当时还名叫 dotCloud 的 Docker 公司,也是这股 PaaS 热潮中的一份子,但它的主打产品由于跟主流的 Cloud Foundry 社区脱节,长期以来也无人问津。眼看就要被如火如荼的 PaaS 风潮抛弃,dotCloud 公司却做出了这样一个决定:开源自己的容器项目 Docker。“容器”这个概念从来就不是什么新鲜的东西,也不是 Docker 公司发明的。即使在当时最热门的 PaaS 项目 Cloud Foundry 中,容器也只是其最底层、最没人关注的那一部分。说到这里,我正好以当时的事实标准 Cloud Foundry 为例,来解说一下 PaaS 技术。
PaaS 项目被大家接纳的一个主要原因,就是它提供了一种名叫“应用托管”的能力。当时虚拟机和云计算已经是比较普遍的技术和服务了,用户往往租一批服务器,然后用脚本或手工的方式在这些机器上部署应用。当然,这个部署过程难免会碰到云端虚拟机和本地环境不一致的问题,所以当时的云计算服务,比的就是谁能更好地模拟本地服务器环境,能带来更好的“上云”体验。而 PaaS 开源项目的出现,就是当时解决这个问题的一个最佳方案。举个例子,创建好虚拟机之后,运维人员只需要在这些机器上部署一个 Cloud Foundry 项目,然后开发者只要执行一条命令就能把本地的应用部署到云上,这条命令就是:
$ cf push "我的应用"
是不是很神奇?事实上,像 Cloud Foundry 这样的 PaaS 项目,最核心的组件就是一套应用的打包和分发机制。 Cloud Foundry 为每种主流编程语言都定义了一种打包格式,而“cf push”的作用,基本上等同于用户把应用的可执行文件和启动脚本打进一个压缩包内,上传到云上 Cloud Foundry 的存储中。接着,Cloud Foundry 会通过调度器选择一个可以运行这个应用的虚拟机,然后通知这个机器上的 Agent 把应用压缩包下载下来启动。这时候关键来了,由于需要在一个虚拟机上启动很多个来自不同用户的应用,Cloud Foundry 会调用操作系统的 Cgroups 和 Namespace 机制为每一个应用单独创建一个称作“沙盒”的隔离环境,然后在“沙盒”中启动这些应用进程。这样,就实现了把多个用户的应用互不干涉地在虚拟机里批量地、自动地运行起来的目的。这正是 PaaS 项目最核心的能力。 而这些 Cloud Foundry 用来运行应用的隔离环境,或者说“沙盒”,就是所谓的“容器”。
# 2. Docker 反杀 PaaS
而 Docker 项目,实际上跟 Cloud Foundry 的容器并没有太大不同。然而短短几个月,Docker 项目就迅速崛起了。它的崛起速度如此之快,以至于 Cloud Foundry 以及所有的 PaaS 社区还没来得及成为它的竞争对手,就直接被宣告出局了。事实上,Docker 项目确实与 Cloud Foundry 的容器在大部分功能和实现原理上都是一样的,可偏偏就是这剩下的一小部分不一样的功能,成了 Docker 项目接下来“呼风唤雨”的不二法宝。这个功能,就是 Docker 镜像。
PaaS 之所以能够帮助用户大规模部署应用到集群里,是因为它提供了一套应用打包的功能。可偏偏就是这个打包功能,却成了 PaaS 日后不断遭到用户诟病的一个“软肋”。出现这个问题的根本原因是,一旦用上了 PaaS,用户就必须为每种语言、每种框架,甚至每个版本的应用维护一个打好的包。这个打包过程,没有任何章法可循,问题很多。最后结局就是,“cf push”确实是能一键部署了,但是为了实现这个一键部署,用户为每个应用打包的工作可谓一波三折,费尽心机。
而 Docker 镜像解决的,恰恰就是打包这个根本性的问题。 所谓 Docker 镜像,其实就是一个压缩包。但是这个压缩包里的内容,比 PaaS 的应用可执行文件 + 启停脚本的组合就要丰富多了。实际上,大多数 Docker 镜像是直接由一个完整操作系统的所有文件和目录构成的,所以这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。
这就是 Docker 镜像最厉害的地方:只要有这个压缩包在手,你就可以使用某种技术创建一个“沙盒”,在“沙盒”中解压这个压缩包,然后就可以运行你的程序了。更重要的是,这个压缩包包含了完整的操作系统文件和目录,所以你可以先用这个压缩包在本地进行开发和测试,完成之后,再把这个压缩包上传到云端运行。在这个过程中,这个压缩包赋予了你一种极其宝贵的能力:本地环境和云端环境的高度一致!这正是 Docker 镜像的精髓。
那么,有了 Docker 镜像这个利器,PaaS 里最核心的打包系统一下子就没了用武之地。相比之下,在当今的互联网里,Docker 镜像需要的操作系统文件和目录很容易获得。当然,docker run 创建的“沙盒”,也是使用 Cgroups 和 Namespace 机制创建出来的隔离环境,在后面的文章中,会详细介绍这个机制的实现原理。
所以,Docker 项目给 PaaS 世界带来的“降维打击”,其实是提供了一种非常便利的打包机制。这种机制直接打包了应用运行所需要的整个操作系统,从而保证了本地环境和云端环境的高度一致。而对于开发者们来说,在终于体验到了生产力解放所带来的痛快之后,他们自然选择了用脚投票,直接宣告了 PaaS 时代的结束。
不过,Docker 项目固然解决了应用打包的难题,但它并不能代替 PaaS 完成大规模部署应用的职责。而且 Cloud Foundry 项目并没有第一时间使用 Docker 作为自己的核心依赖,去替换自己那套饱受诟病的打包流程,反倒是一些机敏的创业公司,纷纷在第一时间推出了 Docker 容器集群管理的开源项目(比如 Deis 和 Flynn),它们一般称自己为 CaaS,即 Container-as-a-Service,用来跟“过时”的 PaaS 们划清界限。
而在 2014 年底的 DockerCon 上,Docker 公司雄心勃勃地对外发布了自家研发的“Docker 原生”容器集群管理项目 Swarm,不仅将这波“CaaS”热推向了一个前所未有的高潮,更是寄托了整个 Docker 公司重新定义 PaaS 的宏伟愿望,正式拉开了 Docker 公司扩张的序幕。
# 3. Docker 重新走回 PaaS 之路
Docker 项目之所以能取得如此高的关注,一方面正如前面所说,它解决了应用打包和发布这一困扰运维人员多年的技术难题;而另一方面,就是因为它第一次把一个纯后端的技术概念,通过非常友好的设计和封装,交到了最广大的开发者群体手里。这种受众群体的变革,正是 Docker 这样一个后端开源项目取得巨大成功的关键。这也是经典 PaaS 项目想做却没有做好的一件事情:PaaS 的最终用户和受益者,一定是为这个 PaaS 编写应用的开发者们。
Docker 公司在 2014 年发布 Swarm 项目,让他回到了 PaaS 项目原本深耕了多年的那个战场:如何让开发者把应用部署在我的项目上。
没错,Docker 项目从发布之初就全面发力,从技术、社区、商业、市场全方位争取到的开发者群体,实际上是为此后吸引整个生态到自家“PaaS”上的一个铺垫。只不过这时,“PaaS”的定义已经全然不是 Cloud Foundry 描述的那个样子,而是变成了一套以 Docker 容器为技术核心,以 Docker 镜像为打包标准的、全新的“容器化”思路。
这,正是 Docker 项目从一开始悉心运作“容器化”理念和经营整个 Docker 生态的主要目的。而 Swarm 项目,正是接下来承接 Docker 公司所有这些努力的关键所在。Docker 公司为什么要在 Docker 项目已经取得巨大成功之后,却执意要重新走回那条已经让无数先驱们尘沙折戟的 PaaS 之路呢?
其实公司一直有对 Docker 的担忧,因为用户最终是要部署业务平台,而 Docker 只是一个小工具,只有那些能够为用户提供平台层能力的工具,才会真正成为开发者们关心和愿意付费的产品。因此,Docker 公司决定向 PaaS 项目进化,从而提供更多的平台层能力。2014 年 Docker 发布 Swarm 项目,以一个完整的整体来对外提供集群管理功能。Docker 也开始借助这波浪潮通过并购来完善自己的平台层能力。
其中 Docker 公司最成功的案例是收购了 Fig 项目,它首次提出了“容器编排”(Container Orchestration)的概念。
但这之后,Swarm 发布的同年 6 月,Google 正式宣告了 Kubernetes 项目的诞生,这个项目再次改变了整个容器市场的格局。
# 4. 尘埃落定
2014~2015 年间,以 Docker 为中心的容器社区一片繁荣,但 Docker 在高速迭代中表现出不稳定和频繁变更问题。由此其他几家公司开始想切割 Docker 的话语权,从而成立了一个中立的基金会,提出了 OCI(Open Container Initiative)标准,目标将容器运行时和镜像的实现从 Docker 项目中完全剥离出来,从而避免了 Docker 公司在容器技术上的一家独大。
但是 Docker 已经成为了当时容器生态的事实标准,OCI 一直难以推进,所以 Google 和 RedHat 等公司把第二把武器摆上了台面。因为这场斗争一旦被转移到容器之上的平台层,Docker 公司的竞争优势便立刻捉襟见肘了。因为在平台层,Google 和 Redhat 这样的成熟公司才拥有深厚的技术积累,而 Docker 公司只有一个 Swarm。
于是 Google 等公司共同发起了一个 CNCF 基金会,并希望以 Kubernetes 项目为基础,建立一个由开源基础设施领域厂商主导的、按照独立基金会方式运营的平台级社区,来对抗以 Docker 公司为核心的容器商业生态。
Kubernetes 是 Google 在容器化基础设施领域多年来实践经验的沉淀与升华,并借助着 Redhat 的合作,用让人耳目一新的设计理念和号召力,很快就构建出了一个与众不同的容器编排与管理的生态。就这样,Kubernetes 项目在 GitHub 上的各项指标开始一骑绝尘,将 Swarm 项目远远地甩在了身后。
Kubernetes 推进整个社区的民主化架构,从 API 到容器运行时的每一层,Kubernetes 项目都为开发者暴露出了可以扩展的插件机制。很快在整个容器社区中催生出了大量的、基于 Kubernetes API 和扩展接口的二次创新工作,比如:
- 目前热度极高的微服务治理项目 Istio;
- 被广泛采用的有状态应用部署框架 Operator;
- 还有像 Rook 这样的开源创业项目,它通过 Kubernetes 的可扩展接口,把 Ceph 这样的重量级产品封装成了简单易用的容器存储插件。
Kubernetes 社区不断崛起和壮大,Docker 最终放弃了与 Kubernetes 生态的竞争,并转而专注于自己的商业业务,并在 17 年在 Docker 企业版中内置了 Kubernetes 项目,这标志着持续了近两年之久的“编排之争”至此落下帷幕。
2018 年 3 月 28 日,这一切纷争的始作俑者,Docker 公司的 CTO Solomon Hykes 宣布辞职,曾经纷纷扰扰的容器技术圈子,到此尘埃落定。
# 5. 总结
容器技术圈子在短短几年里发生了很多变数,但很多事情其实也都在情理之中。就像 Docker 这样一家创业公司,在通过开源社区的运作取得了巨大的成功之后,就不得不面对来自整个云计算产业的竞争和围剿。而这个产业的垄断特性,对于 Docker 这样的技术型创业公司其实天生就不友好。
在这种局势下,接受微软的天价收购,在大多数人看来都是一个非常明智和实际的选择。可是 Solomon Hykes 却多少带有一些理想主义的影子,既然不甘于“寄人篱下”,那他就必须带领 Docker 公司去对抗来自整个云计算产业的压力。
只不过,Docker 公司最后选择的对抗方式,是将开源项目与商业产品紧密绑定,打造了一个极端封闭的技术生态。而这,其实违背了 Docker 项目与开发者保持亲密关系的初衷。相比之下,Kubernetes 社区,正是以一种更加温和的方式,承接了 Docker 项目的未尽事业,即:以开发者为核心,构建一个相对民主和开放的容器生态。
这也是为何,Kubernetes 项目的成功其实是必然的。
现在,我们很难想象如果 Docker 公司最初选择了跟 Kubernetes 社区合作,如今的容器生态又将会是怎样的一番景象。不过我们可以肯定的是,Docker 公司在过去五年里的风云变幻,以及 Solomon Hykes 本人的传奇经历,都已经在云计算的长河中留下了浓墨重彩的一笔。