Docker技术原理

🏡Docker概念
📁Docker is an open-source project that automates the deployment of applications indise software containers,by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux.
📁Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的LInux及其上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口(类似iPhone的app).几乎没有性能开销,可以很容易地在机器和数据中心中运行.
在这里插入图片描述
Docker 的出现一定是因为目前的后端在开发和运维阶段确实需要一种虚拟化技术解决开发环境和生产环境环境一致的问题,通过 Docker 我们可以将程序运行的环境也纳入到版本控制中,排除因为环境造成不同运行结果的可能.但是上述需求虽然推动了虚拟化技术的产生,但是如果没有合适的底层技术支撑,那么我们仍然得不到一个完美的产品.
🏡Namespaces
命名空间 (namespaces) 是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法.在日常使用 Linux 或者 macOS 时,我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样.
在这里插入图片描述
在这种情况下,一旦服务器上的某一个服务被入侵,那么入侵者就能够访问当前机器上的所有服务和文件,这也是我们不想看到的,而Docker其实就通过Linux的Namespaces对不同的容器实现了隔离.
Linux的命名空间机制提供了以下其中不同的命名空间:

Namespace 系统调用参数 功能 隔离内容
IPC CLONE_NEWIPC 保证容器内的进程能够相互通信,但是不能跨容器访问其他容器的数据 信号量、消息队列和共享内存
Mount CLONE_NEWNS 独立的根文件系统,以实现在容里面启动服务并且构建出容器的运行环境 挂载点(文件系统)
UTS CLONE_NEWUTS 用于系统标识,包含主机名和域名,用来唯一标识独立于宿主机系统和运行在其上的其他容器 主机名或域名
PID CLONE_NEWPID 每个容器处有一个PID为1的进程,用来管理进程的创建和回收 进程编号
Network CLONE_NEWNET 网络是容器中非常重要的一环,每个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP协议栈等,在运行容器时会自动生成一些防火墙规则用于和外界通讯 网络设备、网络栈、端口等
User CLONE_NEWUSER 每个容器中都有单独的用户和组,和宿主机并不冲突,只是会把用户的作用范围限制在每个容器内 用户和用户组

🏡CGroups
通过Linux的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离,但是命名空间并不能够为我们提供物力资源上的隔离,比如CPU或者内存,如果同一台机器上运行了多个对彼此以及宿主机器一无所知的容器,这些容器却共同占用了宿主机器的物理资源.
在这里插入图片描述
如果其中的一个容器正在执行CPU密集型的任务,那么就会影响其他容器中任务的性能与执行效率,导致多个容器互相影响并且抢占资源.如何对多个容器的资源使用进行限制就成了解决进程虚拟资源隔离之后的主要问题,而Control Groups(简称CGroups)就是能够隔离宿主机器上的物理资源,例如CPU、内存、磁盘I/O和网络带宽.
每一个CGroup都是一组被相同的标准和参数限制的进程,不同的CGroup支架是由层级关系的,也就是说它们之间可以从父类继承一些用于限制资源使用的标准和参数.
在这里插入图片描述
Linux的CGroup能够为一组进程分配资源,也就是我们再上面提到的CPU、内存、网络带宽等资源,通过对资源的分配,CGroup能够提供以下的几种功能:
在这里插入图片描述
在Cgroup中,所有的任务就是一个系统的一个进程,而CGroup就是一组按照某种标准划分的进程,在CGroup这种机制中,所有的资源控制都是以CGroup作为单位实现的,每一个进程都可以随时加入一个CGroup,也可以随时退出一个CGroup.
CGroup介绍、应用实例以及原理描述
Linux使用文件系统来实现CGroup,可以直接使用如下命令查看当前CGroup中有哪些子系统.
在这里插入图片描述
大多数Linux的发行版都有这非常相似的子系统,之所以将上面的cpuset、cpu等东西称作子系统,是因为它们能够为相对应的控制组分配资源并限制资源的使用.
如果要创建一个新的CGroup只需要在想要分配或者限制资源的子系统下面创建一个新的文件夹,然后这个文件夹就会自动出现很多内容.如果在Linux上安装了Docker,就会发现所有的子系统目录下都有一个名为docker的文件夹:
在这里插入图片描述
9c3057xxx 其实就是我们运行的一个 Docker 容器,启动这个容器时,Docker 会为这个容器创建一个与容器标识符相同的 CGroup,在当前的主机上 CGroup 就会有以下的层级关系:
在这里插入图片描述
每一个 CGroup 下面都有一个 tasks 文件,其中存储着属于当前控制组的所有进程的 pid,作为负责 cpu 的子系统,cpu.cfs_quota_us 文件中的内容能够对 CPU 的使用作出限制,如果当前文件的内容为 50000,那么当前控制组中的全部进程的 CPU 占用率不能超过 50%.
如果系统管理员想要控制 Docker 某个容器的资源使用率就可以在 docker 这个父控制组下面找到对应的子控制组并且改变它们对应文件的内容,当然我们也可以直接在程序运行时就使用参数,让 Docker 进程去改变相应文件中的内容.
在这里插入图片描述
当我们使用Dokcer关闭掉正在运行的容器时,Docker的子控制组对应的文件夹也会被Docker进程移除,Docker在使用CGroup时也只是做了一些创建文件夹改变文件内容的文件操作,不过CGroup的使用也确实解决了限制子容器资源占用的问题,系统管理员能够为多个容器合理分配的资源并且不会出现多个容器互相抢占资源的问题.


