背景

img

云原生技术有利于各组织在**公有云、私有云和混合云*等新型动态环境中,构建和运行可弹性扩展*的应用。云原生的代表技术包括**容器、服务网格、微服务、不可变基础设施和声明式API**。

聊容器技术避不开云原生,聊云原生也避不开容器技术。容器技术和云原生就是一对双螺旋体,容器技术催生了云原生思潮,云原生生态推动了容器技术发展。从2013年docker(container)技术诞生,到2015年CNCF这个云原生领域重量级联盟便成立,这不是历史的巧合而是历史的必然。作为云原生关键技术之一的容器,从2013年诞生以来一直是行业关注的焦点之一。借用一张业界广泛引用的云原生容器技术进阶图来了解一下容器技术和云原生诞生的历史背景。

img

先让我们一起来看看容器技术发展的历史纪年表,先直观感受一下这片如火如荼的热土吧!

1979年,Unix v7系统支持chroot,为应用构建一个独立的虚拟文件系统视图。

1999年,FreeBSD 4.0支持jail,第一个商用化的OS虚拟化技术。

2004年,Solaris 10支持Solaris Zone,第二个商用化的OS虚拟化技术。

2005年,OpenVZ发布,非常重要的Linux OS虚拟化技术先行者。

2004年 ~ 2007年,Google 内部大规模使用 Cgroups 等的OS虚拟化技术。

2006年,Google开源内部使用的process container技术,后续更名为cgroup。

2008年,Cgroups 进入了 Linux 内核主线。

2008年,LXC(Linux Container)项目具备了Linux容器的雏型。

2011年,CloudFoundry开发Warden系统,一个完整的容器管理系统雏型。

2013年,Google通过Let Me Contain That For You (LMCTFY) 开源内部容器系统。

2013年,Docker项目正式发布,让Linux容器技术逐步席卷天下。

2014年,Kubernetes项目正式发布,容器技术开始和编排系统起头并进。

2015年,由Google,Redhat、Microsoft及一些大型云厂商共同创立了CNCF,云原生浪潮启动。

2016年-2017年,容器生态开始模块化、规范化。CNCF接受Containerd、rkt项目,OCI发布1.0,CRI/CNI得到广泛支持。

2017年-2018年,容器服务商业化。AWS ECS,Google EKS,Alibaba ACK/ASK/ECI,华为CCI,Oracle Container Engine for Kubernetes;VMware,Redhat和Rancher开始提供基于Kubernetes的商业服务产品。

2017年-2019年,容器引擎技术飞速发展,新技术不断涌现。2017年底Kata Containers社区成立,2018年5月Google开源gVisor代码,2018年11月AWS开源firecracker,阿里云发布安全沙箱1.0。

2020年-202x年,容器引擎技术升级,Kata Containers开始2.0架构,阿里云发布沙箱容器2.0….

整理容器技术近20年的发展历史,大致可以将其分为四个历史阶段,下文将详细介绍这四个历史阶段。

img

技术萌芽期

img

容器技术需要解决的核心问题之一运行时的环境隔离。容器的运行时环境隔离,目标是给容器构造一个无差别的运行时环境,用以在任意时间、任意位置运行容器镜像。由于docker的布道,大家习惯性认为容器的运行时环境隔离就是OS虚拟化,或则容器等于namespace + cgroup + 安全防护机制。我不太赞同这种看法,这个只是一段历史时期、一种容器运行时的实现技术,还有很多种其它可能的技术方案来实现容器运行环境。所以,回到需求的本源:容器需要运行时隔离技术来保证容器的运行环境符合预期。习惯上,大家把这种实现容器隔离技术的组件叫做容器运行时。

从另外一个角度看,容器隔离技术解决的是资源供给问题。为啥需要容器隔离技术来解决资源供给问题呢?成也萧何,败也萧何!摩尔定律实在太过强大,它让我们有了越来越多的计算资源可以使用。10年前做小型机时,小型机的典型规格是32路8核CPU,现在一台4路PC服务器计算能力都超过10年前的小型机服务器。小型机的典型用法是把整机切分为多个分区使用。观察当下云服务硬件发展趋势,越来越有熟悉的感觉,我们在把小型机相关技术“军转民”。现在我们一台PC服务器拥有了非常强大的、能和十年前小型机媲美的计算能力,巧合的是当下PC服务器的典型用法也和十年前的小型机用法类似,切割为1-8vCPU的虚拟机/容器使用。

