一篇初识什么是容器,引出 Docker
引题:
在正式引入架构演进之前,优先对其中一些比较重要的概念做前置介绍:****基础概念****应用(Application)/系统(System):为了完成一整套服务的一个程序或者一组相互配合的程序群。生活例子类比:为了完成一项任务,而搭建的由一个人或者一群相互配的人组成的团队。模块(Module)/组件(Component):当应用较复杂时,为了分离职责,将其中具有清晰职责的、内聚性强的部分,抽象出概念,便于理解。生活例子类比:军队中为了进行某据点的攻克,将人员分为突击小组、爆破小组、掩护小组、通信小组等。分布式(Distributed):系统中的多个模块被部署于不同服务器之上,即可以将该系统称为分布式系统。如 Web 服务器与数据库分别工作在不同的服务器上,或者多台 Web 服务器被分别部署在不同服务器上。生活例子类比:为了更好的满足现实需要,一个在同一个办公场地的工作小组被分散到多个城市的不同工作场地中进行远程配合工作完成目标。跨主机之间的模块之间的通信基本要借助网络支撑完成。集群(Cluster):被部署于多台服务器上的、为了实现特定目标的一个/组特定的组件,整个整体被称为集群。比如多个 MySQL 工作在不同服务器上,共同提供数据库服务目标,可以被称为一组数据库集群。生活例子类比:为了解决军队攻克防守坚固的大城市的作战目标,指挥部将大批炮兵部队集中起来形成一个炮兵打击集群。分布式 VS 集群:分布式强调的是物理形态,即工作在不同服务器上并且通过网络通信配合完成任务;而集群更在意逻辑形态,即是否为了完成特定服务目标。主(Master)/从(Slave):集群中,通常有一个程序需要承担更多的职责,被称为主;其他承担附属职责的被称为从。比如 MySQL 集群中,只有其中一台服务器上数据库允许进行数据的写入(增/删/改),其他数据库的数据修改全部要从这台数据库同步而来,则把那台数据库称为主库,其他数据库称为从库。中间件(Middleware):一类提供不同应用程序用于相互通信的软件,即处于不同技术、工具和数据库之间的桥梁。生活例子类比:一家饭店开始时,会每天去市场挑选买菜,但随着饭店业务量变大,成立一个采购部,由采购部专职于采买业务,称为厨房和菜市场之间的桥梁。容器(Docker):Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 操作系统的机器上,也可以实现虚拟化。可以理解为一个集装箱,集装箱里面是每个用户的货物,整体打包。容器编排(K8S):kubernetes,简称 K8s,是用 8 代替名字中间的 8 个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效。可以理解为一个货船,安装集装箱的大小,货物情况合理的来组织集装箱完成整体货物的搬运。****评价指标****可用性(Availability):考察单位时间段内,系统可以正常提供服务的概率/期望。例如: 年化系统可用性= 系统正常提供服务时长 / 一年总时长。这里暗含着一个指标,即如何评价系统提供无法是否正常,我们就不深入了。平时我们常说的 4 个 9 即系统可以提供 99.99% 的可用性,5 个 9 是 99.999% 的可用性,以此类推。我们平时只是用高可用(HighAvailability HA)这个非量化目标简要表达我们系统的追求。响应时长(Response Time RT):指用户完成输入到系统给出用户反应的时长。例如点外卖业务的响应时长 = 拿到外卖的时刻 - 完成点单的时刻。通常我们需要衡量的是最长响应时长、平均响应时长和中位数响应时长。这个指标原则上是越小越好,但很多情况下由于实现的限制,需要根据实际情况具体判断。吞吐(Throughput) VS 并发(Concurrent):吞吐考察单位时间段内,系统可以成功处理的请求的数量。并发指系统同一时刻支持的请求最高量。例如一条 2 车道高速公路,一分钟可以通过 20 辆车,则并发是 2,一分钟的吞吐量是 20。实践中,并发量往往无法直接获取,很多时候都是用极短的时间段(比如 1 秒)的吞吐量做代替。我们平时用高并发(Hight Concurrnet)这个非量化目标简要表达系统的追求。
一、容器架构说明
1.1 单机架构
****简介****
单机架构:将应用程序、数据库、文件系统等所有服务和资源全部部署在同一台物理服务器上。
****出现原因****
出现在互联网早期,访问数据量比较小,一个单片机就足以满足需求。
****架构工作原理****
以电子商城为例,可以看到通过应用(划分了多个模块)和数据库在单个服务器上协作完成业务运行:

运行模式:

