一. 简介
开篇,先给出一个结论:容器是一个“单进程”模型。一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。
关于Namespace和Cgroups这俩功能的联合使用,实现了Docker所谓的 伪“虚拟化”。
二. Namespace
Namespace是Linux内核的功能之一,也是Linux上容器的基本方面。另一方面,Namespace提供了一层隔离。Docker使用各种Namespace来提供容器所需的隔离,以便保持可移植性并避免影响主机系统的其余部分。容器的每个方面都在单独的Namespace中运行,并且对其的访问仅限于该Namespace。
2.1 clone()函数
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);
2.2 原理
例如上面案例,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 PID 是 1。之所以说“看到”,是因为这只是一个“障眼法”,在宿主机真实的进程空间里,这个进程的 PID 还是真实的数值,比如 100。
2.3 Namespace分类
Namespace类型如下:
- Process ID
- Mount
- IPC (Interprocess communication)
- User (currently experimental support for)
- Network
2.4 小结
实际上在创建容器进程时,Docker指定了这个进程所需要启用的一组 Namespace 参数。这样,容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。
三. Cgroups
Linux Cgroups
的全称是 Linux Control Group
。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
3.1 查看cgroup文件
在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup
路径下。
我们可以通过如下指令查看
mount -t cgroup
在 /sys/fs/cgroup
下面有很多诸如cpuset、cpu、 memory
这样的子目录,也叫子系统。这些都是当前机器当前可以被 Cgroups 进行限制的资源种类。
3.2 限制资源
在子系统对应的资源种类下,我们就可以看到该类资源具体可以被限制的方法。
- 查看配置文件
对 CPU 子系统来说,使用如下指令查看对应的配置文件:
ls /sys/fs/cgroup/cpu
(由于暂无对应展示系统,所以此处是引用自网上指令结果)我们会查看到这些文件:
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_releasecgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
目标参数
关于上面内容,cfs_period 和 cfs_quota 这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。配置限制参数
我们已经找到了目标配置,此刻我们可以向对应的配置文件写入限制参数即可。
指令如下:
echo 30000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
在每 100 ms 的时间里,被该控制组限制的进程只能使用 30 ms 的 CPU 时间,也就是说这个进程只能使用到 30% 的 CPU 带宽。
- 配置tasks
我们把被限制的进程的 PID(task-id) 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:
echo task-id > /sys/fs/cgroup/cpu/container/tasks
task-id
就是我们填写我们被限制的进程号。
Cgroup在容器空间内提供资源限制和报告功能。它们允许对哪些主机资源分配给容器以及何时分配容器进行精细控制。
3.3 Cgroups类型
常见的Cgroups管理的资源类型如下:
- CPU
- Memory
- Network Bandwidth
- Disk
- Priority
3.4 小结
Linux Cgroups
就是一个子系统目录加上一组资源限制文件的组合。它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的PID
填写到对应控制组的tasks
文件中就可以了。
四. 总结
容器,其实是一种特殊的进程而已。所以,Docker其实没有那么神话,也没有那么的高门槛。对比虚拟机,“敏捷”和“高性能”是容器最大的优势。
本文关于Namespace和Cgroups的讲解非常粗浅,Linux相关基础还是非常深的,终于明白Linux为啥这么优秀。
换句话说,容器本身没有价值,有价值的是“容器编排”,这将是后面文章关于Kubernetes的开始。
最后,欢迎关注我的博客:https://blog.wyatt.plus
Reference
https://medium.com/@kasunmaduraeng/docker-namespace-and-cgroups-dece27c209c7
https://coolshell.cn/articles/17010.html