为什么人们总是习惯于把一个大的服务器资源切分为小的分区使用而不是研发能够充分发挥大型服务器整机计算能力的软件呢?个人认为背后有两个制约因素:

  • 待解决问题本身内在的并行度有限。随着多核多处理器系统的日益普及,IT行业从2004年开始进行串行编程到并行编程的升级改造。开始阶段针对特定行业应用的并行化改造效果非常明显,但是后来发现随着并行度提高改造成本越来越大、收益却越来越低。受阿姆达尔定律制约,解决特定问题的并行度超过一定临界点之后收益将逐渐变小。所以一味提高系统并行度并不是经济的做法。

  • 人类智力有限。受人类智力限制,系统越复杂、并行度越高,软件越容易出故障,软件维护代价成指数级增长。所以,从软件工程看,大家也趋向于接口化、模块化、单元化的软件架构设计,尽量控制软件的复杂度,降低工程成本。

从经验看,1-8个CPU的并行度是软件工程的舒适区,这个也是容器化、微服务等技术背后的驱动因素之一。

有点跑题了。。。总之,基于隔离的资源供给不是伪需求。对于软件运行环境的隔离要求,从操作系统出现之初就有了。多任务分时操作系统和进程虚拟地址都是为了解决多个任务运行在同一台主机上的资源共享问题,让每个进程都以为自己独占主机。当然仅仅是进程隔离是远远不够的。纵观当前的资源隔离技术,我们大致可以将资源隔离技术分成5类:

img

  • 进程隔离。OS以进程作为Task运行过程的抽象,进程拥有独立的地址空间和执行上下文,本质上OS对进程进行了CPU和内存虚拟化。但是进程之间还共享了文件系统、网络协议栈、IPC通信空间等多种资源,进程之间因为资源争抢导致的干扰很严重。这个层级的隔离适合在不同的主机上运行单个用户的不同程序,由用户通过系统管理手段来保证资源分配与安全防护等问题。

  • OS虚拟化。OS隔离,也就是大家常说的操作系统虚拟化(OS virtualization),是进程隔离的升华版。进程隔离是为每个进程实现了单独的地址空间及CPU上下文,OS隔离则是利用操作系统分身术为每一组进程实例构造出一个独立的OS环境,以进一步虚拟化文件系统、网络协议栈、IPC通信空间、进程ID、用户ID等OS资源。OS隔离需要解决三个核心问题:独立视图、访问控制及安全防护。Chroot、Linux namespace机制为进程组实现独立视图,cgroup对进程组进行访问控制,而Capabilities、Apparmor、seccomp等机制则实现安全防护。当然,OS是一个非常复杂、动态变化的系统,OS分身术虽然让进程组感觉有了独立的OS,但是真实实现还是一个OS实例,所以整体防护能力还是堪忧。

  • 硬件虚拟化。OS虚拟化是实现OS内核的分身术,而硬件虚拟化则是实现硬件设备的分身术。硬件虚拟化技术的出现,让同一个物理服务器上能够同时运行多个操作系统,每个操作系统都认为自己在管理一台完整的服务器。不同操作系统之间是严格隔离的,Guest操作系统对硬件的访问都是受VMM或CPU的严格监管的。硬件虚拟化既有很好的安全性,也有很好的隔离性,缺点就是引入的硬件虚拟化层导致了额外的性能开销。

  • 硬件分区。这个是传统小型机体系采用的资源分隔技术,就是从硬件或固件层彻底把一台大型服务器分隔为多个硬件单元,从而获得最高等级的安全性和隔离性。但是小型机作为一个逐步没落的技术路线,其不足之处还是显而易见的:资源分隔粒度不灵活、系统成本偏高、系统可扩展性受限。

  • 语言运行时隔离。对于Java、nodejs等需要language runtime的managed language,我们还有一个选项,就是在language runtime里实现隔离。针对函数计算等云原生服务,理论上在语言运行时实现隔离机制是最优路径。但是这条路线目前实现上还有不少现实的制约,所以目前多数函数计算还是采用的容器/VM技术来实现的隔离。

