从「集装箱」思考Docker风潮
2017-09-23
Docker

从「集装箱」思考Docker风潮

-- Docker潮流下的赢家策略

By 高焕堂 

2015/02/20  (2015/8/16更新)                                              

 前言

   在许多革命性转折里,经常出现集装箱的身影;它就像幸运草一般,总是带来许多幸福和财运。现在Docker风起云涌,再现集装箱身影,如果开放视野、大力支持它,持续发挥它的潜能和力量,则幸运草就会出现在我们身旁了。

  由于Docker集装箱带来的商机,其最直接的受益者是软件管理者(或称维运者),例如软件测试工具业者、测试人员等。因此在今天,不论您是开发者或是维运者,最好是从维运者的角度、扩大视野来支持它,便能站在制高点上拟订最佳策略,掌握了需求碎片化的潮流,进而成为新世代的领头羊。

  在这新世代里,除了拿Docker集装箱来打包微服务(micro-service)来满足需求碎片之外。我们还要以广大的视野、创新的思维,将碎片组合出各式各样、气象万千的商业服务。就像飞机设计师一样,把一群各自<不会飞>的模块(如轮胎、引擎、机翼、油箱等),以创新模式将它们组合起来,竟然整体就<能飞>上天空了。于是,创新组合的接口(interface)的定义权成为兵家必争之地,唯有掌握接口才有话语权。

1、缘由

自從2014年以來,Docker 的集装箱(container)技术,可说是红透半天边,而且势如破竹、蔚为风潮,正在强力改变云(cloud)服务的世界。这跟半世纪前,海上船运业的集装箱风潮,对整个产业的革命性改变,其力道来源和产生经济效益,可说具有异曲同工之妙。

     

       wKiom1TprDfStFdWAAB98bcr0pM520.jpg

         图-1、Docker平台的标志(Logo)

 

这项力道和潮流的直接受益者,是管理者(operator,又称维运者),而不是开发者(developer)。因此,在本文里,我将从管理者的视角来说明Docker集装箱即将带来的革命性潮流,让读者们皆能兴奋地迎接这项已经来到身边的潮流,并且能从中获利。

 

2、回顾半世纪前的船运集装箱风潮

在半世纪之前,集装箱发挥了巨大的力量,改变了整个运输产业,也改变了人们的生活。就如Intel公司总裁葛洛夫(Andrew Grove)曾举集装箱为例说道:

「短短的十年,实际上只是航运史上一个极短促的时间,造船设计即走向标准化,冷冻运输船也诞生了,最重要的是集装箱化作业的兴起,这种容许船货更快速装卸的技术在航运的生产力上引进了『十倍速』的改变,逆转了节节升高的成本趋势,..... 有些港口做了改变,有些虽尽力改革,却无法做到,许多则坚持抗拒这种潮流,结果,这些新技术引发了全世界货运港口的重新洗牌,.... 没有采行新技术的港口(如新加坡及西雅图)可能被重新规画,成为购物中心、休闲场所或河岸公寓大厦。」

      wKioL1TprVuixl0IAAD3cTw8GFs421.jpg   

         图-2、集装箱让运输费用降低一半(以下摘自百度图片)

 

长荣海运公司总裁 张荣发 先生在其回忆录上写道:

「为了配合集装箱化运输时代的来临,海运事业的整体运作型态也产生了重大的转变,无论在海上运送、码头作业以及陆运转接上,都有革命性的改变。陆上拖车运输业应时而兴,扮演极为重要的角色,以集装箱拖车配合集装箱船运输,具有简化包装、防止窃盗、加速货物搬运及便利关务检验等优点,使集装箱运输作业更加灵活。为了能确实掌握海上及陆上的运送服务质量和效率,就率先于1973年9月成立了长荣运输公司。」

 

      wKiom1TprI-zxCh6AAC_ZcfTjKw361.jpg

           图-3、世界航运巨擘:长荣(Evergreen)

 

