对虚拟化和容器技术的理解总结
因为项目需求,最近在学习虚拟化和容器技术,在网上看到了很多关于这方面的知识,所以在这里写一篇博客简单总结一下这段时间学习的收获。
1.虚拟化
虚拟化的概述
虚拟化技术其实是一种将计算机物理资源进行抽象、转换为虚拟的计算机资源提供给程序使用的技术。虚拟化技术作为云计算的基础,属于云计算技术的基础架构即服务层,其提供"资源的整合"和“重新逻辑”(例如,将用户发送请求,管理员得到请求后把用户需要的计算机资源梳理成可以马上投入使用的“计算机”,再将其提供给用户)按需分配,使得资源充分利用。
虚拟化的工作原理
虚拟化的工作原理是直接在物理服务器硬件上或主机操作系统上插入一个精简的软件层,该软件层包含一个以动态和透明方式分配硬件资源的虚拟机监视器(虚拟化管理程序,也称为Hypervisor)。虚拟化的工作原理是一个类似的“封装过程”,将硬件资源(包括CPU、内存、操作系统和网络设备)"封装"起来、因此虚拟机可与所有标准的操作系统、应用程序和设备驱动程序完全兼容,可与同时在一台物理服务器上安装运行多个操作系统和应用程序,每个操作系统和应用程序都可以在其需要时访问其所需的资源。
虚拟化的好处
开发者不需要写复杂的兼容性代码即可实现跨平台运行应用程序。当虚拟化应用于计算机的资源管理时,通过虚拟化技术来管理计算机资源的方式,不但让我们对计算机资源的控制变得更加灵活,也大幅提高了计算机资源的使用率。提高使用率是因为当我们平时使用计算机时,系统几乎 95% 以上的资源处于闲置状态。如果我们通过虚拟化技术,把其他的一些程序放到这台机器上来运行,它们就能够充分利用闲置的资源。这带来的好处就是我们不需要再为这些程序单独部署机器,从而节约不少的成本。
部分读者可能会产生疑惑,我本身就可以在操作系统里安装这些程序并且同时运行,为什么还要把它们分别装到不同的虚拟环境中去呢?虽然我们能够在操作系统里同时运行多个程序,但前提得是这些程序本身不存在冲突。这里的冲突体现在很多的方面,例如不同的程序同时使用了同一个端口;不同程序依赖于同一个工具库的不同版本;程序本身限制了同时开启的进程数等。虚拟化技术通过资源隔离的方式,无形地也可以把这些程序隔离在不同的虚拟环境中,既然虚拟环境不同,自然运行在不同环境中的程序就不会互相干扰或争抢资源了。
虚拟化的分类
总体来说可以区分为两大类:硬件虚拟化,软件虚拟化。
1. 硬件虚拟化:指的是物理硬件本身就提供虚拟化的支持。举个例子来说,某个平台的 CPU,能够将另外一个平台的指令集转换为自身的指令集执行,并给程序完全运行在那个平台上的感觉。又或者说,CPU 能够自身模拟裂变,让程序或者操作系统认为存在多个 CPU,进而能够同时运行多个程序或者操作系统。这些都是硬件虚拟化的体现。
2. 软件虚拟化:指的是通过软件的方式来实现虚拟化中关键的指令转换部分。依然用 CPU 的例子来说话,在软件虚拟化实现中,通过一层夹杂在应用程序和硬件平台上的虚拟化实现软件来进行指令的转换。也就是说,虽然应用程序向操作系统或者物理硬件发出的指令不是当前硬件平台所支持的指令,这个实现虚拟化的软件也会将之转换为当前硬件平台所能识别的。
当然,在实际场景中,虚拟化还能进行更加细化的分类,例如:
- 平台虚拟化:在操作系统和硬件平台间搭建虚拟化设施,使得整个操作系统都运行在虚拟后的环境中。
- 应用程序虚拟化:在操作系统和应用程序间实现虚拟化,只让应用程序运行在虚拟化环境中。
- 内存虚拟化:将不相邻的内存区,甚至硬盘空间虚拟成统一连续的内存地址,即我们常说的虚拟内存。
- 桌面虚拟化:让本地桌面程序利用远程计算机资源运行,达到控制远程计算机的目的。
2.容器技术
容器技术的概述
容器技术是一种全新意义上的虚拟化技术,按分类或者实现方式来说,其属于操作系统虚拟化的范畴,由操作系统提供虚拟化的支持。指的是操作系统自身支持一些接口,能够让应用程序间可以互不干扰的独立运行,并且能够对其在运行中所使用的资源进行干预。由于应用程序的运行被隔离在了一个独立的运行环境之中,这个独立的运行环境就好似一个容器,包裹住了应用程序,这就是容器技术名字的由来。说起容器技术,就不得不说docker了,下面是docker官方提供的图片。形象一点形容就是,我们的操作系统环境就像是大海一样,而docker就像是其中的一条鲸鱼,载着各种各样的容器运行在我们的操作系统上。
容器技术与虚拟机的区别
从下图可以分析出容器技术是如何从效率上完胜虚拟机
由于没有了虚拟操作系统和虚拟机监视器这两个层次,大幅减少了应用程序运行带来的额外消耗。
更准确的来说,所有在容器中的应用程序其实完全运行在了宿主操作系统中,与其他真实运行在其中的应用程序在指令运行层面是完全没有任何区别的。
docker的技术实现
Docker 的实现,主要归结于三大技术:命名空间 ( Namespaces ) 、控制组 ( Control Groups ) 和联合文件系统 (c ) 。接下来分别介绍这三种技术
Namespace
命名空间是 Linux 核心在 2.4 版本后逐渐引入的一项用于运行隔离的模块。命名空间的主要目的就是为了集合相同模块的类,区分不同模块间的同名类。同样的,Linux 内核的命名空间,就是能够将计算机资源进行切割划分,形成各自独立的空间。
就实现而言,Linux Namespaces 可以分为很多具体的子系统,如 User Namespace、Net Namespace、PID Namespace等等。
这里我们以进程为例,通过 PID Namespace,我们可以造就一个独立的进程运行空间,在其中进程的编号又会从 1 开始。在这个空间中运行的进程,完全感知不到外界系统中的其他进程或是其他进程命名空间中运行的进程。
Control Groups
资源控制组 ( 常缩写为 CGroups ) 是 Linux 内核在 2.6 版本后逐渐引入的一项对计算机资源控制的模块。资源控制组的作用就是控制计算机资源的。
与以隔离进程、网络、文件系统等虚拟资源为目的 Namespace 不同,CGroups 主要做的是硬件资源的隔离。虚拟化除了制造出虚拟的环境隔离同一物理平台运行的不同程序之外,另一大作用就是控制硬件资源的分配,CGroups 的使用正是为了这样的目的。CGroups 除了资源的隔离,还有资源分配这个关键性的作用。通过 CGroups,我们可以指定任意一个隔离环境对任意资源的占用值或占用率,这对于很多分布式使用场景来说是非常有用的功能。
Union File System
联合文件系统 ( Union File System ) 是一种能够同时挂载不同实际文件或文件夹到同一目录,形成一种联合文件结构的文件系统。联合文件系统本身与虚拟化并无太大的关系,但 Docker 却创新的将其引入到容器实现中,用它解决虚拟环境对文件系统占用过量,实现虚拟环境快速启停等问题。
docker的四大组成对象
镜像 ( Image )、容器 ( Container )、网络 ( Network )、数据卷 ( Volume )。
镜像
镜像,可以理解为一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容。Docker 的镜像与虚拟机中的镜像还是有一定区别的。docker利用了 AUFS 作为底层文件系统实现,通过这种方式,Docker 实现了一种增量式的镜像结构。
每次对镜像内容的修改,Docker 都会将这些修改铸造成一个镜像层,而一个镜像其实就是由其下层所有的镜像层所组成的。当然,每一个镜像层单独拿出来,与它之下的镜像层都可以组成一个镜像。
另外,由于这种结构,Docker 的镜像实质上是无法被修改的,因为所有对镜像的修改只会产生新的镜像,而不是更新原有的镜像。
为了将零星的数据整合起来,我们提出了镜像层(image layer)这个概念。layer(镜像层)是一个Docke来管理镜像层的中间概念,单个镜像层可能被多个镜像共享。
下面的这张图描述了一个镜像层,通过图片我们能够发现一个层并不仅仅包含文件系统的改变,它还能包含了其他重要信息。
每一层都包括了一个指向父层的指针。如果一个层没有这个指针,说明它处于最底层。
容器
容器 ( Container ) 就更好理解了,在容器技术中,容器就是用来隔离虚拟环境的基础设施,而在 Docker 里,它也被引申为隔离出来的虚拟环境。如果把镜像理解为编程中的类,那么容器就可以理解为类的实例。镜像内存放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成为了一个“活”的空间。
容器(container)的定义和镜像(image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
用更官方的定义,Docker 的容器应该有三项内容组成:
- 一个 Docker 镜像
- 一个程序运行环境
- 一个指令集合
网络
在 Docker 中,实现了强大的网络功能,我们不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离。另外,利用一些技术,Docker 能够在容器中营造独立的域名解析环境,这使得我们可以在不修改代码和配置的前提下直接迁移容器,Docker 会为我们完成新环境的网络适配。对于这个功能,我们甚至能够在不同的物理服务器间实现,让处在两台物理机上的两个 Docker 所提供的容器,加入到同一个虚拟网络中,形成完全屏蔽硬件的效果。正是因为拥有强大的网络功能,才能让我们制造健壮的 Docker 应用体系。
数据卷
除了网络之外,文件也是重要的进行数据交互的资源。在以往的虚拟机中,我们通常直接采用虚拟机的文件系统作为应用数据等文件的存储位置。然而这种方式其实并非完全安全的,当虚拟机或者容器出现问题导致文件系统无法使用时,虽然我们可以很快的通过镜像重置文件系统使得应用快速恢复运行,但是之前存放的数据也就消失了。
为了保证数据的独立性,我们通常会单独挂载一个文件系统来存放数据。这种操作在虚拟机中是繁琐的,因为我们不但要搞定挂载在不同宿主机中实现的方法,还要考虑挂载文件系统兼容性,虚拟操作系统配置等问题。值得庆幸的是,这些在 Docker 里都已经为我们轻松的实现了,我们只需要简单的一两个命令或参数,就能完成文件系统目录的挂载。
能够这么简单的实现挂载,主要还是得益于 Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。
在 Docker 中,通过这几种方式进行数据共享或持久化的文件或目录,我们都称为数据卷 ( Volume )。
通过挂载数据卷的方式,我们可以让宿主机的文件数据和容器中的文件数据进行交互,可以得知容器内部发生的情况,还可以通过容器之间继承数据卷的方式,实现容器集群共享数据。
Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。Dockerfile 的每一条指令都会生成一个对应的镜像层,而镜像正是由Dockerfile生成的一个个镜像层所构成的,最上层的镜像层id代表了整个镜像的id。学习Dockerfile的相关操作指令,可以通过这个网址学习:https://www.runoob.com/docker/docker-dockerfile.html
镜像,容器,仓库之间的相互关系及对应操作指令图
本文部分内容来源于CSDN博主「千与千寻之前」的原创文章:https://blog.csdn.net/cpongo3/article/details/93623781