在OS虚拟化这条技术路线上,最大的技术贡献来源于Google。2003-2006年,Google陆续发布的“三驾马车”,奠定了大数据计算的框架,随后进一步创造了“云”的概念。也是从这时期开始,进程隔离技术进入了一个更高级的阶段。在 Google 提出的云计算框架下,被隔离的进程不仅仅是一个与外界隔绝但本身却巍然不动的 Jail,它们更需要像一个个轻便的容器,除了能够与外界隔离之外,还要能够被控制与调配,从而实现分布式应用场景下的跨平台、高可用、可扩展等特性。2006年,Google推出Process Containers,用来对一组进程进行限制、记账、隔离资源(CPU、内存、磁盘 I/O、网络等)。由于技术更加成熟,Process Container 在 2006 年正式推出后,第二年就进入了 Linux 内核主干,并正式更名为 Cgroups,标志着 Linux 阵营中“容器”的概念开始被重新审视和实现。在 2008 年,通过将 Cgroups 的资源管理能力和 Linux Namespace (命名空间)的视图隔离能力组合在一起,一项完整的容器技术 LXC (Linux Container)出现在了 Linux 内核中,这就是如今被广泛应用的容器技术的实现基础。

总体看,在2013年docker被发明以前,Linux操作系统已经大体上解决了容器核心技术之一的运行环境隔离技术,或者说Linux OS虚拟化技术已经基本上成型了。虽然容器运行环境隔离技术已经基本就位,我们仍需等待另外一项关键技术才能迎来容器技术的腾飞时刻。

技术迸发期

img

2013年之前,云计算行业一直在为云原生的正确打开姿势而操心。Platform as a Service(PaaS)看起来是个有前途的方向。2006年Fotango公司发布的Zimi服务,可以说是PaaS行业的鼻祖,具有按使用付费、免运维(Serverless)、API化配置和服务等典型云原生的特征;2008年Google推出GAE;2011年Pivotal发布Cloud Foundry。这些早期的PaaS平台进行了非常有益的探索,推动了云计算生态的健康发展,但是这些早期探索技术并没有形成大的行业趋势,而是局限在一些的特定的领域。直到Docker开源,大家才如梦方醒,原来不是方向不对,而是应用分发和交付的手段不行。

Docker真正核心的创新是容器镜像(docker image),一种新型的应用打包、分发和运行机制。容器镜像将应用运行环境,包括代码、依赖库、工具、资源文件和元信息等,打包成一种操作系统发行版无关不可变更软件包。

  • 容器镜像打包了整个容器运行依赖的环境,以避免依赖运行容器的服务器的操作系统,从而实现“build once,run anywhere”。

  • 容器镜像一但构建完成,就变成read only,成为不可变基础设施的一份子。

  • 操作系统发行版无关,核心解决的是容器进程对操作系统包含的库、工具、配置的依赖,但是容器镜像无法解决容器进程对内核特性的特殊依赖。这个在实际使用容器的过程中也经常跳进这个大坑:

Docker的宣传口号是“Build,Ship and Run Any App,Anywhere”。我们已经理解了docker通过container image解决“Run Anywhere”的机制,那么“Run Any App”是如何实现的呢?其实也是依赖container image,用户可以打包任何容器进程所依赖的环境,而不用改造应用来适配PaaS定义的运行环境。真是“Run Any App”一举打破了PaaS行业面临的困境,创造出了无限的可能性,大力推动了云原生的发展。让我们一起来向这个伟大的创意致敬!

img

至此,容器技术体系已经解决了最核心的两个问题:如何发布软件如何运行软件腾飞时刻即将到来。2014年前司前老板对我说“别成天搞Linux kernel了,要不你看看docker?” 经过短暂的调研,我给了前老板一个简单而清晰的回答,“无它,唯打包工具尔!”因为这个回答,云原生为我打开的一扇大门就悄悄关上了。回想一下历史,有时也挺懊悔的,因为自己太年轻而没有看清楚容器技术 + 编排系统的威力,更没有体会到云原生即将到来的气息!

Docker作为一个单机软件打包、发布、运行系统,其价值是非常巨大的;但是仅仅将docker技术局限在单机范围不能发挥这个创新技术的最大价值,自然下一步业界希望基于docker技术构建一个云化的集群系统,来对业务容器进行编排管理。

