Docker 项目的核心原理:为待创建的用户进程
1.启用 Linux Namespace 配置:修改进程视图
2.设置指定的 Cgroups 参数:为进程设置资源限制
3.切换进程的根目录(Change Root):
容器的隔离与限制
1.启用 Linux Namespace 配置
namespace 技术是用来修改进程视图的主要方法
1) linux 创建namespace的代码逻辑
以创建PID namespace 为例
namespace 是linux创建进程的一个可选参数,在 Linux 系统中创建进程的系统调用是 clone(),比如:
int pid = clone(main_function, stack_size, SIGCHLD, NULL);
这个系统调用就会为我们创建一个新的进程,并且返回它的进程号 pid。
而当我们用 clone() 系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID 参数
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 PID 是 1,在宿主机真实的进程空间里,这个进程的 PID 还是真实的数值,比如 100。
2) linux namespace 介绍
- UTS Namespace:隔离主机名
- IPC Namespace:隔离进程间通信
- PID Namespace:隔离进程ID
- Mount Namespace:隔离进程看到的文件层级
- User Namespace:隔离用户组ID(举个例子:在宿主机上以一个非root用户运行创建一个User Namespace ,在UserNamespace里面映射成root用户)
- Network Namespace:用来隔离网络设备,IP地址端口等网络栈
Mount Namespace 跟其他 Namespace 的使用略有不同的地方:它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。
3) namespace技术缺陷
- 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。这意味着,如果要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的。
- 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间。
2.设置指定的 Cgroups 参数
cgroup全称是control groups。control groups:控制组,被整合在了linux内核当中,把进程(tasks)放到组里面,对组设置权限,对进程进行控制(它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等)。可以理解为用户和组的概念,用户会继承它所在组的权限。
cgroup 提供了将进程组织成控制组的能力,然后通过使用 资源控制子系统(cgroup_subsys) 来对控制组进行资源使用的控制,cgroup 支持的 资源控制子系统 有以下几种:
cpu子系统:限制 CPU 的使用。
memory子系统:限制内存使用。
cpuset子系统:可以为进程组分配单独的 CPU 或者内存节点。
cpuacct子系统:统计CPU group的使用情况。
blkio子系统:限制I/O,一般用于磁盘。
devices子系统:限制进程使用的设备。
freezer子系统:可以挂起和恢复进程组。
net_cls子系统:可以标记进程组的网络数据包,使用 tc 模块(traffic control)对数据包进行控制。
cgroup 通过把进程组织成 控制组,然后通过 资源控制子系统 来对 控制组 进行资源使用的限制,所以 cgroup 的分析可以分成两部分:cgroup框架 和 资源控制子系统。
cgroup 控制组
控制组 说白了就是一组进程(进程组),cgroup 就是用来限制 控制组 的资源使用。为了能够方便地向一个 控制组 添加或者移除进程(在命令行也能操作),内核使用了 虚拟文件系统 来进行管理 控制组。
我们可以把一个 控制组 当成是一个目录,由于目录有层级关系,所以 控制组 也有层级关系,如下图所示:
cgroup CPU限制
在cgroup里面,跟CPU相关的子系统有cpusets、cpuacct和cpu。
cpuset主要用于设置CPU的亲和性,可以限制cgroup中的进程只能在指定的CPU上运行,或者不能在指定的CPU上运行
cpuacct包含当前cgroup所使用的CPU的统计信息
cgroup Memory 限制
在上图中,我们创建了 2 个 cgroup(每个 cgroup 有 4 个进程),并且限制它们各自最多只能使用 2GB 的内存。如果使用超过 2GB 的内存,那么将会触发 OOM(Out Of Memory) 错误。
Cgroups缺陷
Cgroups 对资源的限制能力有很多不完善的地方,比如 /proc 文件系统的问题。
Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。
但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。
造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。