****技术案例****
我们打开一个浏览器,访问这个网址,通过DNS获取这个网址的IP地址,因为我们上述蓝色的部分【用户、商品、交易等】都是我们写的代码功能,对外提供服务。所以也就是说,我们写的功能代码最终以 tomcat 组件的形式对外提供一个服务。即应用服务就是我们服务器的一个组件。故我们拿到了相应的IP地址并访问了指定的组件应用服务,之后到我们的数据库服务【MySQL等其他数据库】进行增删改查操作。操作完毕后将结果返回给用户。

****架构优点****
成本低、部署简单
****架构缺点****
存在严重的性能瓶颈【原因:用户的请求量变大】
数据库和应用相互竞争资源,响应速度变慢【原因:假设服务器有8G内存,应用需要8G,数据库也需要8G内存】
1.2 应用数据分离架构
****简介****
应用数据分离架构:应用服务和数据库服务使用不同服务器。
****出现原因****
单机存在严重的资源竞争,导致站点变慢。
****架构工作原理****
以电子商城为例,可以看到应用(划分了多个模块)和数据库在各自的服务器上通过网络协作完
成业务运行。

运行模式:

****技术案例****
我们打开一个浏览器,访问这个网址,通过DNS获取这个网址的应用服务器的IP地址,抵达应用服务器后访问指定的应用服务,之后通过网络访问该功能的存储服务器的数据库,查到之后将数据返回给我们的应用。返回给用户。

****架构优点****
成本相对可控、
性能相比单机有提升、
数据库单独隔离,不会因为应用把数据库搞坏,有一定的容灾能力。
****架构缺点****
硬件成本变高、【原因:多购买了一台服务器】
性能有瓶颈,无法应对海量并发。【原因:当访问量来到1w, 2w的时候又扛不住了】
1.3 应用服务集群架构
****简介****
应用服务集群架构:引入了负载均衡,应用以集群方式运作。
****出现原因****
单个应用不足以支持海量的并发请求,高并发的时候站点响应变慢。
****架构工作原理****
以电子商城为例,可以看到应用不再是一个,而是变成了多个,通过负载均衡来支持海量的并发。


运行模式:

****技术案例****
我们打开一个浏览器,访问这个网址,通过DNS获取这个网址的应用服务器的IP地址(负载均衡服务器的任意一个IP地址),之后流程和上述一样。
因为一个 Tomcat 应用服务最大可抗住1w个并发,假设来了很多很多的并发(>1w),引入负载均衡层【Nginx 、LVS/F5、等等】。一个Nginx负载均衡组件可以抗住5w级别的并发。若来了10w的并发则横向添加一个Nginx服务器,一次类推。但又假设来了50w的并发Nginx也扛不住了,则再引入一个负载均衡层LVS或者F5,LVS可以抗住几十万的一个并发,F5可以抗住几百万达至千万的一个并发。再次来个极端,来了上亿级别的并发,解决上一层"DNS",也就是说每当来了请求,返回的IP是依次访问不同的LVS/F5服务器。

****架构优点****
应用服务高可用:应用满足高可用,不会一个服务出问题整个站点挂掉。
应用服务具备一定高性能:如果不访问数据库,应用相关处理通过扩展可以支持海量请求快速响应
应用服务有一定扩展能力:支持横向扩展。
****架构缺点****
数据库成为性能瓶颈,无法应对数据库的海量查询、
数据库是单点,没有高可用、
运维工作增多,扩展后部署运维工作增多,需要开发对应的工具应对快速部署、
硬件成本较高。
1.4 读写分离/主从分离架构
****简介****
读写分离/主从分离架构:将数据库读写操作分散到不同的节点上,数据库服务器搭建主从集群,一主一从、一主多从都可以,数据库主机负责写操作,从机只负责读操作。
****出现原因****
数据库成为瓶颈,而互联网应用一般读多写少,数据库承载压力大,主要是由这些读的请求造成
的,那么我们可以把读操作和写操作分开。
****架构工作原理****
以电子商城为例,可以看到数据库服务器不再是一个,而是变成了多个,数据库主机负责写操作,从机负责读操作,数据库主机通过复制将数据同步到从机。

运行模式:


****技术案例****
mycat, tddl组件(中间件层/中间层):当我们的读/写的流量来了,先到mycat, tddl 组件,该组件会检测这个流量到底是读还是写,当检测到是写的流量就访问Mysql主数据库服务器,写完之后就将写入后的数据同步给其他的写数据库服务器(从)。当检测到是读的流量就直接访问Mysql从数据库服务器。

****架构优点****
数据库的读取性能提升、
读取被其他服务器分担,写的性能间接提升、
数据库有从库,数据库的可用性提高了。
****架构缺点****
热点数据的频繁读取导致数据库负载很高、
当同步挂掉,或者同步延迟比较大时,写库和读库的数据不一致、
服务器成本需要进一步增加。
1.5 冷热分离架构
****简介****
冷热分离架构:引入缓存,实行冷热分离,将热点数据放到缓存中快速响应。【将系统中的数据根据访问频率划分为“热数据”和“冷数据”。】
****出现原因****
海量的请求导致数据库负载过高,站点响应再度变慢。
****架构工作原理****
以电子商城为例,可以看到多了缓存服务器,对于热点数据全部放到缓存中,不常用数据再去查
询我们的数据库。