聊到容器编排系统,我们需要从Google聊起。2008年,Google 基于 LXC 推出首款应用托管平台 GAE (Google App Engine),首次把开发平台当做一种服务来提供。GAE 是一种分布式平台服务,Google 通过虚拟化技术为用户提供开发环境、服务器平台、硬件资源等服务,用户可以在平台基础上定制开发自己的应用程序并通过 Google 的服务器和互联网资源进行分发。Google 在 GAE 中使用了一个能够对 LXC 进行编排和调度的工具 —— Borg (Kubernetes 的前身)。Borg 是 Google 内部使用的大规模集群管理系统,可以承载十万级的任务、数千个不同的应用、同时管理数万台机器。Borg 通过权限管理、资源共享、性能隔离等来达到高资源利用率。它能够支持高可用应用,并通过调度策略减少出现故障的概率,提供了任务描述语言、实时任务监控、分析工具等。如果说一个个隔离的容器是集装箱,那么 Borg 可以说是最早的港口系统,而 LXC + Borg 就是最早的容器编排框架。

2013年docker推出之后迅速席卷全球,2014年Google基于内部使用的Borg系统创建了开源项目Kubernetes(简称K8S),用于解决大规模集群的容器部署、运行、管理等问题。Kubernetes在容器的基础上增加了一层的新的管理抽象Pod,以便更好地利用容器进行应用的功能模块切分。得益于 Google 在大规模集群基础设施建设的强大积累,脱胎于 Borg 的 K8S 很快成为了行业的标准应用,堪称容器编排的必备工具。

作为回应,Docker公司在2015年发布的Docker 1.12版本中也加入了一个容器集群管理系统Docker swarm,以及配套的Docker machine、Docker Compose等工具,力图构建完善的容器编排系统,和Kubernetes展开正面竞争。从此,容器江湖分为两大阵营:Google派和Docker派;而容器编排系统则是Kubernetes,Docker Swarm和Apache Mesos三国并立。各大派系的竞争愈演愈烈,逐渐延伸到行业标准的建立之争。让我们一起来回忆一下这段风起云涌的江湖历史吧!

2013年Docker公司推出docker之后,紧接着CoreOS 应运而生。CoreOS 是一个基于 Linux 内核的轻量级操作系统,专为云计算时代计算机集群的基础设施建设而设计,拥有自动化、易部署、安全可靠、规模化等特性。其在当时有一个非常显眼的标签:专为容器设计的操作系统。借着 Docker 的东风,CoreOS 迅速在云计算领域蹿红,一时间,Docker + CoreOS 成为业内容器部署的黄金搭档。同时,CoreOS 也为 Docker 的推广与社区建设做出了巨大的贡献。然而,日渐壮大的 Docker 似乎有着更大的“野心”。不甘于只做“一种简单的基础单元”的 Docker,自行开发了一系列相关的容器组件,同时收购了一些容器化技术的公司,开始打造属于自己的容器生态平台。显然,这对于 CoreOS 来说形成了直接的竞争关系。2014 年末,CoreOS 推出了自己的容器引擎 Rocket (简称 rkt),试图与 Docker 分庭抗礼。rkt 和 Docker 类似,都能帮助开发者打包应用和依赖包到可移植容器中,简化搭环境等部署工作。rkt 和 Docker 不同的地方在于,rkt 没有 Docker 那些为企业用户提供的“友好功能”,比如云服务加速工具、集群系统等。反过来说,rkt 想做的,是一个更纯粹的业界标准。

上面这段材料引至于“从虚拟化到云原生——容器技术的发展史”,为什么大段大段地引用这部分材料呢?这里面最关键的脉络是由于技术公司之间的商业竞争,在竞争合作之间寻找平衡从而导致了标准规范的诞生,而标准规范的诞生是整个云原生生态最重要的基石