集装箱的威力是来自于它提供了一致的接口(interface),简化了运输业的工具。例如以前,在集装箱尚未普及之前,在公路上,必须为汽车业而设计特殊的拖车;在港口码头,也必须为木材业而设计特殊的卸货吊车及仓库等等。这些特殊设计对于运输管理、港口管理、仓储管理等都是很麻烦的事。有了集装箱之后,就出现了专门运集装箱的轮船,也有专门拖集装箱的拖车,高速公路的弯曲度也因集装箱拖车的安全而修正,仓库的管理也变得很单纯。集装箱不一定带给汽车业、木材业、玩具业带来直接的方便,也许反而带来不方便(如大汽车必须拆解开来才能装进集装箱里)。但是运输业等获得好处,所以运输业会很乐意把集装箱拱抬起来,促成集装箱的革命性风潮。

将之对应到Docker风潮,可知道Docker集装箱的效益在于:让所有云服务都有一致的操作(operation)界面,包括部署、管理等方式。众多云平台就像众多码头一样,都使用一致的方式来操作集装箱,例如卸货器具、拖车等。Docker公司的Scott Johnston曾说道:

「你将不再需要使用各项单独的IT管理工具来分别进行App的管理、部署、监控和扩容等功能操作,在整个企业内这些操作都可得到一致性、统一性。」

 

3、从<国王的皮鞋>领悟Docker集装箱的经济效益

古代有一位国王在它的国境里视察,因为路面崎岖不平,还有很多碎石头,刺得国王的脚又痛又麻。

           wKioL1TprfeAv3kJAAEN_MLzw4U767.jpg

   图-4、赤脚国王的故事(摘自百度图片)

   回到了王宫后,他下了一道命令,要将国内所有的道路都铺上一层牛皮。让他自己和]全国的人走路不再受刺痛之苦。众大臣听了国王的话都一筹莫展,知道这很难。即便杀尽国内所有的牛,也凑不到足够的牛皮来铺路,而且花费昂贵。这时,一个聪明的仆人向国王建言:可以试着用牛皮将脚包起来,大王的脚就不会忍受痛苦了。国王听道而顿悟了,便收回命令,采纳了建议,于是,皮鞋就这样发明了出来了。

  wKioL1TprkOQVrDCAACaXBtvdBI793.jpg

                     图-5、国王的皮鞋


 

  我想,大家一定都听说过上述的皮鞋故事了。其解决脚痛不方便的方案有二:第1方案是:将所有道路都铺上一层牛皮(如VMware),实在不经济实惠。 第2方案是:用两片牛皮包住脚,这就是皮鞋(Docker集装箱)。那么,你领悟到什么呢? 至少明显知道第2方案可带来可观的经济效益。

  从上述皮鞋故事的比喻,可知道传统的虚拟化(virtualization)技术就相当于在各道路(实体机器)上铺一层牛皮(VM, 虚拟机),然后让国王的脚(App)在牛皮(VM)上走路(执行)。传统上云平台采取虚拟化手段来满足用户个别的资源需求分配,以及确保其可用性和隔离性。然而无论是KVM还是Xen等Guest OS都很浪费资源又难于管理, 都不如Docker集装箱(皮鞋)来的更加灵活、快速和节省资源。

 