运行模式:


****技术案例****
热数据(Hot Data):被频繁访问的数据;冷数据(Cold Data):不常被访问的数据。将热数据加载到性能极高的内存缓存中(如Redis、Memcached),让绝大多数对热数据的访问请求直接由缓存来响应,从而避免穿透到后端的数据库。


****架构优点****
大幅降低对数据库的访问请求,性能提升非常明显。
****架构缺点****
带来了缓存一致性,缓存击穿,缓存失效,缓存雪崩等问题、
服务器成本需要进一步增加、
业务体量支持变大后,数据不断增加,数据库单库太大,单个表体量也太大,数据查询会很慢,导致数据库再度成为系统瓶颈。
1.6 垂直分库架构
****简介****
垂直分库架构:数据库的数据被拆分,数据库数据分布式存储,分布式处理,分布式查询,也可以理解为分布式数据库架构。【即根据业务维度来对数据库进行拆分。将原本耦合在一起的不同业务的数据,分散到不同的数据库中。】
****出现原因****
单机的写库会逐渐会达到性能瓶颈,需要拆分数据库,数据表的数据量太大,处理压力太大,需要进行分表,为降低运维难度,业界逐渐研发了分布式数据库,库表天然支持分布式。
****架构工作原理****
以电子商城为例,数据库是由多个主从库或者存储集群构成,支持分布式大规模并行处理。



运行模式:


****技术案例****
案例:



****架构优点****
数据库吞吐量大幅提升,不再是瓶颈
****架构缺点****
跨库join、分布式事务等问题,这些需要对应的去进行解决,目前的mpp都有对应的解决方案。
数据库和缓存结合目前能够抗住海量的请求,但是应用的代码整体耦合在一起,修改一行代码需
要整体重新发布。
1.7 微服务架构
****简介****
微服务架构:微服务是一种架构风格,按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。
****出现原因****
扩展性差:应用程序无法轻松扩展,因为每次需要更新应用程序时,都必须重新构建整个系统。
持续开发困难:一个很小的代码改动,也需要重新部署整个应用,无法频繁并轻松的发布版本。
不可靠:即使系统的一个功能不起作用,可能导致整个系统无法工作。
不灵活:无法使用不同的技术构建单体应用程序。
代码维护难:所有功能耦合在一起,新人不知道何从下手。
****架构工作原理****
以电子商城为例,一个商城应用拆分成了多个微服务,如用户服务、交易服务和商品服务,相
互之间协作支持整个商城的应用。


运行模式:

****技术案例****
微服务架构不是一个单一的技术,而是一个完整的生态系统。将一个大型的、复杂的单体应用,按照业务边界(Business Capability)拆分成一组小而专注、可以独立开发、独立部署、独立扩展的自治服务。每个服务都围绕着特定的业务功能构建,并通过轻量级的通信机制相互协作,共同构成一个完整的应用系统。

****架构优点****
灵活性高:服务独立测试、部署、升级、发布
独立扩展:每个服务可以各自进行扩展
提高容错性:一个服务问题并不会让整个系统瘫痪
新技术的应用容易:支持多种编程语言
****架构缺点****
资源使用变多:所有这些独立运行的微服务都需要需要占用内存和CPU。
处理故障困难:一个请求跨多个服务调用,需要查看不同服务的日志完成问题定位。
运维复杂度高:业务不断发展,应用和服务都会不断变多,应用和服务的部署变得复杂,同一台服务器上部署多个服务还要解决运行环境冲突的问题,此外,对于如大促这类需要动态扩缩容的场景,需要水平扩展服务的性能,就需要在新增的服务上准备运行环境,部署服务等,运维将变得十
处理故障困难。
1.8 容器编排架构
****简介****
容器编排架构:借助容器化技术(如docker)将应用/服务可以打包为镜像,通过容器编排工具(如k8s)来动态分发和部署镜像,服务以容器化方式运行。【容器编排架构是一种利用容器技术来自动化部署、扩展和管理应用服务的架构模式。它将每一个微服务及其所有依赖(代码、运行时、系统库、配置文件)打包成一个标准化的、轻量级的、可移植的“容器镜像”。然后,通过一个“容器编排平台”(如Kubernetes, K8s)来对这些容器进行生命周期管理。】
****出现原因****
微服务拆分细,服务多部署工作量大,而且配置复杂,容易出错微服务数量多扩缩容麻烦,而且容易出错,每次缩容后再扩容又需要重新配置服务对应的环境参数信息微服务之间运行环境可能冲突,需要更多的资源来进行部署或者通过修改配置来解决冲突
****架构工作原理****
以电子商城为例,一个商城应用拆分成了多个微服务,如用户服务、交易服务和商品服务,每一
个微服务打包到容器之中,相互协作来完成系统功能,通过容器编排工具完成部署运维。