容器引擎(docker vs rocket)、容器编排(Docker swarm vs Kubernetes vs Apache Mesos)的相互竞争的结果就是大家坐下来谈接口标准。2015年6月,Docker带头成立OCI,旨在“制定并维护容器镜像格式和容器运行时的正式规范(OCI Specifications)”,其核心产出是OCI Runtime Spec(容器运行时规范)、OCI Image Spec(镜像格式规范)、OCI Distribution Spec(镜像分发规范)。所以OCI组织解决的是容器的构建、分发和运行问题。一个月之后,Google带头成立了Cloud Native Computing Foundation(CNCF),旨在“构建云原生计算 —— 一种围绕着微服务、容器和应用动态调度的、以基础设施为中心的架构,并促进其广泛使用”。所以CNCF组织解决的是应用管理及容器编排问题。这两个围绕容器的基金会对云原生生态的发展发挥了非常重要的作用,二者不是竞争而是相辅相成,共同制定了一系列行业事实标准。这些行业事实标准的确立,各行业注入了无限活力,基于接口的标准的具体实现不断涌现,呈现出一片百花齐放的景象。

image.png

其中,与容器相关的最为重要的几个规范包括:CRI、CNI、CSI、OCI Distribution Spec、OCI Image Spec、OCI Runtime Spec和Shimv2。其中的CRI、OCI Image Spec、OCI Runtime和Shimv2规范和阿里云沙箱容器关系非常密切。

所以,非常感谢这个云原生、容器技术迸发的黄金期,一群有创意的人走到一起共同创造了这几个关键的规范,为各个厂商提供各具特色且遵循规范的技术实现提供了可能性。

商用探索期

img

经过5年的技术发展期,容器技术基本成熟,云原生体系也具雏型。从2017年开始,各大云厂商开始试水容器服务及进步的云原生服务。从目前的商业形态看,容器相关的公共云服务大致可以划分为三种形态:

  1. 通用容器编排服务。在容器编排系统三国杀结果出来以前,基于多方下注策略构建的容器编排服务系统。其中AWS是自研的编排系统,Azure的ACS同时支持Docker Swarm、DC/OS和Kubernetes,阿里云ACS则是支持Docker swarm和Kubernetes。Google和华为则是坚定支持Kubernetes而未推出支持其它容器编排系统的容器服务。随着Kubernetes一统容器编排江湖,这条路线的容器服务日渐式微,Azure更是在今年初直接终止了ACS服务。

  2. Kubernetes容器编排服务。Google是理所当然最早试水Kubernetes容器编排服务的大厂,也较早开展了K8S容器编排服务。随着2017年各大厂在CNCF这张谈判桌上达成了Kubernetes兼容性认证流程,Kubernetes编排服务市场迎来一轮大爆发,到2018年各大云厂商的K8S容器编排服务就完整就位了。

  3. Serverless容器实例服务。从2017年开始,行业开始试水Serverless容器实例服务,把用户从维护容器基础设施的繁重任务中解放出来从而聚焦业务本身。Google Cloud Run核心目标是支持Knative,所以其使用形态上附加了不少约束条件。

img

从上图可以看出,从2014年开始探索公共云容器服务,特别是经过2017-2018年这两年的抢跑期,容器服务的基本商业形态已经比较明晰了。发展态势可以概括为:

  • 行业对容器化的接受程度已经很高,容器化普及率也是逐年提升。

  • 容器编排系统已经一战定江山,K8S成为事实上的容器编排之王。

  • Serverless容器实例服务受到市场的欢迎,客户群体日益扩大。

  • 长期看托管容器编排服务和Serverless容器实例服务将长期共存,协同满足客户对服务成本和弹性能力的需求。

商用模式探索期间,核心目标是快速试错引导和确认客户需求,构建适用的产品形态。这个期间的产品技术架构的构建思路是利用现有成熟技术快速搭建商用形态,在试错过程中不断前行。

其中,容器编排托管服务节点级的典型架构是利用IaaS系统生成VM,然后在VM里面部署kubelet、docker、containerd、runC等容器服务组件,也就是VM + 容器的技术架构。一个VM可以承载同一个用户的多个容器/Pod实例。而Serverless容器实例服务的节点级架构更直接,在一个VM里面只部署一个容器/Pod实例,从而实现Serverless。这种短平快的打法快速推进了商用模型的探索,起到了非常重要的历史作用,但是其在弹性能力、部署密度、资源成本方面的历史局限性还是很大的。

img

商用拓展期

img

