在开始谈docker容器之前,先需要清楚什么是虚拟化,什么是容器
虚拟化
如果要⽤简单的语句来阐述虚拟化技术的话,那么可以这么解释: 虚拟化技术是⼀种将计算机物理资源进⾏抽象、转换为虚拟的计算机资源提供给程序使⽤的技术。 这⾥所指的计算机资源,就包括了 CPU 提供的运算控制资源,硬盘提供的数据存储资源,⽹卡提供的⽹络传输资源等。

为跨平台而生
计算机发展早期,各类计算机平台,计算资源所提供的接口都不一样,调用十分混乱,没有像今天一样有相对统一的标准。由于为兼容不同的平台写各种各样的兼容代码,于是虚拟技术运应而生。虚拟化技术通过本身适配不同平台的硬件,抽象成统一的接口,从而实现程序的跨平台。
将虚拟化技术用于资源管理
在虚拟化技术发展的过程中,人们又发现了虚拟化技术的另外一个用途:资源管理。 因为虚拟化技术本来就是对计算机物理资源的抽象转换成虚拟的计算机资源,这样就很容易在这里对计算机资源进行修改,比如可以告诉程序这台计算机只有4G内存,而无论计算机是有16G还是32G,程序都会按照虚拟机告诉它的4G内存来进行使用。 通过虚拟化技术管理计算机资源的方式,不当能让我们对计算机资源的控制更加灵活,而且还能极大的提交计算机资源的使用率。 看到这可能会有些迷惑,虚拟化技术本身就要耗费部分的计算机资源,怎么还能产生1+1>2的效果? 其实这里指的是计算机的使用率,而非计算机的占用率,这两者看似很相近,其实并非一个概念。虚拟化技术能够提高计算机资源的使用率,是指利用虚拟化技术,将原本程序使用不到的资源分配给其他程序使用,从而提升计算机资源的整体利用率。 例如,这⾥我们有⼀台运⾏ Nginx 的机器,由于 Nginx 运⾏对系统资源的消耗并不⾼,这就让系统⼏乎 95% 以上的资源处于闲置状态。这时候我们通过虚拟化技术,把其他的⼀些程序放到这台机器上来 运⾏,它们就能够充分利⽤闲置的资源。这带来的好处就是我们不需要再为这些程序单独部署机器,从⽽节约不少的成本。

虚拟化的分类
- 硬件虚拟化
- 软件虚拟化
所谓硬件虚拟化,指的是物理硬件本⾝就提供虚拟化的⽀持。举个例⼦来说,某个平台的 CPU,能够将另外⼀个平台的指令集转换为⾃⾝的指令集执⾏,并给程序完全运⾏在那个平台上的感觉。又或者 说,CPU 能够⾃⾝模拟裂变,让程序或者操作系统认为存在多个 CPU,进⽽能够同时运⾏多个程序或者操作系统。这些都是硬件虚拟化的体现。 ⽽软件虚拟化则指的是通过软件的⽅式来实现虚拟化中关键的指令转换部分。依然⽤ CPU 的例⼦来说话,在软件虚拟化实现中,通过⼀层夹杂在应⽤程序和硬件平台上的虚拟化实现软件来进⾏指令的转换。也就是说,虽然应⽤程序向操作系统或者物理硬件发出的指令不是当前硬件平台所⽀持的指令,这个实现虚拟化的软件也会将之转换为当前硬件平台所能识别的
在实际场景中,虚拟化还能进⾏更加细化的分类,例如:
- 平台虚拟化:在操作系统和硬件平台间搭建虚拟化设施,使得整个操作系统都运⾏在虚拟后的环境中。
- 应⽤程序虚拟化:在操作系统和应⽤程序间实现虚拟化,只让应⽤程序运⾏在虚拟化环境中。
- 内存虚拟化:将不相邻的内存区,甚⾄硬盘空间虚拟成统⼀连续的内存地址,即我们常说的虚拟内存。
- 桌⾯虚拟化:让本地桌⾯程序利⽤远程计算机资源运⾏,达到控制远程计算机的⽬的。
虚拟机
虚拟机 ( Virtual Machine )。所谓虚拟机,通常来说就是通过⼀个虚拟机监视器 ( Virtual Machine Monitor ) 的设施来隔离操作系统与硬件或者应⽤程序与操作系统,以此达到虚拟化的⽬的。这个夹在其中的虚拟机监视器,常常被称为 Hypervisor。

容器技术
容器技术是⼀种全新意义上的虚拟化技术,按分类或者实现⽅式来说,其应该属于操作系统虚拟化的范畴,也就是在由操作系统提供虚拟化的⽀持。 所谓容器技术,指的是操作系统⾃⾝⽀持⼀些接⼜,能够让应⽤程序间可以互不⼲扰的独⽴运⾏,并且能够对其在运⾏中所使⽤的资源进⾏⼲预。 由于应⽤程序的运⾏被隔离在了⼀个独⽴的运⾏环境之中,这个独⽴的运⾏环境就好似⼀个容器,包裹住了应⽤程序,这就是容器技术名字的由来。 虚拟机VS容器