即:将应用和其环境打包在一起,形成一个隔离的、自给自足的单元。


运行模式:

****技术案例****


****架构优点****
部署、运维简单快速:一条命令就可以完成几百个服务的部署或者扩缩容。
隔离性好:容器与容器之间文件系统、网络等互相隔离,不会产生环境冲突。
轻松支持滚动更新:版本间切换都可以通过一个命令完成升级或者回滚。
****架构缺点****
技术栈变多,对研发团队要求高。
机器还是需要公司自身来管理,在非大促的时候,还是需要闲置着大量的机器资源来应对大促,机器自身成本和运维成本都极高,资源利用率低,可以通过购买云厂商服务器解决。
题外话:互联网应用的实战架构:

二、容器技术发展史
1979年贝尔实验室发明chroot
chroot系统调用是在1979年开发第7版Unix期间引I入的。贝尔实验室在UnixV7的
开发过程中,发现当一个系统软件编译和安装完成后,整个测试环境的变量就会发生
改变,下一次测试需要重新配置环境信息。
设计者们思考能否隔离出来一个独立的环境,来构建和搭建测试环境,所以发明了
chroot,可以把一个进程的文件系统隔离起来。
chroot系统调用可以将进程及其子进程的根目录更改为文件系统中的新位置。隔离以
后,该进程无法访问到外面的文件,因此这个被隔离出来的新环境像监狱一样,被命
名为ChrootJail(监狱)。后续测试只需要把测试信息放到Jail中就可以完成测试了。
这一进步是进程隔离的开始:为每个进程隔离文件访问。所以chroot可以认为是容器
技术的鼻祖。
2000年FreeBSD4.0发行FreeBSDJail
2000年,当时一家小型共享环境托管提供商提出了FreeBSDJail,以实现其服务与其
客户服务之间的明确分离,以实现安全性和易于管理。每个Jail都是一个在主机上运
行的虚拟环境,有自己的文件进程、用户和超级用户帐户,能够为每个系统分配一个
IP地址。
FreeBSDJail不仅仅有chroot的文件系统隔离,并且扩充了独立的进程和网络空间。
2001年LinuxVServer 发行
与FreeBSDJails一样,LinuxVServer是一种监狱机制,可以对计算机系统上的资源
(文件系统、网络地址、内存)进行分区。
2004年SolarisContainers发行
2004年,SolarisContainers的第一个公开测试版发布,结合系统资源控制和区域进
行隔离,并添加了快照和克隆能力。
这个时期的进程隔离技术大多以Jail模式为核心,基本实现了进程相关资源的隔离操
作,没有更大的应用场景发展有限。
2006年,Go0gle101计划提出云的概念,对当前的主流开发模式产生深远的影响。
也许以后我们会更多考虑如果出现比现在多1000倍,10000倍的数据量的时候,我们
该如何处理?要想让”云”发挥潜能,与此相关的编程和操作就应该与使用互联网一样简
单。随后,亚马逊、IBM等行业巨头也陆续宣布各自的“云”计划,宣告“云”技术时代的
来临。
云计算需要处理海量数据、超高并发、快速扩展等问题,此时不仅仅需要隔离还需要
能够对资源进行控制和调配。
2006年google 推出Process Containers
Process Containers(由Google于20o6年推出)旨在限制、统计和隔离一组进程的
资源使用(CPU、内存、磁盘I/O、网络)。一年后它更名为“Control Groups
(cgroups)”,并最终合并到 Linux内核2.6.24。
2008年LXC推出
LXC(Linux容器)是Linux容器管理器的第一个、最完整的实现。它是在2008年使
用cgroups和Linux命名空间实现的,它可以在单个Linux内核上运行,不需要任何
补丁。
同年谷歌推出GAE(GoogleAppEngine)首次把开发平台当做一种服务来提供,采
用云计算技术,跨越多个服务器和数据中心来虚拟化应用程序。
同时Google在GAE中使用了Borg(Kubernetes的前身)来对容器进行编排和调度。
LXC和Borg其实就相当于最早的docker 和 k8s.
2011年CloudFoundry推出Warden
2011年启动了Warden,/早期使用LXC,后来替换为自己的实现,直接对Cgroups以
及LinuxNamespace操作。开发了一个客户端-服务器模型来管理跨多个主机的容器
集合,并且可以管理cgroups、命名空间和进程生命周期。
2013年LMCTFY启动
Let Me Contain That For You(LMCTFY)于2013 年作为Google容器堆栈的开源版本
启动,提供Linux应用程序容器。应用程序可以“容器感知”,创建和管理它们自己的子
容器。在谷歌开始和docker合作,后续转向了docker公司的libcontainer,LMCTFY
的于2015年停止。
2013年Docker推出到风靡全球
Docker最初是一个叫做dotCloud的PaaS服务公司的内部项目,后来该公司改名为
Docker。Docker在初期与Warden类似,使用的也是LXC,之后才开始采用自己开发
的libcontainer来替代LXC,它是将应用程序及其依赖打包到几乎可以在任何服务器
上运行的容器的工具。与其他只做容器的项目不同的是,Docker引入了一整套管理容
器的生态系统,这包括高效、分层的容器镜像模型、全局和本地的容器注册库、清晰
的RESTAPI、命令行等等。
Docker为提供了一整套的解决方案,不仅解决了容器化问题,而且解决了分发问题,
很快被各大厂商选择变成了云基础设施,厂商围绕Docker也开始了生态建设。
Google &Docker竞争
2013年CoreOS发布和 Docker由合作终止
技术革命带来新的市场机遇,CoreOS也是其中的一员,在容器生态圈中贴有标签:
专为容器设计的操作系统CoreOS。作为互补,CoreOS+Docker曾经也是容器部署的
灵魂伴侣。CoreOS为Docker的推广和源码社区都做出了巨大的贡献。
Docker生态扩张,与最开始是“一个简单的基础单元”不同,Docker也在通过开发或收
购逐步完善容器云平台的各种组件,准备打造自己的生态圈,而这与CoreOS的布局
有直接竞争关系。
2014年6月Google发布开源的容器编排引擎Kubernetes(K8S)
容器只是解决了容器化,分发问题,但是一个软件的网络问题、负载均衡问题、监控、
部署、更新、镜像管理、发布等很多问题并没有有效的解决。
Google内部调度系统Borg已经拥有10多年的使用容器经验,在2014年6月推出了
开源的K8S,可以支持对容器的编排和管理,完成生态的闭环。
同年7月,微软、Red Hat、IBM、Docker、CoreOS、Mesosphere和 Saltstack等
公司,相继加入K8S。之后的一年内,VMware、HP、Intel等公司,也陆续加入。
2014年12月CoreOS发布开源容器引擎Rocket(rkt)
2014年底,CoreOS正式发布了CoreOS的开源容器引擎Rocket(简称rkt),和
Docker正式分开发展。Google于2015年4月领投CoreOS1200万美元,而
CoreOS也发布了Tectonic,成为首个支持企业版本kubernetes的公司。从此,容器
江湖分为两大阵营,Google派系和Docker派系。
2015年Docker推出容器集群编排组件Swarm
在Docker 1.12及更高版本中,Swarm模式与Docker引l擎集成,为Docker容器提供
原生集群管理功能。
两大派系的竞争愈演愈烈,行业标准的诉求越来越强烈。
2015年6月Docker成立OCI
Docker公司在容器运行因为高速迭代导致变更频繁,影响较大。
2015年6月22日,由Docker公司牵头,CoreOS、Google、RedHat等公司共同宣
布,Docker公司将Libcontainer捐出,并改名为RunC项目,交由一个完全中立的基
金会管理,然后以RunC为依据,大家共同制定一套容器和镜像的标准和规范。
RUNC的本质就是可以不通过DockerDamon直接运行容器。
规范就是OCI,旨在“制定并维护容器镜像格式和容器运行时的正式规范(OCI
Specifications)”。其核心产出是OCI Runtime Spec(容器运行时规范)、OCI Image
Spec(镜像格式规范)、OCIDistribution Spec(镜像分发规范)。所以OCI组织解决
的是容器的构建、分发和运行问题。
社区们期望通过标准来约束Docker公司的话语权,不过Docker公司并没有积极推动
OCI的发展,而且OCl也无法影响Docker的地位,因为Docker已经是事实的容器标
准。
Google和RedHat等公司将方向调转到容器上面的平台层。
2015年7月Google带头成立CNCF
Google联合Linux基金会成立CNCF(Cloud Native ComputingFoundation)云原
生计算基金会。旨在构建云原生基础设施。K8S是第一个纳入进来的项目,像后续有
名的监控设施Prometheus,配置设施ETCD都加入进来。CNCF组织解决的是应用
管理及容器编排问题。和OCI共同制定了一系列行业事实标准。
k8s成为云原生事实标准
2016年发布CRI标准
Google就和红帽主导了CRI标准,用于k8s和特定的容器运行时解耦。
CRI(Container RuntimeInterface容器运行时接口)本质上就是k8s定义的一组与容器
运行时进行交互的接口,所以只要实现了这套接口的容器运行时都可以对接k8s。
但是这个适合Docker还是事实标准,并CRI并没有话语权,但是又必须支持Docker,
所以就有了dockershim,dockershim的本质其实就是k8s对接docker的一个CRI的实
现。
2016年Docker捐献containerd
containerd作为运行时标准,Docker 从DockerEngine种剥离出来,捐献给CNCF.这
个时候Google为了将containerd加入到cri标准中,又开发了cri-containerd,用来完
成k8s和容器之间的交互。
2016年CRI-O 发布
CRI-O可以让开发者直接从Kubernetes来运行容器,这意味着Kubernetes可以不依
赖于传统的容器引擎(比如Docker),也能够管理容器化工作负载。容器此时也回归
到自己的位置,如何更好的封装云原生的程序。
在2016年,Docker公司宣布了一个震惊全部人的计划:放弃现有的Swarm项目,将
容器编排和集群管理功能所有内置到Docker项目中。
而Kubernetes的应对策略则是反其道而行之,开始在整个社区推动“民主化”架构,从
API到容器运行时的每一层,Kubernetes项目都为开发者暴露出了能够扩展的插件机
制,鼓励用户经过代码的方式介入到Kubernetes项目的每个阶段。
在进入2017年之后,更多的厂商愿意把宝压在K8S上,投入到K8S相关生态的建设
中来。这两年包括阿里云、腾讯、百度等中国科技企业也陆续加入CNCF,全面拥抱
容器技术与云原生。
Swarm的失败后,社区版Docker项目改名为moby,将Docker引流到Docker的企业
版上去,螳臂挡车。
2017年containerd确定作为标准CRI
2017年各大厂商都开始拥抱Kubernetes,亚马逊AWS,Microsoft Azure,VMware,
有的甚至抛弃了自家的产品。
亚马逊网络服务(AWS)于八月份以白金会员(最高级别)加入了CNCF。
VMware都作为CNCF的白金会员注册
Docker Inc.ocker 企业版框架中添加了本地Kubernetes支持。Docker自己的Swarm
技术也借鉴了k8s的技术进一步发展。
Kubernetes已成了容器编排领域的绝对标准,Docker已成容器事实的标准。
核心问题:容器哪些技术过时了
DockerClient
此时K8s只是编排领域的一个选择,而Docker此时一家独大,所以K8s的客户端只
是作为Docker的客户端来调用Docker引擎来完成服务。
RUNC&Shim
OCI催生runc,剥离Docker Engine的一家独大的情况,确保各个厂商都可以搭建自
己的容器平台。CRI标准确立了但是Docker并没有接入该标准。此时催生了临时技术
shim.
CRI-Containerd
containerd被捐献出来,谷歌开发cri-containerd接入CRI标准。
CRI-O
k8s已经成为事实的编排标准,促使容器回归云原生本质。
Containerd
containerd实现CRI,成为CRI的事实标准
实际生产的集群采用的什么运行时组件?
以腾讯的TKE(腾讯商用K8S产品)为例,支持选择containerd和docker两种模式的
选择。
如何选择呢?
(1)Containerd调用链更短,组件更少,更稳定,占用节点资源更少。建议选择
Containerd。
(2)以下情况还是要用docker
使用docker build/push/save/load等命令。
调用 docker API
需要docker compose 或 docker swarm。
三、Docker 的简单介绍
3.1 什么是虚拟化和容器化
物理机:实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理
机提供给虚拟机以硬件环境,有时也称为“寄主”或“宿主”。
虚拟化:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上
同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都
可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
容器化:容器化是一种虚拟化技术,又称操作系统层虚拟化(Operating system level
virtualization),这种技术将操作系统内核虚拟化,可以允许用户空间软件实例
(instances)被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运
行。这个软件实例,也被称为是一个容器(containers)。对每个实例的拥有者与用户
来说,他们使用的服务器程序,看起来就像是自己专用的。容器技术是虚拟化的一种。
docker是现今容器技术的事实标准。
****生活例子****
3.2 为什么要虚拟化和容器化
虚拟化的核心目标是资源隔离与复用。