4、Docker如何运输(ship)集装箱?

 顾名思义,Docker就是“码头搬运工人”之意。而集装箱的主要用途就是运输东西。所以,我们把焦点放在Docker集装箱和如何运输上,也就是从运输(shipping)的角度来认识Docker及其集装箱。

 设想在开发平台上,开发者撰写一份dockerfile档,让Docker(码头搬运工人)在此平台上建立一个Docker集装箱,此集装箱运行于开发平台上的一个用户进程(process)里,包含了执行某一特定App程序的所需要的OS、软件库、配置文件和资料,是一个可移植的运行单位。那么,如何把这个集装箱运输(移植)到云平台上呢?这时,Docker(码头搬运工人)就从这个集装箱(或其dockerfile)产生出它的镜像(image),通称为Docker(集装箱)镜像;然后把该(集装箱的)镜像传输到云平台上。云平台上的Docker会依据这镜像,修改一下配置模块,就在云平台上创建一个新的Docker集装箱了,让App在此集装箱里执行。相对上,一个Docker镜象是一个模子(template),可用来创建多个Docker集装箱对象或实例(instance)。

   由于Docker集装箱及其镜像,是由dockerfile文件的脚本所创建的;所以也可直接将dockerfile文件传输到云平台,并依据其脚本而在云平台上创建新的Docker集装箱。集装箱的dockerfile文件和镜像两者都是模子,都可用来(在云平台上)创建集装箱实例,并让App顺畅执行起来。软件专家波金(Lucas Perkins)在其文章:“ Docker and Shipping Containers:  An Imperfect Analogy”里,就拿一棵树来比喻一个Docker集装箱,而不是拿船运集装箱来比喻。他说道: 

  • “The shipping container analogy is apt, but for me it completely breaksdown on one crucial point: when shippingcontainers go down, their cargo is lost.”(拿船运集装箱来比喻是可以的,但有一点会失真:当集装箱沉入大海,货物就消失了。)  

  • “Docker containers don't work this way. When they go down, you simplyrebuild the container.”(Docker集装箱并非如此,当它损毁了,只要重建一个就行了。) 

  • “In this sense, Docker containers are more like plants than shippingcontainers. If a plant dies, you simply plant a seed and replace it.” (以此观之,Docker集装箱更像树木。如果一棵树枯死了,只要播下种子,长出一棵新树就行了。) 

  • “If a Docker container goes down, .... You can simply use the oldcontainer's Dockerfile (think of it as a container seed) to sprout a newcontainer identical to the old one. Even better, Dockerfiles, like seeds, tendto be quite small , but they can grow into mighty oaks.”(如果一个Docker集装箱损毁了,你只要使用原来的dockerfile(就像种子)来重新长出一棵一样的树就行了。而且一个小小的dockerfile,就能长出一棵大树。)

 上述dockerfile是一种脚本文件,用来描述如何把二进制(binary)文件装进一个Docker集装箱镜像(Dockerimage),并做好配置。当你使用docker build命令的时候,Docker会读取这dockerfile文件,执行其脚本内容来构建立一个Docker镜像。所以,DockerFile的用途就(像樹的種子)用来构建Docker镜像。我想,从上所述,你应该可以领悟Docker集装箱运输的涵意了。

 

5、从LXC容器到Docker集装箱

Docker集装箱是基于LXC容器而发展出来的。其实,这里的集装箱和容器都是“Container”术语的的中文翻译。那么,为何我称LXC容器,而称Docker集装箱呢? 其主要原因是:LXC容器是特定平台的虚拟化,不能充分独立于底层机器(平台)的配置(configuration),例如networking, storage, logging, distro等等。所以,LXC本身无法充分跨(机器)平台,导致App也无法跨平台。也就说,LXC难以通过标准化的模板制作、重建、复制和移植,无法如船运集装箱一般,可以跨越各地港口和码头。

后来,Docker弭补了这项缺点。Docker在LXC与平台之间定义了标准接口,提供一种安全、可重复的执行环境,让各集装箱都运行于自己的网络空间、虚拟界面和IP地址;并能自动部署和更新软件版本。这种跨平台的新型LXC就成为Docker集装箱。就像船运集装箱与各港口的码头、各公司货轮或拖车的型号、配置是无关的。

简而言之,虽然LXC容器很成熟了,只是缺乏跨平台性,不方便在多平台(机器)之间移动;也不方便于创建管理,不易于重复操作和共享等。基于成熟的LXC容器功能,Docker集装箱解决了上述问题,成为可移植、易于改版与整合的新一代虚拟化技术。“集装箱”一词强调了Docker 集装箱的效益在于:让所有云服务都有一致的部署、传输、改版等管理方式。众多云平台就像众多码头一样,都使用一致的方式来操作集装箱,例如卸货器具、拖车等。

 

6、认识LXC容器

  LXC仰赖namespace来实现隔离性。让每个容器都有自己的命名空间,确保不同容器之间不会相互影响,让每个容器成为拥有自己进程和网络空间的虚拟环境,都成为一个独立运行的单位。此外,LXC藉由内核的cgroup来对各个容器(的进程)使用的系统资源做严格的限制。

     wKioL1TpsMngc0eRAABiI1fwTec847.jpg

简而言之,LXC基于namespace的隔离机制和cgroup的资源控制功能,来管理容器。例如可建立一个cgroup来限制某个(容器)进程对CPU的占用率不能超过50%。而Docker则在LXC基础上,加上Docker境像管理方式,就成为Docker集装箱了。

     wKioL1TpsOjgnQ0jAABuZZpc8ek590.jpg

    Docker借鉴了虚拟机(VM)的模式,让用戶像管理VM一样的管理他们的集装箱镜像。

 