到2019年,容器服务的商业形态以及市场趋势已经很明显了,行业整体进入了商业拓展阶段,对外宣传吸引更多的客户群体,对内苦练内功提升产品技术竞争力,行业正在经历从“有”到“优”的技术升级。行业正在经历这个技术升级的历史阶段,还谈不上结论,只能一起来聊聊趋势及预判。本系列专题的关注点是容器隔离技术,所以先不聊商业拓展和容器编排而聚焦于容器引擎技术发展趋势。到现在为止,我们大体上可以把容器引擎技术划分为两代:

  1. Container on VM。也就是按照分层设计思路,通过IaaS + PaaS的架构构建容器服务,这个是商用探索阶段的典型架构。基于各大云厂商成熟的IaaS基础设施生产虚拟机,在虚拟机里面部署容器服务组件。这种架构采用的是lift and shift策略,把容器服务的运维责任从用户转移到云厂商。采用和用户相同的软件组件,只是转移运维责任,有利于引导客户逐步上云、接受云原生思维。但是这个时期云厂商提供的服务是单纯的运维托管,相对用户自建容器服务并没有太明显的技术优势,甚至受多租户隔离的限制部分使用体验还不如用户自建容器服务。

  2. Container with hardware virtualization。如果沿用Container on VM的分层设计架构,云厂商很难构建独有的技术优势。对于Serverless容器实例服务,服务交付平面已经从IaaS的硬件接口上移到OS Syscall,所以不要遵循VM + 容器的分层设计思路。我们需要从需求本源出发,容器服务需要高性能、强隔离、够安全和低成本的容器引擎。当前行业研发热点之一就是如何构建这样一个容器引擎,具体技术思路请留意后续系列文章。

小结

img

总结来看,容器服务生态大概经历了四个阶段,分别解决或试图解决不同的问题:

  1. 技术萌芽期:解决了容器运行环境的隔离问题
  2. 技术迸发期:解决了软件分发及容器编排问题
  3. 商用探索期:确认了容器的商用服务形态
  4. 商用拓展期:扩大适用场景和部署规模,通过技术创新提升产品竞争力

闲言碎语

img

聊了这么多历史,让我们再来闲聊一下docker这个公司和docker这门技术吧!

2019年11月13日,私有云基础设施公司Mirantis在其官方博客宣布,收购Docker公司企业级业务,包括接管它的700多个客户,这标志着Docker公司从2013年开始的商业化探索彻底失败。在不了解容器发展历史的人看来,这种结果很难理解,Docker是容器热潮的开创者,容器则是这一轮云计算技术演进的开启者,为什么明明站在风口上了,却仍然飞不起来?

其实,Docker今天的命运,在4年前就决定了。2014年Kubernetes发布后,迅速吸引了包括Redhat在内的一批重量级成员,并在一年之后迅速发布Kubernetes 1.0以支撑正式商用。作为回应Docker公司主导成立了OCI,旨在为容器镜像格式和运行时制定一个开放标准,从而继续占据容器生态的话语权。但是2015年7月CNCF成立之后,迅速弯道超车开辟新的战场,主攻容器编排与应用管理。随后2016年Kubernetes社区制定了容器运行时的接口规范CRI,只要实现这个CRI规范的容器运行时就可以和K8S生态对接,从引发了容器引擎的研发热潮。cri-containerd,cri-o,frakti等引擎不断涌现,加上原有的rkt引擎,docker变成了容器引擎芸芸众生中的一员。从哪儿来到哪儿去,docker又回到了最初的状态,一个单机版软件打包运行工具,基本上完美错过了云原生浪潮。

但是在相当长的时期内,docker这个客户端容器管理工具(UI)还是会长期存在的,毕竟强大的用户群体在哪儿。但是在云服务厂商的技术栈中,docker的地位会越来越弱,逐步被K8S专用的容器引擎替代。虽然现在docker的群众基础依然强大,但是星星之火已经点燃,趋势已然显现,剩下的只是时间问题!


参考文献

  • Cloud Native and Container Technology Landscape
  • A Brief History of Containers: From the 1970s Till Now
  • 从虚拟化到云原生——容器技术的发展史
  • 为什么说2019,是属于容器技术的时代?
  • 阿里巴巴在安全容器上的实践与探索
  • 安全容器在边缘计算场景下的实践
  • 展望2020:传统容器已死,安全容器将成为云原生标配

img