3.3 虚拟化的实现方式
****应用程序执行环境分层****

硬件层:提供硬件抽象,包括指令集架构、硬件设备及硬件访问接口
操作系统层:提供系统调用接口管理硬件资源
程序库层:提供数据结构定义及函数调用接口
****虚拟化常见类别****
**虚拟机**
存在于硬件层和操作系统层间的虚拟化技术。虚拟机通过“伪造”一个硬件抽象接口,将一个操作系统以及操作系统层以上的层嫁接到硬件上,实现和真实物理机几乎一样的功能。比如我们在一台 Windows 系统的电脑上使用 Android 虚拟机,就能够用这台电脑打开 Android 系统上的应用。
**容器**
存在于操作系统层和函数库层之间的虚拟化技术。容器通过“伪造”操作系统的接口,
将函数库层以上的功能置于操作系统上。以 Docker 为例,其就是一个基于 Linux 操作系统的 Namespace 和 Cgroup 功能实现的隔离容器,可以模拟操作系统的功能。简单来说,如果虚拟机是把整个操作系统封装隔离,从而实现跨平台应用的话,那么容器则是把一个个应用单独封装隔离,从而实现跨平台应用。所以容器体积比虚拟机小很多,理论上占用资源更少。容器化就是应用程序级别的虚拟化技术。容器提供了将应用程序的代码、运行时、系统工具、系统库和配置打包到一个实例中的标准方法。容器共享一个内核(操作系统),它安装在硬件上。
**JVM之类的虚拟机**
存在于函数库层和应用程序之间的虚拟化技术。Java 虚拟机同样具有跨平台特性,所谓跨平台特性实际上也就是虚拟化的功劳。我们知道 Java 语言是调用操作系统函数库的,JVM 就是在应用层与函数库层之间建立一个抽象层,对下通过不同的版本适应不同的操作系统函数库,对上提供统一的运行环境交给程序和开发者,使开发者能够调用不同操作系统的函数库。
****常见虚拟化实现****
**主机虚拟化(虚拟机)实现**
主机虚拟化的原理是通过在物理服务器上安装一个虚拟化层来实现。这个虚拟化层可以在物理服务器和客户操作系统之间建立虚拟机,使得它们可以独立运行。从软件框架的角度上,根据虚拟化层是直接位于硬件之上还是在一个宿主操作系统之上,将虚拟化划分为 Type1 和 Type2.Type1 类的 Hypervisor(Hypervisor 是一种系统软件,它充当计算机硬件和虚拟机之间的中介,负责有效地分配和利用由各个虚拟机使用的硬件资源,这些虚拟机在物理主机上单独工作,因此,Hypervisor 也称为虚拟机管理器。)直接运行在硬件之上,没有宿主机操作系统,Hypervisor 直接控制硬件资源和客户机。典型框架为 Xen、VmwareESX。
Type2 类的 Hypervisor 运行在一个宿主机操作系统之上(Vmware Workstation)或者系统里面,Hypervisor 作为宿主机操作系统中的一个应用程序,客户机就是在宿主机操作系统上的一个进程
**容器虚拟化实现**
*容器虚拟化实现原理*
容器虚拟化,有别于主机虚拟化,是操作系统层的虚拟化。通过 namespace 进行各程序的隔离,加上 cgroups 进行资源的控制,以此来进行虚拟化。
【即:隔离(namespace) + 控制(cgroups)】
四、基于容器虚拟化的两个工具
4.1 工具1—namespace
****什么是 Namespace(命名空间)****
namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中。
Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前namespace 里的进程,对其他 namespace 中的进程没有影响。
Linux 提供了多个 API 用来操作 namespace,它们是 clone()、setns() 和 unshare() 函数,为了确定隔离的到底是哪项 namespace,在使用这些 API 时,通常需要指定一些调用参数:CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS 和 CLONE_NEWCGROUP。如果要同时隔离多个 namespace,可以使用 | (按位或)组合这些参数。
具体版本信息