🏡UnionFS
Linux的命名空间和控制组分别解决了不同资源隔离的问题,前者解决了进程、网络以及文件系统的隔离,后者实现了CPU、内存等资源的隔离,但是在Docker中还有一个非常重要的问题需要解决,就是镜像.
Docker镜像其实本质就是一个压缩包,我们可以使用下面的命令讲一个Docker镜像中的文件导出:
在这里插入图片描述
可以看到这个busybox镜像中的目录结构和Linux操作系统的根目录中的内容并没有太多的却别,可以说Docker镜像就是一个文件.

  • 💿存储驱动
    Docker使用了一系列不同的存储驱动管理镜像内的文件系统并运行容器,这些存储驱动与Docker卷(Volume)有些不同,存储引擎管理者能够在多个容器之间共享的存储.
    首先需要理解 Docker 是如何构建并且存储镜像的,也需要明白 Docker 的镜像是如何被每一个容器所使用的;Docker 中的每一个镜像都是由一系列只读的层组成的,Dockerfile 中的每一个命令都会在已有的只读层上创建一个新的层:
    在这里插入图片描述
    容器中的每一层都只对当前容器进行了非常小的修改,上述的 Dockerfile 文件会构建一个拥有四层 layer 的镜像:
    在这里插入图片描述
    当镜像被 docker run 命令创建时就会在镜像的最上层添加一个可写的层,也就是容器层,所有对于运行时容器的修改其实都是对这个容器读写层的修改.
    容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器.
    在这里插入图片描述
  • 💿AUFS
    UnionFS其实是一种为Linux操作系统设计的用于把多个文件系统联合到同一个挂载点的文件系统服务.而AUFS即Advanced UnionFSQISHI JIUSHI UnionFS的升级版,能够提供更优秀的性能和效率.
    AUFS 作为联合文件系统,它能够将不同文件夹中的层联合(Union)到了同一个文件夹中,这些文件夹在 AUFS 中称作分支,整个『联合』的过程被称为联合挂载(Union Mount):
    在这里插入图片描述
    每一个镜像层或者容器层都是 /var/lib/docker/ 目录下的一个子文件夹;在 Docker 中,所有镜像层和容器层的内容都存储在 /var/lib/docker/aufs/diff/ 目录中:
    在这里插入图片描述
    而 /var/lib/docker/aufs/layers/ 中存储着镜像层的元数据,每一个文件都保存着镜像层的元数据,最后的 /var/lib/docker/aufs/mnt/ 包含镜像或者容器层的挂载点,最终会被 Docker 通过联合的方式进行组装.
    在这里插入图片描述
    上图非常好地展示了组装的过程,每一个镜像层都是建立在另一个镜像层之上的,同时所有的镜像层都是只读的,只有每个容器最顶层的容器层才可以被用户直接读写,所有的容器都建立在一些底层服务(Kernel)上,包括命名空间,控制组,rootfs等等,这种容器的组装方式提供了非常大的灵活性,只读的镜像层通过共享也能够减少磁盘的占用.

🖨总结
Docker目前已经成为了非常主流的技术,已经在很多成熟公司的生产环境中使用,但是Docker的核心技术其实已经有很多年历史了,Linux命名空间、控制组和UnionFS三大技术支撑了目前Docker的实现,也是Docker能够出现的最重要原因.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章