Docker的实现原理以及与容器的区别

323 阅读7分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

docker和容器的区别?

其实容器的发展历史早于docker的。docker也不等同于容器,“容器”是一系列内核特性的统称。

2000年的时候,LXC容器发布,这是一种内核虚拟 化的技术,可以提供轻量级的虚拟化,以便隔离进程和资源,LXC是docker最初使用的具体内核功能的实现。

2013年的时候,Docker发布,组合LXC、Union File System和cgroups等Linux技术,创建了容器化标准。而且Docker 引入了ship(发布)的概念,构建了一套build-ship-run的软件开发流程,让软件开发、发布、运行变得更加简单。

比较内容传统开发方式容器开发方式
构建方式maven打包dockerfile
交付方式jar包或者war包容器
一致性弱,开发环境、测试环境、生产环境难以一致强,不依赖于OS以及运行时环境

docker 应用了哪些内核技术

NameSpace隔离进程运行环境

NameSpace是Linux系统内核用来隔离内核资源的一种方式,通过NameSpace可以让进程只能看到与自己相关的资源。不同的NameSpace下的进程相互隔离,不能被感知到。NameSpace是对全局系统资源的一种封装隔离,使得在不同NameSpace下的进程拥有独立的全局系统资源,改变一个NameSpace下的系统资源只会影响这个NameSpace下的进程,对其他NameSpace下的进程无影响。

Linux内核实现NameSpace的一个主要目的就是想实现轻量级虚拟化服务,同一个NameSpace下的进程可以感知到彼此的存在,而对外界的进程一无所知,让容器以为自身处在一个独立的系统中,从而达到隔离的目的。

从dokcer实现者的角度看,可以通过chroot命令切换根目录的挂载点,使得文件系统隔离。

容器拥有独立的IP、端口、路由,网络之间进行了隔离。容器有自己的PID(进程号)和宿主机的PID进行隔离。容器有自己的用户,用户组需要隔离。

通过这些全局系统资源的隔离,使得容器中的进程看起来像是拥有了独立的系统环境。存在一些LInux命令对进程和NameSpace操作,例如:Clone。创建新进程并且指定他的NameSpace。

cgroup参数限制资源分配的配额?

cgroups是Linux内核提供的一种可以限制一个进程或者多个进程的所使用资源的机制,可以针对内存、CPU等实现精细化的控制。

cgroups 全称是control groups,cgroups为每种可以控制的资源定义了一个子系统。典型的子系统介绍如下:

  1. cpu 子系统,主要限制进程的 cpu 使用率。
  2. cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
  3. cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
  4. memory 子系统,可以限制进程的 memory 使用量。
  5. blkio 子系统,可以限制进程的块设备 io。
  6. devices 子系统,可以控制进程能够访问某些设备。
  7. net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
  8. freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
  9. ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。

这里面每一个子系统都需要与内核的其他模块配合来完成资源的控制。

cgroup的层级结构:

docker订单

上面这个图从整体结构上描述了进程与 cgroups 之间的关系。最下面的P代表一个进程。每一个进程的描述符中有一个指针指向了一个辅助数据结构css_set(cgroups subsystem set)。 指向某一个css_set的进程会被加入到当前css_set的进程链表中。一个进程只能隶属于一个css_set,一个css_set可以包含多个进程,隶属于同一css_set的进程受到同一个css_set所关联的资源限制。

上图中的”M×N Linkage”说明的是css_set通过辅助数据结构可以与 cgroups 节点进行多对多的关联。但是 cgroups 的实现不允许css_set同时关联同一个cgroups层级结构下多个节点。 这是因为 cgroups 对同一种资源不允许有多个限制配置。

一个css_set关联多个 cgroups 层级结构的节点时,表明需要对当前css_set下的进程进行多种资源的控制。而一个 cgroups 节点关联多个css_set时,表明多个css_set下的进程列表受到同一份资源的相同限制。

切换进程的根目录到联合挂载的rootfs(change root)

Union File System,联合文件系统,将多个不同位置的目录联合挂载(union mount)到同一个目录下,Docker 利用这种联合挂载的能力,将容器镜像里的多层内容呈现为统一的rootfs(根文件系统),Rootfs打包了整个操作系统的文件和目录,是应用运行所需要的最完整的“依赖库”。

在Docker中使用AUFS(Another Union File System或Advanced Multilayered Unification File System)就是一种联合文件系统。AUFS不仅可以对每一个目录设定只读(Readonly)、读写(Readwrite)和写(Witeout-able)权限,同时AUFS也可以支持分层的机制,例如,可以对只读权限部分逻辑上进行增量地修改而不影响只读部分。

docker订单

当Docker在利用镜像启动一个容器时,Docker镜像将分配文件系统,并且挂载一个新的可读写的层给容器,容器将会在这个文件系统中被创建,并且这个可读写的层被添加到镜像中。Docker目前支持的联合文件系统种类包括AUFS、Btrfs、VFS和DeviceMapper等。

在Docker中,上层的Image依赖下层的Image,因此Docker中把下层的Image称作父Image,没有父Image的Image称作Base Image。

因此,想要从一个Image启动一个Container,Docker会先逐次加载其父Image直到Base Image,用户的进程运行在Writeable的文件系统层中。

所有父Image中的数据信息以及ID、网络和LXC管理的资源限制、具体container的配置等,构成一个Docker概念上的Container。

Docker安全性:

Docker容器的安全问题在于是共享内核,因此受到攻击的时候攻击面会特别大。

SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。

在使用了 SELinux 的操作系统中,决定一个资源是否能被访问的因素除了某个资源是否拥有对应用户的权限(读、写、执行)外,还需要判断每一类进程是否拥有对某一类资源的访问权限。

这样一来,即使进程是以 root 身份运行的,也需要判断这个进程的类型以及允许访问的资源类型才能决定是否允许访问某个资源。进程的活动空间也可以被压缩到最小。

即使是以 root 身份运行的服务进程,一般也只能访问到它所需要的资源。即使程序出了漏洞,影响范围也只有在其允许访问的资源范围内。安全性大大增加。

docker订单

\