- UTS:每个容器能看到自己的 hostname,拥有独立的主机名和域名。
- IPC:同一个 IPC namespace 的进程之间能互相通讯,不同的 IPC namespace 之间不能通信。
- PID:每个 PID namespace 中的进程可以有其独立的 PID,每个容器可以有其 PID 为 1 的 root 进程。
- Network:每个容器用有其独立的网络设备,IP 地址,IP 路由表,/proc/net 目录,端口号。
- Mount:每个容器能看到不同的文件系统层次结构。
- User:每个 container 可以有不同的 user 和 group id。
4.2 工具2—cgroup
****什么是 cgroups****
cgroups(Control Groups) 是 linux 内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。简单说,cgroups 可以限制、记录任务组所使用的物理资源。本质上来说,cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。
****为什么使用 cgroups****
其可以做到对cpu,内存等资源实现精细化的控制,目前越来越火的轻量级容器Docker 及 k8s 中的 pod 就使用了cgroups 提供的资源限制能力来完成cpu,内存等部分的资源控制。
比如在一个既部署了前端web服务,也部署了后端计算模块的八核服务器上,可以使用cgroups限制web server仅可以使用其中的六个核,把剩下的两个核留给后端计算模块。
****cgroups 的用途****
Resource limitation: 限制资源使用,例:内存使用上限/cpu 的使用限制Prioritization: 优先级控制,例:CPU 利用/磁盘 IO 吞吐Accounting: 一些审计或一些统计Control: 挂起进程/恢复执行进程
****cgroups 可以控制的子系统****
| blkio | 对块设备的 IO 进行限制。 |
| cpu | 限制 CPU 时间片的分配 |
| cpuacct | 生成 cgroup 中的任务占用 CPU 资源的报告,与 cpu 挂载在同一目录。 |
| cpuset | 给 cgroup 中的任务分配独立的 CPU(多处理器系统) 和内存节点。 |
| devices | 限制设备文件的创建,和对设备文件的读写 |
| freezer | 暂停/恢复 cgroup 中的任务。 |
| memory | 对 cgroup 中的任务的可用内存进行限制,并自动生成资源占用报告。 |
| perf_event | 允许 perf 观测 cgroup 中的 task |
| net_cls | cgroup 中的任务创建的数据报文的类别标识符,这让 Linux 流量控制器(tc 指令)可以识别来自特定 cgroup 任务的数据包,并进行网络限制。 |
| hugetlb | 限制使用的内存页数量。 |
| pids | 限制任务的数量。 |
| rdma | 限制 RDMA 资源(Remote Direct Memory Access,远程直接数据存取) |
五、LXC是什么
****LXC 是什么****
LXC(LinuX Containers)Linux 容器,一种操作系统层虚拟化技术,为 Linux 内核容器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。透过统一的名字空间和共享 API 来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得 Linux 用户可以容易的创建和管理系统或应用容器。LXC 是最早一批真正把完整的容器技术用一组简易使用的工具和模板来极大的简化了容器技术使用的一个方案LXC 虽然极大的简化了容器技术的使用,但比起直接通过内核调用来使用容器技术,其复杂程度其实并没有多大降低,因为我们必须要学会 LXC 的一组命令工具,且由于内核的创建都是通过命令来实现的,通过批量命令实现数据迁移并不容易。其隔离性也没有虚拟机那么强大。后来就出现了 docker,所以从一定程度上来说,docker 就是 LXC 的增强版。