6.1 隔离性

   LXC运行于一个用戶空间进程里,在既有的进程管理架构上,增添了资源管理和隔离机制。所以LXC是针对某一App提供资源隔离和控制的轻量型虚拟系统。LXC仰赖namespace来实现隔离性。让每个容器都有自己的命名空间,比如pid/net/ipc/mnt/uts等命名空间,以及不同的 user id和group id。有了namespace从进程、网络、IPC、档系统、UTS和用户角度进行隔离,我们就能e确保在不同容器之间不会相互影响,每个容器都成为一个独立运行的单位。从容器里而观之,它是一个完整的Linux的世界。在整个平台而观之,容器运行于一个普通的用户空间进程,namespace创造了这种映射和隔离效果,云平台承载着一个个容器,就如同造物者创造了许多世外桃源一般。

 

6.2 资源控制

  LXC仰赖cgroup来限制各个进程对系统资源的使用能力。通常会创建多个cgroup,形成一个树状结构(hierarchy)。然后subsystem会关联连接到这个树状结构上。一个subsystem代表着一项资源,例如CPU、Memory或 I/O等。例如下图:

    wKioL1TpsWzzjKjjAADG3LP_wH4943.jpg

     图-6、cgroup树状结构

 这图里的cgroup组织形式是树状结构的,包含一个父cgroup和三个子cgroup,其关联到两个subsystem (即CPU和memory)。这subsystem是经由cgroup来与task(典型的就是进程)连结,以便实现对task的资源管理与控制。一个task可加入到树状结构上的一个cgroup,由此cgroup来限制该task的资源使用。其中,cgroup与task是多对多(N:N)的连结关系。亦即,一个cgroup可以连结到多个task。而一个task也可连结到多个cgroup,但是在一个树状结构里只能加入一个cgroup。例如,针对一个(容器)进程,先创建名为“cpuset”的cgroup,然后将一个进程(/mytask)的PID写入/sys/fs/cgroup/cpuset/ tasks 文件里,就把这个mytask加入到该cgroup了。如下图: 

    wKiom1TpsHTBnM0nAAE24SmaStk542.jpg 

       图-7、cgroup与task的N:N连结关系

  这个mytask连结到两个cgroup:即“cpuset”和“ioset”,各连结到一个subsystem(即CPU和I/O资源)。

 

7、认识Docker园丁(Runtime)

  刚才说明了,我们在运输(ship)或移植一个Docker集装箱时,就像移植一棵树一样, 但是移植树的种子(seed)到另一个花园(平台)里,重新打造出一样的(identical)环境(花盆)并重新长出一样的树。例如,一个dockerfile就是种子,体积很小,运输快速。如下图:   

   wKiom1Tpsujj_MwQAAESaE06H8Q505.jpg

     图-8、以树来比喻Docker集装箱的运输

   

 那么,我们在电脑上,需要有位园丁来打造花盆、准备资源(如水、泥土)等工作。这位园丁就是:Docker Runtime。它是由三个模块所组成,包括:Docker Server、Docker Engine和Docker Daemon三部分。通常,人们是透过Docker Client来与Docker Server建立通信(两者是C/S架构)。例如,我们可以将docker build命令传送给Docker Server来依据指定的dockerfile来创建一个Docker镜像。   

   wKiom1TpsjOxFqxRAACsouvXYsI299.jpg

    图-9、Docker Runtime的结构

   Docker Server接受DockerClient所传送来的请求,然后转给Docker Engine去转换出一连串的工作(job)来管理集装箱。例如,向Docker Registry获取镜像、通过GraphDriver执行集装箱镜像的建立、通过NetworkDriver执行容器网络环境的配置、通过ExecDriver执行集装箱内部的软件等。

 

8、认识Docker集装箱集散地(Hub)

  Docker公司不仅仅提供上述的Docker园丁来帮你搬运集装箱,还提供DockerHub来做为集装箱的共享平台。Docker公司提供的開放平台,主要包括:

    Platform = Docker Engine + Docker Hub + APIs + Ecosystem

如下图: 

   wKioL1TptKKQ8Jx2AAEKzs0aFXE066.jpg

    图-10、<Docker Engine + Docker Hub>开放性平台

  我们在开发平台上,使用Docker引擎来将App打包到集装箱里,然后透过DockerHub API来将集装箱(的镜像)放到DockerHub上。于是,Docker Hub成为一个集装箱集散地,也就是一个共享的集装箱平台。需要时,可从这Hub寻找到集装箱,并下载到云服务平台(如阿里云或Google云)上去运行。 

   wKiom1Tps7Cz34zAAAD7GUvjJ1o035.jpg

    图-11、Docker Hub集装箱共享平台

  所以,Docker Engine和Docker Hub两者联手,为开发者和系统管理员设计出一个易于发布和运行分布式App的开放性平台。 

 