什么是Docker
Docker是由 dotCloud 在2013年开源的一个由Go实现的容器引擎。
Docker带来什么
利⽤它的全⾯性和易⽤性带来的提升我们的⼯作效率,可以将开发人员或者运维人员从重复且容易出错的服务搭建中解放出来,特别是在微服务的浪潮下,项目多模块化和服务化,一个完整的项目由很多小服务组成,这对于搭建来说也是一个不小的挑战。 docker技术实现 Docker 的实现,主要归结于三⼤技术:命名空间 ( Namespaces ) 、控制组 ( Control Groups ) 和联合⽂件系统 ( Union File System ) 。

Namespace
命名空间是 Linux 核⼼在 2.4 版本后逐渐引⼊的⼀项⽤于运⾏隔离的模块。Linux 内核的命名空间,就是能够将计算机资源进⾏切割划分,形成各⾃独⽴的空间。 就实现⽽⾔,Linux Namespaces 可以分为很多具体的⼦系统,如 User Namespace、Net Namespace、PID Namespace、Mount Namespace 等等。 这⾥我们以进程为例,通过 PID Namespace,我们可以造就⼀个独⽴的进程运⾏空间,在其中进程的编号又会从 1 开始。在这个空间中运⾏的进程,完全感知不到外界系统中的其他进程或是其他进程命名空间中运⾏的进程。

Control Groups
资源控制组 ( 常缩写为 CGroups ) 是 Linux 内核在 2.6 版本后逐渐引⼊的⼀项对计算机资源控制的模块。 顾名思义,资源控制组的作⽤就是控制计算机资源的。与隔离进程、⽹络、⽂件系统等虚拟资源为⽬的 Namespace 不同,CGroups 主要做的是硬件资源的隔离。 之前我们提到了,虚拟化除了制造出虚拟的环境隔离同⼀物理平台运⾏的不同程序之外,另⼀⼤作⽤就是控制硬件资源的分配,CGroups 的使⽤正是为了这样的⽬的。 需要再强调⼀次的是,CGroups 除了资源的隔离,还有资源分配这个关键性的作⽤。通过 CGroups,我们可以指定任意⼀个隔离环境对任意资源的占⽤值或占⽤率,这对于很多分布式使⽤场景来说是⾮ 常有⽤的功能。
Union File System
联合⽂件系统 ( Union File System ) 是⼀种能够同时挂载不同实际⽂件或⽂件夹到同⼀⽬录,形成⼀种联合⽂件结构的⽂件系统。联合⽂件系统本⾝与虚拟化并⽆太⼤的关系,但 Docker 却创新的将其引⼊ 到容器实现中,⽤它解决虚拟环境对⽂件系统占⽤过量,实现虚拟环境快速启停等问题。 在 Docker 中,提供了⼀种对 UnionFS 的改进实现,也就是 AUFS ( Advanced Union File System )。


| 属性 | Docker | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 硬盘使⽤ | MB 级 | GB 级 |
| 性能 | 接近原⽣ | 较低 |
| 普通机器⽀撑量 | 数百个 | ⼏个 |
Docker 能做什么
从理论上我们已经知道 Docker 能够为我们的⼯作带来巨⼤的便利,那么将其放于实践中,我们应该如何正确的使⽤它呢?这⾥我摘录整理了⼀段来⾃ Docker 官⽅⽂档的指导意见,希望能够对⼤家的实 践提供参考。
更快、更⼀致的交付你的应⽤程序
使⽤ Docker 后,开发者能够在本地容器中得到⼀套标准的应⽤或服务的运⾏环境,由此可以简化开发的⽣命周期 ( 减少在不同环境间进⾏适配、调整所造成的额外消耗 )。对于整个应⽤迭代来说,加⼊ Docker 的⼯作流程将更加适合持续集成 ( Continuous Integration ) 和持续交付 ( Continuous Delivery )。 举个具体的例⼦: 开发者能够使⽤ Docker 在本地编写代码并通过容器与其他同事共享他们的⼯作。 他们能够使⽤ Docker 将编写好的程序推送⾄测试环境进⾏⾃动化测试或是⼈⼯测试。 当出现 Bugs 时,开发者可以在开发环境中修复它们,并很快的重新部署到测试环境中。 在测试完成后,部署装有应⽤程序的镜像就能完成⽣产环境的发布。
跨平台部署和动态伸缩
基于容器技术的 Docker 拥有很⾼的跨平台性,Docker 的容器能够很轻松的运⾏在开发者本地的电脑,数据中⼼的物理机或虚拟机,云服务商提供的云服务器,甚⾄是混合环境中。 同时,Docker 的轻量性和⾼可移植性能够很好的帮助我们完成应⽤的动态伸缩,我们可以通过⼀些⼿段近实时的对基于 Docker 运⾏的应⽤进⾏弹性伸缩,这能够⼤幅提⾼应⽤的健壮性。
让同样的硬件提供更多的产出能⼒
Docker 的⾼效和轻量等特征,为替代基于 Hypervisor 的虚拟机提供了⼀个经济、⾼效、可⾏的⽅案。在 Docker 下,你能节约出更多的资源投⼊到业务中去,让应⽤程序产⽣更⾼的效益。同时,如此低的 资源消耗也说明了 Docker ⾮常适合在⾼密度的中⼩型部署场景中使⽤。
Docker核心组成
在 Docker 体系⾥,有四个对象 ( Object ) 是我们不得不进⾏介绍的,因为⼏乎所有 Docker 以及周边⽣态的功能,都是围绕着它们所展开的。它们分别是:镜像 ( Image )、容器 ( Container )、⽹络 ( Network )、数据卷 ( Volume )。
镜像
镜像,可以理解为⼀个只读的⽂件包,其中包含了虚拟环境运⾏最原始⽂件系统的 内容。 当然,Docker 的镜像与虚拟机中的镜像还是有⼀定区别的。⾸先,之前我们谈到了 Docker 中的⼀个创新是利⽤了 AUFS 作为底层⽂件系统实现,通过这种⽅式,Docker 实现了⼀种增量式的镜像结构。