六、重新再来看 Docker
****Docker 本质****
Docker 本质其实是 LXC 之类的增强版,它本身不是容器,而是容器的易用工具。容器是 linux 内核中的技术,Docker 只是把这种技术在使用上简易普及了。Docker 在早期的版本其核心就是 LXC 的二次封装发行版。
Docker 作为容器技术的一个实现,或者说让容器技术普及开来的最成功的实现。Docker 是基于 Go 语言实现的一个开源项目,它的主要目标是“Build,Ship andRun Any APP,Anywhere”,即通过对组件的封装、分发、部署、运行等生命周期的管理,使得用户的应用及其运行环境能够做到“一次封装,到处运行”。
早期 Docker 利用 LXC 做容器管理引擎,但是在创建容器时,不再使用模板去安装生成,而是通过镜像技术(把一个操作系统用户空间所需要使用到的组件事先编排好,并整体打包成一个文件,image 文件),镜像文件集中放在一个仓库中。当需要创建容器时,Docker 调用 LXC 的工具 lxc-create,但不再通过 lxc 的模板去安装,而是连接到镜像服务器上下载匹配的镜像文件,而后基于镜像启动容器。所以,Docker 极大的简化了容器的使用难度。以后我们创建启动容器,只需要一个命令,docker-run,docker-stop 就可以启动停止一个容器了。
****Docker 的引擎迭代****
Docker 早期是基于 LXC 容器管理引擎实现,当后来成熟之后,Docker 自建了一个容器引擎叫 libcontainer,后来 CNCF 的介入,Docker 又研发了一个工业化标准的容器引擎 runC,目前所使用的新版 Docker,所使用的容器引擎就是 RunC。
****Docker 和虚拟机的区别****

****Docker 为什么比虚拟机资源利用率高,启动快****

docker 有比虚拟机更少的抽象层。docker 不需要 Hypervisor 实现硬件资源虚拟化,运行在 docker 容器上的程序直接使用的是实际物理机的硬件资源。因此在 cpu、内存利用率上 docker 将会在效率上有明显的优势。docker 利用的是宿主机的内核,而不需要Guest OS,节省了 Guest OS 占用的资源。docker 不需要 Guest OS,创建一个容器时,不需要和虚拟机一样重新加载一个操作系统内核。从而避免引寻、加载操作系统内核返回时耗时耗资源的过程,当新建一个虚拟机时,虚拟机软件需要加载 Guest OS,返回新建过程是分钟级别的。而新建一个docker 容器只需要几秒钟。
****Docker 和 JVM 虚拟化的区别?****