9、阐述<集装箱>幕后的架构设计思维

 9.1 序中有乱

 前面,介绍过了台湾长荣海运公司繁荣发达的历史经验,可让你体会出集装箱如何带来巨大经济价值。集装箱的外表简单有序、能叠得很高、而且井然有序;集装箱的内部是空的,用来容纳多样化而繁杂的物品;这种情形称为:序中有乱(变化)。序中有乱的巨大威力,改变了整个运输产业,也改变了人们的生活。

  俗语说:科学家从乱中找序,而设计师(艺术家)则规划序中有乱。无论是「乱中有序」或「序中有乱」,两者都要呈现出序(order),并包容乱(change),只是手段不同而已。两种手段都能带来巨大经济价值,精通这两种手艺,是当今需求碎片化时代哩,将云平台上的微服务(micro-service)迅速创新组合成为App的不二法门。序中有乱的<乱>是变化、成长与繁荣之意。

 「乱中有序」与「序中有乱」两者之间,只是人们抽象视角(viewpoint)的不同心智(mental)呈现而已,并外在世界的真实事物(和景像)。就像大家孰悉的「横看成岭侧成峰,远近高低各不同」诗句里,因为视角不同而呈现于内心的不同景像。例如,台北101大楼的钢骨结构,可从「序中有乱」视角来看它;也可以从「乱中有序」来看它。再如,一盆看来很漂亮的枫叶,既可从「序中有乱」视角来看它;也可以从「乱中有序」来看它。 

          wKioL1TptNHiJc5rAAFxFHj754M560.jpg

    图-12、「乱中有序」还是「序中有乱」呢?

  其实,中文字的<易>,并不代表简单(easy);而是代表变化(change)之意。当我们找到一种容器(container),来包装变化,就得到简单了。因此,「容易」两个字组合在一起,才代表简单(easy or simple)之意。于是,Docker集装箱以容器来包装复杂多变,任人们拥有<简单而容易>的方式来实践App的维运。它的幕后蕴藏了典型的「序中有乱」架构设计思维。

 

9.2 <合>的设计法则

  在我所写的书籍:《思考软件、创新设计:A段架构师的思考技术》(北京电子工业出版社)里,我也详细阐述了集装箱的设计哲理,我书中写道:

 「这来自于自然界的造物之道。自然界生物之设计,其主要限制是:信息的有限性(Information Limitations)。由于这项限制,一个生物形体的造成,是出自一个概括性的计划:<单纯的造形>。随着生物的成长、与环境的交互信息越多,逐渐在细节上修修补补,就发展出<不同的内涵>。然后,基于单纯的造形,不断进行<重复的组合>。例如,漂亮的枫叶林,就是合乎“单纯造形、不同内涵、重复组合”三项特性。许多造形相同(且不同细节)的枫叶,组合出一遍美丽的树林。」

           wKiom1Tps9yzy4AMAAC_hKincuU218.jpg

       图-13、「序中有乱」带来的美感

  「再如人们的手掌的造形也都极为相似,其细节纹路也各不相同,也满足上述三项特性。关于<信息的有限性>与自然造物法则,在生物学界的探讨论文已经非常多了,在此就不多叙述了。在最具爆发力的工业设计品中,你常常可以发现其杰作具有其特色:简单造形、内涵不同、无限重复。集装箱就是典型的单纯造形,它兼具了这三项特质。更重要的是,它带来无比巨大的商业潜力和商机。举凡能包容变化之体系,都有三项共同之特性:

  • 特性1:构造简单——单一元素。

  • 特性2:容易组合——简单的(如线性、树状或网状)组合规律,呈现出美好的序。

  • 特性3:包容变化——集装箱能装无限形式之物。

 

因为单一元素,简单组合,具有极大的包容力和弹性,发挥<序中有乱>的特质,带来一样的巨大潜能,蔚为风潮。」

欢迎您有空时,可阅读我所写的这本书,并多多赐教。 

         wKioL1TpujTzbuGXAAB_SsWqOQk432.jpg