容器
容器 ( Container ) 就更好理解了,在容器技术中,容器就是⽤来隔离虚拟环境的基础设施,⽽在 Docker ⾥,它也被引申为隔离出来的虚拟环境。 如果把镜像理解为编程中的类,那么容器就可以理解为类的实例。镜像内存放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成为了⼀个“活”的空间。 ⽤更官⽅的定义,Docker 的容器应该有三项内容组成:
- ⼀个 Docker 镜像
- ⼀个程序运⾏环境
- ⼀个指令集合
⽹络
在 Docker 中,实现了强⼤的⽹络功能,我们不但能够⼗分轻松的对每个容器的⽹络进⾏配置,还能在容器间建⽴虚拟⽹络,将数个容器包裹其中,同时与其他⽹络环境隔离。

数据卷
除了⽹络之外,⽂件也是重要的进⾏数据交互的资源。在以往的虚拟机中,我们通常直接采⽤虚拟机的⽂件系统作为应⽤数据等⽂件的存储位置。然⽽这种⽅式其实并⾮完全安全的,当虚拟机或者容器 出现问题导致⽂件系统⽆法使⽤时,虽然我们可以很快的通过镜像重置⽂件系统使得应⽤快速恢复运⾏,但是之前存放的数据也就消失了。 为了保证数据的独⽴性,我们通常会单独挂载⼀个⽂件系统来存放数据。这种操作在虚拟机中是繁琐的,因为我们不但要搞定挂载在不同宿主机中实现的⽅法,还要考虑挂载⽂件系统兼容性,虚拟操作 系统配置等问题。值得庆幸的是,这些在 Docker ⾥都已经为我们轻松的实现了,我们只需要简单的⼀两个命令或参数,就能完成⽂件系统⽬录的挂载。 能够这么简单的实现挂载,主要还是得益于 Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载⽬录外,还能够建⽴独⽴的⽬录持久存放数据,或者在容器间共 享。 在 Docker 中,通过这⼏种⽅式进⾏数据共享或持久化的⽂件或⽬录,我们都称为数据卷 ( Volume )。
Docker Engine
时⾄今⽇,Docker ⽣态已经远⽐它诞⽣之初要庞⼤许多,虽然我们仍然习惯使⽤ Docker 这个名字去指代实现容器技术⽀持的软件,但显然更加容易与其他的概念产⽣混淆。这⾥我们很有必要对这个 Docker 中最核⼼的软件进⾏介绍,不仅因为它在 Docker ⽣态中扮演着中⼼的地位,也因为它是我们在开发中实实在在接触最多的东西。 ⽬前这款实现容器化的⼯具是由 Docker 官⽅进⾏维护的,Docker 官⽅将其命名为 Docker Engine,同时定义其为⼯业级的容器引擎 ( Industry-standard Container Engine )。在 Docker Engine 中,实现了 Docker 技术中最核⼼的部分,也就是容器引擎这⼀部分。
docker daemon 和 docker CLI
虽然我们说 Docker Engine 是⼀款软件,但实实在在去深究的话,它其实算是由多个独⽴软件所组成的软件包。在这些程序中,最核⼼的就是 docker daemon 和 docker CLI 这俩了。 所有我们通常认为的 Docker 所能提供的容器管理、应⽤编排、镜像分发等功能,都集中在了 docker daemon 中,⽽我们之前所提到的镜像模块、容器模块、数据卷模块和⽹络模块也都实现在其中。在操 作系统⾥,docker daemon 通常以服务的形式运⾏以便静默的提供这些功能,所以我们也通常称之为 Docker 服务。

