Chroot简介:
早期的容器技术使用chroot作为系统目录隔离的手段。在此之前先介绍什么是chroot。
之前已经存在了chroot,chroot全称为change root directory更改root目录,在使用之后能以指定位置作为/的位置,这使得系统读取的目录不再是旧系统根下而是新的根下。
Chroot优点 :
- 增加了系统的安全性,限制了用户的权力
- 在经过 chroot 之后,在新根下将访问不到旧系统的根目录结构和文件,这样就增强了系统的安全性。这个一般是在登录 (login) 前使用 chroot,以此达到用户不能访问一些特定的文件。
- 建立一个与原系统隔离的系统目录结构,方便用户的开发
- 使用 chroot 后,系统读取的是新根下的目录和文件,这是一个与原系统根下文件不相关的目录结构。在这个新的环境中,可以用来测试软件的静态编译以及一些与系统不相关的独立开发。
- 切换系统的根目录位置,引导 Linux 系统启动以及急救系统等。
chroot 的作用就是切换系统的根位置,而这个作用最为明显的是在系统初始引导磁盘的处理过程中使用,从初始 RAM 磁盘 (initrd) 切换系统的根位置并执行真正的 init。另外,当系统出现一些问题时,我们也可以使用 chroot 来切换到一个临时的系统。
演示详细见网址chroot的用法 - charlieroro - 博客园 (cnblogs.com)
Chroot缺点:
那它也是存在局限性的,例如它依赖一台unix系统,并且只是对系统目录进行隔离,不对进程以及网络资源进行隔离。
检验进程空间,在新根下进行ping的操作,在新的界面使用ps aux|grep ping可以看到本质还是在跟系统上进行的。以上就是chroot存在的缺陷。
Cgroup简介:
cgroup 是 Linux 内核的一个功能,用来限制、控制与分离一个进程组的资源(如CPU、内存、磁盘输入输出,网络等)。我们可以将系统资源按照特定的百分比分配给cgroup。剩余的资源可以供其他cgroup或者进程使用。
- 资源限制:限制进程使用资源上限
- 优先级控制:不同组可以有不同优先级,比如CPU使用和磁盘IO吞吐
- 审计:计算group资源使用情况,可以用来计费
- 控制:挂起一组进程,或者重启一组进程
cgroup核心概念:
cgroup 是一种分层组织进程的机制, 沿层次结构以受控的方式分配系统资源。
- task:在 linux 系统中,内核本身的调度和管理并不对进程和线程进行区分,只是根据 clone 时传入的参数的不同来从概念上区分进程和线程。这里使用 task 来表示系统的一个进程或线程。
- subsystem:子系统,具体的资源控制器,控制某个特定的资源使用。比如 CPU 子系统可以控制 CPU 时间,memory 子系统可以控制内存使用量
- cgroup:cgroups 中的资源控制以 cgroup 为单位实现。Cgroup 表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个 cgroup,也可以从某个 cgroup 迁移到另一个 cgroup
- hierarchy:层级树,一系列 cgroup 组成的树形结构。每个节点都是一个 cgroup,cgroup 可以有多个子节点,子节点默认会继承父节点的属性。系统中可以有多个 hierarchy
虽然 cgroup 支持 hierarchy,允许不同的子资源挂到不同的目录,但是多个树之间有各种限制,增加了理解和维护的复杂性。在实际使用中,所有的子资源都会统一放到某个路径下(比如 ubuntu20 的 /sys/fs/cgroup/)
层级树hierarchy,子系统subsystem,cgroup控制组,task任务的关系:
规则一:层级树一对多子系统,子系统为红色部分
规则二:子系统一对一层级树
规则三:系统每次新建一个hierarchy时,该系统上的所有task默认构成了这个新建的hierarchy的初始化cgroup,这个cgroup也称为root cgroup。对于你创建的每个hierarchy,task只能存在于其中一个cgroup中,即一个task不能存在于同一个hierarchy的不同cgroup中,但是一个task可以存在在不同hierarchy中的多个cgroup中。如果操作时把一个task添加到同一个hierarchy中的另一个cgroup中,则会从第一个cgroup中移除
如下图,cpu和memory subsystem被附加到cpu_mem_cg的hierarchy。而net_cls subsystem被附加到net_cls hierarchy。并且httpd进程被同时加到了cpu_mem_cg hierarchy的cg1 cgroup中和net hierarchy的cg3 cgroup中。并通过两个hierarchy的subsystem分别对httpd进程进行cpu,memory及网络带宽的限制。
规则四:系统中的任何一个task(Linux中的进程)fork自己创建一个子task(子进程)时,子task会自动的继承父task cgroup的关系,在同一个cgroup中,但是子task可以根据需要移到其它不同的cgroup中。父子task之间是相互独立不依赖的。
子资源系统subsystem
- Block IO(blkio):限制块设备(磁盘、SSD、USB 等)的 IO 速率
- CPU Set(cpuset):限制任务能运行在哪些 CPU 核上
- CPU Accounting(cpuacct):生成 cgroup 中任务使用 CPU 的报告
- CPU (CPU):限制调度器分配的 CPU 时间
- Devices (devices):允许或者拒绝 cgroup 中任务对设备的访问
- Freezer (freezer):挂起或者重启 cgroup 中的任务
- Memory (memory):限制 cgroup 中任务使用内存的量,并生成任务当前内存的使用情况报告
- Network Classifier(net_cls):为 cgroup 中的报文设置上特定的 classid 标志,这样 tc 等工具就能根据标记对网络进行配置
- Network Priority (net_prio):对每个网络接口设置报文的优先级
- perf_event:识别任务的 cgroup 成员,可以用来做性能分析
cgroups文件系统
Linux 使用了多种数据结构在内核中实现了 cgroups 的配置,关联了进程和 cgroups 节点,那么 Linux 又是如何让用户态的进程使用到 cgroups 的功能呢? Linux内核有一个很强大的模块叫 VFS (Virtual File System)。 VFS 能够把具体文件系统的细节隐藏起来,给用户态进程提供一个统一的文件系统 API 接口。 cgroups 也是通过 VFS 把功能暴露给用户态的,cgroups 与 VFS 之间的衔接部分称之为 cgroups 文件系统。下面先介绍一下 VFS 的基础知识,然后再介绍下 cgroups 文件系统的实现
VFS简介:
- 超级块对象(superblock object),用于存放已经注册的文件系统的信息。比如ext2,ext3等这些基础的磁盘文件系统,还有用于读写socket的socket文件系统,以及当前的用于读写cgroups配置信息的 cgroups 文件系统等。
- 索引节点对象(inode object),用于存放具体文件的信息。对于一般的磁盘文件系统而言,inode 节点中一般会存放文件在硬盘中的存储块等信息;对于socket文件系统,inode会存放socket的相关属性,而对于cgroups这样的特殊文件系统,inode会存放与 cgroup 节点相关的属性信息。这里面比较重要的一个部分是一个叫做 inode_operations 的结构体,这个结构体定义了在具体文件系统中创建文件,删除文件等的具体实现。
- 文件对象(file object),一个文件对象表示进程内打开的一个文件,文件对象是存放在进程的文件描述符表里面的。同样这个文件中比较重要的部分是一个叫 file_operations 的结构体,这个结构体描述了具体的文件系统的读写实现。当进程在某一个文件描述符上调用读写操作时,实际调用的是 file_operations 中定义的方法。 对于普通的磁盘文件系统,file_operations 中定义的就是普通的块设备读写操作;对于socket文件系统,file_operations 中定义的就是 socket 对应的 send/recv 等操作;而对于cgroups这样的特殊文件系统,file_operations 中定义的就是操作 cgroup 结构体等具体的实现。
- 目录项对象(dentry object),在每个文件系统中,内核在查找某一个路径中的文件时,会为内核路径上的每一个分量都生成一个目录项对象,通过目录项对象能够找到对应的 inode 对象,目录项对象一般会被缓存,从而提高内核查找速度
使用cgroups
cgroup内核功能没有提供任何系统调用接口,而是Linux vfs的一个实现,所以可以用文件系统的方式操作
- 使用 cgroups 提供的虚拟文件系统,直接通过创建、读写和删除目录、文件来控制 cgroups
- 使用命令行工具,比如 libcgroup 包提供的 cgcreate、cgexec、cgclassify 命令
- 使用 rules engine daemon 提供的配置文件
- 当然,systemd、lxc、docker 这些封装了 cgroups 的软件也能让你通过它们定义的接口控制 cgroups 的内容
cgroup的文件系统
$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
在 Ubuntu 18.04 的机器上,cgroups 已经挂载到文件系统上了,可以通过 mount
命令查看
$ mount -t cgroup -o cpu,cpuset,memory cpu_and_mem /cgroup/cpu_and_mem
上述命令表示把 cpu、cpuset、memory 三个子资源 mount 到 /cgroup/cpu_and_mem
目录下
每个 cgroup 目录下面都会有描述该 cgroup 的文件,除了每个 cgroup 独特的资源控制文件,还有一些通用的文件
- tasks:当前 cgroup 包含的任务(task)pid 列表,把某个进程的 pid 添加到这个文件中就等于把进程移到该 cgroup
- cgroup.procs:当前 cgroup 中包含的 thread group 列表,使用逻辑和 tasks 相同
- notify_on_release:0 或者 1,是否在 cgroup 销毁的时候执行 notify。如果为 1,那么当这个 cgroup 最后一个任务离开时(退出或者迁移到其他 cgroup),并且最后一个子 cgroup 被删除时,系统会执行 release_agent 中指定的命令
- release_agent:需要执行的命令
subsys子资源参数详解
每个 subssytem 负责系统的一部分资源管理,又分别提供多个参数可以控制,每个参数对应一个文件,往文件中写入特定格式的内容就能控制该资源
参考
A.8. net_cls Red Hat Enterprise Linux 7 | Red Hat Customer Portal
浅谈Linux Cgroups机制 - 知乎 (zhihu.com)
原理
(212条消息) 【docker 底层知识】cgroup 原理分析_张忠琳的博客-CSDN博客_cgroup原理
(212条消息) CGroup的原理和使用_书笑生的博客-CSDN博客_cgroup原理
(212条消息) Linux容器:cgroup,namespace原理与实现_rtoax的博客-CSDN博客_cgroup namespace