在這本書裡,我詳细说明了,如何把变化封装起来,凸显简单秩序,让人们因为秩序简单而令人着迷,因为变化无穷而令人惊叹它的无限潜能。这就是船运集装箱、Docker软件集装箱等具有革命性威力的来源,就是:和谐而充满能量。

 

9.3 世界首富:比尔.盖兹(Bill Gates)也在思考集装箱

  鼎鼎大名的微软创始人比尔.盖兹,在2013年阅读了上百本书籍,他阅读之后也做了笔记。颇令人好奇的是,他第一份阅读笔记,竟然是有关于<集装箱运输>。这本书名是:"The Box:How the Shipping Container Made the World Smaller and theWorld Economy Bigger."(By Marc Levinson) 

  wKiom1TpuWGQTIJVAAFH89aa89k035.jpg

      图-14、比尔.盖兹也在思考集装箱

 如果您有兴趣,也可以观看我的线上视频课程,其中有一个视频课程(免费),名称是:“新一代架构师:像Bill Gates一样_思考集装箱”。

             wKioL1TpuoXi6GtWAADUaFf6Tfc794.jpg

    在这视频中,我详细地阐述了集装箱的架构设计思维。观看网址:

http://www.cnblogs.com/smartADT

 

10、Docker潮流下的赢家策略

10.1 从Operator视角看Docker集装箱,掌握商机

  集装箱带来的商业利益,其直接受惠是运输业者,并不是货物制造者或应用者。所以集装箱内部的包装业,如纸盒制造业、打包工人等;拖车汽车厂、拖车行、拖车司机;还有造船厂、海运公司、码头工人等都会迅速蓬勃发展起来。

 wKioL1TpurLhERMnAAFNc8_6-oc340.jpg

             图-15、从Operator视角看集装箱

同样地,Docker集装箱带来的商业利益,直接受惠是软件管理者或称维运者(operator),例如软件测试工具业者、测试人员等。至于大多数的软件开发者(developer),通常等到Docker集装箱变得普遍流行起来了,大家才会大大感受到非用它不可了。因此,不论您是身为开发者,还是维运者,都应该站在维运者的视角和立场来感受Docker集装箱潮流的力量,以便采取最佳策略,抓住这道力量带来的巨大商机。否则您将成为潮流下的后知后觉者。

 

10.2 采取<组合创新>架构设计思维

自从1980年代,面向對象(object-oriented)软件技术流行以来,架构设计有两个基本技艺:分类(classification)与组合(composition)。逐渐地衍生了以下两种不同的架构设计思维:

  • 古典抽象思维:偏于「乱中有序」,从复杂变化中分析出次序;其追求共通性。

  • 创新组合思维:偏于「序中有乱」,力求设计出次序来容纳复杂变化;其追求独特性。这种思维,最常见的比喻是“集装箱”,因为从集装箱的发展历史,很容易让我们体会出<序中有乱>如何带来巨大经济价值。

如今,在这需求碎片化时代里,Docker集装箱将成为打包微服务(micro-service)的最佳载体。于是,我们将需要有创造的架构来将云端的微服务,组合形为具有独特性的App了。于是,需要有<组合创新>的架构设计思维。就像飞机设计师一般,其把一群各自<不会飞>的模块(如轮胎、引擎、机翼、机尾、油箱等),以创新的模式将它们组合起来,竟然整体就<能飞>上天空了。

 

10.3     掌握接口(interface),拥有话语权

  集装箱就是基于「序中有乱」思维,把复杂多变(的内容)包装起来,呈现出简单易用的序。这个序呈现出来,就是集装箱的接口了。同样地,Docker集装箱也定义了一群标准的接口。

  然而,软件产业是一个强龙与地头蛇混杂的丛林世界。大哥(强龙)订定接口为标准,小弟(地头蛇)遵循标准接口。唯有掌握接口制定权才能成为强龙,获得话语权,成为最大获利者。例如,Docker就是基于标准的LXC容器(也是集装箱)而在制定自己的接口,成为产业新标准接口,而建立其强龙地位。

 同样地,在Docker集装箱的潮流下,将涌现更多的小集装箱和接口,也将涌现较大的集装箱和接口。于是强龙处处有,获利无穷时。

原文地址: http://8204129.blog.51cto.com/8194129/1614983