Docker:概念和原理

针对自己学习Docker过程中关于概念和原理上比较重要的内容进行了总结,参考了许多教程

初探


下面先从概念上简单认识一下Docker和容器

Docker和容器


Docker,简单地说就是一个创建和管理容器的工具,而所谓容器,实际上是一种轻量级的虚拟化技术(注意,容器是一个概念,Docker是实现容器的工具)

你可能会问,为啥叫它容器?容器里面总要装点什么吧?没错,容器里面装的就是应用程序,更确切地说,应该是应用程序和它运行时所需要的所有环境

也就是说,容器实际上是一种沙盒技术,就像一个集装箱一样,把你的应用装起来,或者说隔离起来,然后在这个集装箱配置好应用程序,下回我想把应用放到新环境下我可以直接把集装箱(虽然叫集装箱,但其实很轻量的)搬过去就能直接运行了

容器和虚拟机的区别


虚拟机是另一种常见的虚拟技术

虚拟机是直接虚拟到了硬件层,就是说它把处理器、内存、硬盘和网络接口都给你虚拟出来了,在此之上还虚拟了一套包括内核在内的完整的操作系统,而这些都是在你的宿主机操作系统上虚拟出来的,可想而知需要占用多少资源

而容器就不同了,它只是某个进程提供了一个操作系统"空壳",之所以说空壳是因为实际上只是为进程提供了一套文件系统,然后在创建进程的时候给它设定了一些特殊的参数,实际上内核也还是用宿主机的操作系统,确实是足够轻量吧


所以为了了解Docker,就不得不提到容器。由于本人非计算机专业人士,并没有系统学习过Linux内核,可能不会特别深入讨论,想深入了解可以看张磊老师的"深入剖析 Kubernetes"一文,讲的清晰透彻,当然本文也会借鉴其中很多讲解,是一篇深度好文

容器的实现


容器主要的作用就是通过对一个进程进行修饰(其实就是在创建进程时设置特定的参数),从而为其创造出一个边界进行限制

对于包括Docker在内的Linux容器,使用**Namespace技术通过修改进程视图的方式对应用的环境进行了隔离**,Cgroups技术来限制(对宿主机)资源的占用

这里将只对NamespaceCgroups技术的作用进行描述,具体实现涉及Linux内核相关知识,所以就不展开详细讲了

Linux Namespace技术


Namespace其实是Linux在创建进程时的一个可选参数,通过给进程指定一系列的参数来对进程创造了一个全新的进程空间。例如,可以用PID Namespace将进程隔离到一个独立的空间,让它认为自己是系统的的第1号(PID = 1)进程,也看不到系统内的其他进程,可以用Mount Namespace给进程挂载一个自己的文件系统。此外,还有NetworkUserUTSIPC这些Namespace,都是用来对进程的上下文进行限制的

说到这里,这感觉有点像《盗梦空间》里筑梦师(Docker)给人们(进程)造的梦(容器)一样,让他们以为梦境(进程空间)是真实的,而察觉不到现实(宿主机)

Linux Cgroups技术


Linux Cgroups的全程为Linux Control Groups,它最主要的作用就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘和网络带宽等等。

在Linux中,Cgroups给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的/sys/fs/cgroup路径下。

容器的单进程模型


通过上面的描述,要明白容器实际上是一个"单进程"模型。但是"单进程"的意思是只有一个进程是被限制的(可控的),并不是只能运行一个进程。

一个正在运行的Docker容器,其实就是一个启用了多个Linux Namespace的应用进程,而这个进程能够使用的资源量,则受Cgroups配置的限制。

在宿主机中使用ps aux | grep xxx是可以找到容器中的进程在宿主机中真实的PID

容器镜像(rootfs)


容器镜像其实就是挂载在容器根目录上的文件系统,为了更加真实,通常都会挂载一个完整操作系统的文件系统。

但是要注意的是,容器镜像提供的只是一个操作系统包含的文件,配置和目录,并不包括操作系统内核。因此,同一台机器上的所有容器都会共享宿主机操作系统的内核。

Docker使用的rootfs是由多个层组成的,简单的理解就是用户在容器内对rootfs做的修改会以增量的方式出现在特定的层(可读写层)中。每个曾通过联合挂载的方式得到了一整个完整的rootfs

有了容器镜像,我可以事先在这个镜像环境下配置好我的应用,然后使用Docker将整个环境和应用封装打包到一起,这样其他人直接安装我这个打包好的容器就好了,就不用担心重新配置环境的问题。

总结


到此,对容器和Docker应该有了一个初步的认识,概括一下就是,Docker是创建容器的工具,容器其实就是在操作系统之上通过内核的隔离机制为应用程序创建的一个能够满足其运行的"相对"独立的环境

Docker主要为待创建进程所做的工作其实就是:

  1. 启用Linux Namespace配置

  2. 设置指定的Cgroups参数

  3. 切换到进程的根目录(容器镜像的根目录)

参考


发表了43篇文章 · 总计78.96k字
·
Built with Hugo
主题 StackJimmy 设计