容器技术 — Cgroups 与 Namespaces 支撑实现的操作系统虚拟化

news2024/10/6 20:39:25

目录

文章目录

  • 目录
  • 操作系统虚拟化(容器技术)的发展历程
  • Chroot
  • Cgroups
    • Cgroup Subsystems
    • Cgroup Filesystem
    • Cgroup Hierarchy
    • Cgroups 的操作规则
    • Cgroups 的代码实现
  • Namespaces
    • UTS namespace
    • PID namespace
    • IPC namespace
    • Mount namespace
    • Network namespace
    • User namespace
  • Docker 对 Cgroups 和 Namespaces 的应用
  • 参考文档

操作系统虚拟化(容器技术)的发展历程

1979 年,UNIX 的第 7 个版本引入了 Chroot 特性。Chroot 现在被认为是第一个操作系统虚拟化(Operating system level virtualization)技术的原型,本质是一种操作系统文件系统层的隔离技术。

2006 年,Google 发布了在 Linux 上运行的 Process Container(进程容器)技术,其目标是提供一种类似于 Virtual Mahine(计算机虚拟化技术)的、但主要针对 Process 的操作系统级别资源限制、优先级控制、资源审计能力和进程控制能力。

2007 年,Google 推动 Process Container 代码合入 Linux Kernel。同时由于 Container 这一命名在 Kernel 具有许多不同的含义,所以为了避免代码命名的混乱,就将 Process Container 更名为了 Control Groups,简称:Cgroups。

2008 年,Linux 社区整合了 Chroot、Cgroups、Namespaces、SELinux、Seccomp 等多种技术并发布了 LXC(Linux Container)v0.1.0 版本。LXC 通过将 Cgroups 的资源配额管理能力和 Namespace 的资源视图隔离能力进行组合,实现了完备的轻量级操作系统虚拟化。

2013 年 3 月 15 日,在加利福尼亚州圣克拉拉召开的 Python 开发者大会上,DotCloud 的创始人兼首席执行官 Solomon Hvkes 在一场仅 5 分钟的微型演讲中,首次发布了基于 LXC 封装的 Docker Container,并于会后将其源码开源并托管到 Github。

在这里插入图片描述

Chroot

Chroot 是一个可供 User Process 调用的 System Call 接口,可以让一个 Process 把指定的目录作为根目录(Root Directory),随后 Process 所有的文件系统操作都只能在这个指定目录中进行。故称之为 Change Root。

chroot() 的函数原型非常简单:

  • 调用权限:Root 用户。
  • 形参列表
    • path:一个指向字符串的指针,是一个绝对路径,表示将 Process 的根目录更改为的该目录路径。
  • 函数返回
    • 成功:返回 0;
    • 失败:返回 -1。
#include <unistd.h>

int chroot(const char *path);

需要注意的是,在更改了 Process 的根目录后,Process 只能访问新的根目录以及其子目录中的文件和资源。因此,在调用 chroot() 后,应确保 Process 所需要访问的所有文件和资源都存在于新的根目录下。

chroot() 目前主要主要用于:

  1. 安全隔离场景:限制将 Process 的访问范围,以此提高系统的安全性。
  2. 调试环境场景:创建一个与主系统隔离的环境,用于调试、测试和运行 Process。
  3. 系统救援场景:在 Linux 操作系统损坏或遭受攻击时,可以使用 chroot 将 Process 切换到受损系统的根目录中,以便进行修复和救援操作。

可见,chroot() 确实在 Linux File System(文件系统)层面提供了针对 Process 的隔离性,但并不提供完全的安全隔离,无法阻止其他方式的攻击。因此,要想实现 Processes 之间的安全隔离,还需要需采取其他安全措施。

Cgroups

Cgroups(Control Groups)是 Linux Kernel 提供的一种针对 User Process 或 Kernel Thread 的操作系统资源配额与管理技术,主要包括以下 4 个方面:

  1. 资源配额:限制进程对某一系统资源的用量配额。
  2. 优先级:当发生资源竞争时,优先保障哪些进程的资源使用。
  3. 审计:监控及报告进程对资源限制及使用。
  4. 控制:控制进程的状态,例如:运行、挂起、恢复。

Cgroups 设计与实现的核心概念如下图所示,包括:

  1. libcgroups:提供了一组编程接口库和应用程序。
  2. Tasks:User Process 和 Kernel Thread 的统一抽象。因为在 Kernel 中 User Process 或 Kernel Thread 实际上只通过 clone() SCI 传递的参数不同来进行区分,它们都使用了 task_struct 描述。
  3. Subsystems:可控资源的类型定义。
  4. Control Group(cgroup):是一个用于关联若干 Tasks 和 Subsystems 的资源控制组描述。下文中使用小写的 cgroup 来表述一个特定的 Control Group。
  5. Cgroup Filesystem:通过 VFS(虚拟文件系统)统一文件接口的方式向 Userspace 提供 cgroup 的配置入口。

在这里插入图片描述

Cgroup Subsystems

Cgroups 将多种可被管控的系统资源类型定义为 Subsystems(子系统),包括有:

  • cpu:限制 Task 的单颗 CPU Core 使用率。
  • cpuset:限制 Task 使用的 CPU Core 集合。
  • cpuacct:统计 Task 的 CPU 使用报告(Accounting)。
  • memory:限制 Task 使用的 Memory 容量。
  • hugetlb:限制 Task 的大页内存容量。
  • devices:限制 Task 能够访问的设备。
  • blkio:限制 Task 的 Block I/O 使用率。
  • net_cls:限制 Task 的网络数据包类型(Network Classifier)和 Net I/O 使用率。
  • net_prio:设置 Task 的网络流量(Network Traffic)处理优先级。
  • namespace:限制 Task 使用不同的 Namespaces。
  • freezer:挂起或者恢复指定的 Task。
  • perf_event:允许使用 perf 工具来进行监控。
  • pids:限制 cgroup 关联的 Tasks 数量。
  • 等等。

这些 Subsystems 的定义主要是为了提供相应的配置入口,而具体对系统资源进行限制的实现则是充分复用了 Kernel 自身的多种功能模块来完成,例如:

  • cpu Subsystem 依赖 Kernel Process Scheduler 实现。
  • memory Subsystem 依赖 Kernel Memory Manager 实现。
  • net_cls Subsystem 依赖 Kerne Traffic Control 实现。
  • 等等。

通过 CLI 可以查看系统中支持的 Cgroup Subsystems:

$ sudo yum install libcgroup-tools

$ lssubsys -a
cpuset
cpu,cpuacct
blkio
memory
devices
freezer
net_cls,net_prio
perf_event
hugetlb
pids
rdma

Cgroup Filesystem

Cgroups 通过 Kernel VFS(Virtual File System,虚拟文件系统)文件接口的方式向 Userspace 提供了统一的 cgroup 配置入口。

通过 CLI 可以查看当前 Cgroup Filesystem 的挂载路径与内容:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
...
tmpfs            16G     0   16G   0% /sys/fs/cgroup

$ ll /sys/fs/cgroup/
总用量 0
drwxr-xr-x. 4 root root  0 61 16:22 blkio
lrwxrwxrwx. 1 root root 11 61 16:22 cpu -> cpu,cpuacct
lrwxrwxrwx. 1 root root 11 61 16:22 cpuacct -> cpu,cpuacct
drwxr-xr-x. 4 root root  0 61 16:22 cpu,cpuacct
drwxr-xr-x. 2 root root  0 61 16:22 cpuset
drwxr-xr-x. 4 root root  0 61 16:22 devices
drwxr-xr-x. 2 root root  0 61 16:22 freezer
drwxr-xr-x. 2 root root  0 61 16:22 hugetlb
drwxr-xr-x. 4 root root  0 61 16:22 memory
lrwxrwxrwx. 1 root root 16 61 16:22 net_cls -> net_cls,net_prio
drwxr-xr-x. 2 root root  0 61 16:22 net_cls,net_prio
lrwxrwxrwx. 1 root root 16 61 16:22 net_prio -> net_cls,net_prio
drwxr-xr-x. 2 root root  0 61 16:22 perf_event
drwxr-xr-x. 4 root root  0 61 16:22 pids
drwxr-xr-x. 4 root root  0 61 16:22 systemd

可以看见,默认的情况下,Cgroups 会为 Subsystems 创建好它们各自的 Cgroup Filesytem,内含了用于设定资源配额、以及用于关联到若干个 Tasks 所需要的文件。如下所示。

$ ll /sys/fs/cgroup/memory/
总用量 0
-rw-r--r--.  1 root root 0 61 16:22 cgroup.clone_children
--w--w--w-.  1 root root 0 61 16:22 cgroup.event_control
-rw-r--r--.  1 root root 0 61 16:22 cgroup.procs
-r--r--r--.  1 root root 0 61 16:22 cgroup.sane_behavior
-rw-r--r--.  1 root root 0 61 16:22 memory.failcnt
--w-------.  1 root root 0 61 16:22 memory.force_empty
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.failcnt
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.limit_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.max_usage_in_bytes
-r--r--r--.  1 root root 0 61 16:22 memory.kmem.slabinfo
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.tcp.failcnt
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.tcp.limit_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.kmem.tcp.max_usage_in_bytes
-r--r--r--.  1 root root 0 61 16:22 memory.kmem.tcp.usage_in_bytes
-r--r--r--.  1 root root 0 61 16:22 memory.kmem.usage_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.limit_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.max_usage_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.memsw.failcnt
-rw-r--r--.  1 root root 0 61 16:22 memory.memsw.limit_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.memsw.max_usage_in_bytes
-r--r--r--.  1 root root 0 61 16:22 memory.memsw.usage_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.move_charge_at_immigrate
-r--r--r--.  1 root root 0 61 16:22 memory.numa_stat
-rw-r--r--.  1 root root 0 61 16:22 memory.oom_control
----------.  1 root root 0 61 16:22 memory.pressure_level
-rw-r--r--.  1 root root 0 61 16:22 memory.soft_limit_in_bytes
-r--r--r--.  1 root root 0 61 16:22 memory.stat
-rw-r--r--.  1 root root 0 61 16:22 memory.swappiness
-r--r--r--.  1 root root 0 61 16:22 memory.usage_in_bytes
-rw-r--r--.  1 root root 0 61 16:22 memory.use_hierarchy
-rw-r--r--.  1 root root 0 61 16:22 notify_on_release
-rw-r--r--.  1 root root 0 61 16:22 release_agent
drwxr-xr-x. 55 root root 0 61 16:23 system.slice
-rw-r--r--.  1 root root 0 61 16:22 tasks
drwxr-xr-x.  2 root root 0 61 16:23 user.slice

其中 cgroup 的 Core 接口文件以 cgroup 为前缀:

  • cgroup.clone_children:标识 Child cgroup 是否会继承 Parent cgroup。默认值为 0,表示不继承。
  • cgroup.procs:当是 Root cgroup 时,会记录该 Hierarchy 中所有的 PIDs。
  • 等等。

而 memory 为前缀的则为 Controller 接口文件,是 Cgroups 资源分配模型设计的控制器,包括:

  1. 权重(weight):按照权重比率来分配资源。
  2. 限制(max):限制资源被过度使用。
  3. 保护:可以是硬保护,也可能是软保护。
  4. 分配:资源分配参数。

其余还有一个管理接口文件,例如:

  • notify_on_release:标识当这个 cgroup 最后一个 Task 退出的时候是否执行 release_agent。
  • release_agent:是一个路径,用作 Task 退出后自动清理掉不再使用的 cgroup。
  • tasks:记录了关联到这个 cgroup 的 Tasks 列表。

Cgroup Hierarchy

Cgroups 使用 Filesystem 的方式来提供操作入口,所带来的另一个好处就是支持 Cgroup Hierarchy(层次化)组织形式,表现为一棵树状的结构。

当用户在 Parent cgroup 中创建了一个 Child cgroup 之后,Child cgroup 同样会自动创建所需要的配置文件,并可以配置是否继承 Parent cgroup 的相关配置。如下图所示。

$ mkdir /sys/fs/cgroup/memory/cgrp1/

$ ls /sys/fs/cgroup/memory/cgrp1/
cgroup.clone_children  memory.kmem.limit_in_bytes          memory.kmem.tcp.usage_in_bytes  memory.memsw.max_usage_in_bytes  memory.soft_limit_in_bytes  tasks
cgroup.event_control   memory.kmem.max_usage_in_bytes      memory.kmem.usage_in_bytes      memory.memsw.usage_in_bytes      memory.stat
cgroup.procs           memory.kmem.slabinfo                memory.limit_in_bytes           memory.move_charge_at_immigrate  memory.swappiness
memory.failcnt         memory.kmem.tcp.failcnt             memory.max_usage_in_bytes       memory.numa_stat                 memory.usage_in_bytes
memory.force_empty     memory.kmem.tcp.limit_in_bytes      memory.memsw.failcnt            memory.oom_control               memory.use_hierarchy
memory.kmem.failcnt    memory.kmem.tcp.max_usage_in_bytes  memory.memsw.limit_in_bytes     memory.pressure_level            notify_on_release

在这里插入图片描述

最后,在每个 cgroup 的 Filesystem 中都包含了一个 tasks 文件,用于保存关联到当前 cgroup 的 Tasks 列表。如果我们想向某个 cgroup 添加一个 User Process 时,就可以把它的 PID 写入到 tasks 文件中。如下:

$ cd /sys/fs/cgroup/memory/cgrp1    # 进入 cgrp1
$ echo 1029 > tasks                 # 将 PID 1029 的 Process 添加到 cgrp1 的 tasks 列表

Cgroups 的操作规则

用户在使用 Cgroups 时,必须按照一定的操作规则,否则会出现错误。操作规则的目的是为了避免资源配额的配置存在冲突。

  1. 一个 Hierarchy 可以 Attach 多个 Subsystems,如下图将 cpu 和 memory Subsystems Attached 到了同一个 Hierarchy。
    在这里插入图片描述

  2. 一个已经被 Attached 的 Subsystem 只能被再次 Attach 在一个空的 Hierarchy 上,不能 Attach 到一个已经 Attached 了其他 Subsystems 的 Hierarchy 上,如下图 cpu Subsystem 已经 Attached 到了 Hierarchy A,并且 memory Subsystem 已经附加到了 Hierarchy B。因此 cpu Subsystem 不能再 Attach 到 Hierarchy B,只能 Attach 另一个空的 Hierarchy C 上。
    在这里插入图片描述

  3. 每个 Task 只能在同一个 Hierarchy 的唯一一个 cgroup tasks 里,并且可以在多个不同 Hierarchy 的 cgroup tasks 里。如下图,这样保证了对于一个 Task 的同一种 cgroup 配额是唯一的。
    在这里插入图片描述

  4. 子进程在被 fork 出时自动继承父进程所在 cgroups,但是 fork 之后就可以按需调整到其他 cgroup,如下图:
    在这里插入图片描述

Cgroups 的代码实现

现在回头再看 Kernel 中对 cgroup 的声明定义,它被设计成了一个树数据结构:

struct cgroup {
    ...
    // 下面 3 个字段把 cgroup 设计成了一个树数据结构
    struct list_head sibling;   // 兄弟节点
    struct list_head children;  // 子节点
    struct cgroup *parent;      // 父节点

    struct dentry *dentry;      // cgroup 对应的目录对象

    // cgroup 关联的 subsystems 对象
    struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; 
    ...
};

在这里插入图片描述

默认情况下,在 Kernel 启动过程中,会自动实例化一个 rootnode(根节点),并将所有 Subsystems 的 cgroup FS 关联到此 rootnode。

static struct cgroupfs_root rootnode;

struct cgroupfs_root {
    struct super_block *sb;            // Root cgroup FS 的挂载点(VFS 使用)
    ...
    struct list_head subsys_list;      // Root cgroup 绑定的 Subsystems 列表
    struct cgroup top_cgroup;          // Root cgroup 对象
    int number_of_cgroups;             // Root cgroup 拥有的 cgroups 的数量
    ...
};

如果用户想手动的把 Subsystems 挂在到其他 cgroup FS,也可以使用 mount 命令来进行挂载,如下命令所示:

$ mount -t cgroup -o memory memory /sys/fs/cgroup/memory1

另外,cgroup 中的 cgroup_subsys_state 字段用于关联到一个 Subsystems State(子系统资源统计结构体)列表,再关联到若干个具体的 Subsystems。

struct cgroup_subsys_state {
    struct cgroup *cgroup; // 指向 cgroup 对象
    atomic_t refcnt;       // 引用计数器
    unsigned long flags;   // 标志位
};

struct mem_cgroup {
    // 资源统计对象通用部分
    struct cgroup_subsys_state css;

    // 资源统计对象私有部分
    struct res_counter res;  // 用于统计 tasks 的内存使用情况
    struct mem_cgroup_lru_info info;
    int prev_priority;
    struct mem_cgroup_stat stat;
};

在这里插入图片描述

可见 cgroup 和 Subsystems 是一对多的关系,如下图所示。
在这里插入图片描述

同时又由于一个 Task 可以关联到多个 cgroups 中,最终实现了 Tasks 和 Subsystems 之间的多对多关系。如下图所示:

  • ProcessA 属于 /sys/fs/cgroup/memory/cgrp1/cgrp3 和 /sys/fs/cgroup/cpu/cgrp2/cgrp3,所以 ProcessA 就关联了 mem_groupA 和 task_groupA 这两个 Cgroup Subsystems State。
  • ProcessB 属于 /sys/fs/cgroup/memory/cgrp1/cgrp4 和 /sys/fs/cgroup/cpu/cgrp2/cgrp3,所以 ProcessB 就关联了 mem_groupB 和 task_groupA 这两个 Cgroup Subsystems State。

在这里插入图片描述

在 Task 的 task_struct 中通过 css_set 字段来记录自己所关联的 Cgroup Subsystems State 列表,如下:

struct task_struct {
    ...
    struct css_set *cgroups;
    ...
};

struct css_set {
    ...
    // 用于收集不同 cgroup 的资源统计对象
    struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
};

最终 User Process 和 Cgroups 之间就构成了一个 M×N Linkage 的映射关系结构。如下图所示。

在这里插入图片描述

Namespaces

Linux Namespaces(命名空间)是一种操作系统层级的资源视图隔离技术,能够将 Linux 的全局资源,划分为 Namespace 范围内可见的资源。

Namespaces 具有多种类型,基本上涵盖了构成一个操作系统所需要的基本元素:

  1. UTS namespace(系统主机名)
  2. Time namespace(系统时间)
  3. PID namespace(系统进程号)
  4. IPC namespace(系统进程间通信)
  5. Mount namespace(系统文件系统)
  6. Network namespace(系统网络)
  7. User namespace(系统用户权限)
  8. Cgroup namespace(系统 Cgroup)

User Process 是 Namespace 的主要服务对象,与之相关的 SCI 主要有 3 个:

  1. clone():创建一个 Process,同时设置 Namespace Instance 的类型参数。
  2. setns():把一个 Process 加入到指定的 Namespace Instance。
  3. unshare():把一个 Process 脱离指定的 Namespace Instance。

如下图所示,每种 Namespaces 都拥有各自的 clone 类型参数:
在这里插入图片描述

通过 /proc/{pid}/ns 文件可以查看指定 Process 运行在哪些 Namespaces Instance 中,并且每个 Namespace Instance 都具有一个唯一的标识。

$ ls -l --time-style='+' /proc/$$/ns
总用量 0
lrwxrwxrwx. 1 root root 0  ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0  mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0  net -> net:[4026531956]
lrwxrwxrwx. 1 root root 0  pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0  user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0  uts -> uts:[4026531838]

最终,用户可以通过创建多种不同类型的 Namespaces Instance 来提供的操作系统资源的隔离,再结合创建多种不同类型的 cgroups 来提供操作系统的资源配额,就构成了一个最基本的操作系统容器,即:Process Container。

UTS namespace

UTS namespace 为 Container 提供了 Hostname 和 Domain Name 的隔离。

Container 中的 Process 可以根据需要调用 sethostname 和 setdomainname 指令来进行配置,让每个 Container 都可以被视为网络中的一个独立的节点。

PID namespace

PID namespace 为 Container 提供了进程号的隔离。

每个 Containers 都拥有自己的进程环境,Container 的 init Process 都是 PID 1 号进程,它作为所有子进程的父进程。要想做到进程的隔离,首先需要创建出 PID 1 号进程,它具有以下特性:

  • 如果某个子进程脱离了父进程(父进程没有 wait 它),那么 init Process 就会负责回收资源并结束这个子进程。
  • 如果 init Process 被终止,那么 Kernel 就会调用 SIGKILL 终止此 PID namespace 中的所有进程。

IPC namespace

IPC namespace 为 Container 提供了 IPC(进程间)通信机制的隔离,包括信号量、消息队列、共享内存等机制。

每个 Containers 都拥有以下 /proc 文件接口:

  • /proc/sys/fs/mqueue:POSIX Message Queues 接口类型;
  • /proc/sys/kernel:System V IPC 接口类型;
  • /proc/sysvipc:System V IPC 接口类型。

Mount namespace

Mount namespace 为 Container 提供了 Filesystem 挂载点的隔离,继而实现了 VFS 的隔离。

每个 Containers 都拥有以下 /proc 文件接口,可以构成一个独立的 rootfs(Root 文件系统):

  • /proc/[pid]/mounts
  • /proc/[pid]/mountinfo
  • /proc/[pid]/mountstats

实际上,Mount namespace 是基于 Chroot 的不断改良而开发出来的。为 Container 创建的 rootfs 只是一个操作系统发行版所包含的文件、目录和配置,并不包括 Kernel 的文件。

Network namespace

Network namespace 为 Container 提供了网络资源的隔离,包括:

  • Network devices(网络设备)
  • IPv4 and IPv6 protocol stacks(IPv4、IPv6 的协议栈)
  • IP routing tables(IP 路由表)
  • Firewall rules(防火墙规则)
  • Sockets 套接字
  • /proc/[pid]/net
  • /sys/class/net
  • /proc/sys/net

需要注意的是,同一个 Network device 只能存在于一个 Namespace Instance 中,所以常常结合虚拟网络设备来使用。

在这里插入图片描述

User namespace

User namespace 为 Container 提供了用户权限和安全属性相关的隔离,包括:User ID、User Group ID、Root 目录以及特殊的权限。

每个 Containers 都拥有以下 /proc 文件接口:

  • /proc/[pid]/uid_map
  • /proc/[pid]/gid_map

Docker 对 Cgroups 和 Namespaces 的应用

当我们创建了一个 Docker Container 之后就可以查看这个 Container 所具有的 cgroups 和 namespaces 了。

  1. 查看 Container 的 ID(cfca1212d140)和 PID(2240)配置。
$ docker ps
CONTAINER ID   IMAGE                   COMMAND   CREATED         STATUS       PORTS     NAMES
cfca1212d140   centos:centos7.9.2009   "bash"    18 months ago   Up 2 hours             vim-ide

$ docker inspect --format='{{.State.Pid}}' cfca1212d140
2240
  1. 查看 Container 的 cgroups 配置。
$ ll /sys/fs/cgroup/memory/docker/
总用量 0
drwxr-xr-x. 2 root root 0 62 03:40 cfca1212d1407a89632a439e974e246d1f6edd0bbef9079f06addf2613e1d46f

$ cat /sys/fs/cgroup/memory/docker/cfca1212d1407a89632a439e974e246d1f6edd0bbef9079f06addf2613e1d46f/cgroup.procs 
2240

$ cat /sys/fs/cgroup/memory/docker/cfca1212d1407a89632a439e974e246d1f6edd0bbef9079f06addf2613e1d46f/memory.limit_in_bytes
9223372036854771712
  1. 查看 Container 的 namespaces 配置。
$ ls -l --time-style='+' /proc/2240/ns
总用量 0
lrwxrwxrwx. 1 root root 0  ipc -> ipc:[4026532433]
lrwxrwxrwx. 1 root root 0  mnt -> mnt:[4026532431]
lrwxrwxrwx. 1 root root 0  net -> net:[4026531956]
lrwxrwxrwx. 1 root root 0  pid -> pid:[4026532434]
lrwxrwxrwx. 1 root root 0  user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0  uts -> uts:[4026532432]

参考文档

  • https://mp.weixin.qq.com/s/EdRVEJ0i5j9eHwd8QK-cDg
  • https://juejin.cn/post/6921299245685276686
  • https://zhuanlan.zhihu.com/p/388101355

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/612112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Blender2023超好用的插件合集,还不抓紧用起来

Blender对于艺术家或电影制作人来说不再是一个陌生的名字。Blender 拥有一套全面的工具和一个用户友好的界面&#xff0c;使初学者和专业人士都可以使用它。全球开发人员和用户社区不断更新新功能和改进。此外&#xff0c;有这么多可用的工具和插件&#xff0c;Blender可以定制…

项目经理高效时间管理6大原则及技巧

1、 ( 10 2 ) * 5法则 项目经理以10分钟为一个周期&#xff0c;每个周期休息2分钟&#xff0c;这样1小时重复5次&#xff0c;就可以保障我们目标明确但精神和身体上的精力不会透支。 10分钟周期内&#xff0c;需要全心全意做一件事&#xff0c;进入全身心投入工作状态&#xf…

Kerberos从入门到精通以及案例实操系列(二)

5、安全集群使用说明 5.1、用户要求 具体要求以下使用说明均基于普通用户&#xff0c;安全集群对用户有以下要求&#xff1a; 集群中的每个节点都需要创建该用户该用户需要属于hadoop用户组需要创建该用户对应的Kerberos主体 实操&#xff0c;此处以atguigu用户为例&#x…

Spring Boot 系统初始化器详解

Spring Boot 3.x系列文章 Spring Boot 2.7.8 中文参考指南(一)Spring Boot 2.7.8 中文参考指南(二)-WebSpring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解 自定义系统初始化器 Spring Boot 有多种加载自定义初始化器的方法&am…

账号长久不用、归属不明......企业要如何管理这些失控的账号?

据报道&#xff0c;谷歌将于今年底开始删除2年未使用个谷歌个人账号。理由是&#xff0c;谷歌发现&#xff0c;如果一个账户在一定时间内未被使用&#xff0c;那么该账户被入侵的概率更大。 这些长时间未使用的账号使用的密码一般都是比较老的或重用的密码&#xff0c;关联密码…

Linux之tar归档命令

目录 Linux之tar归档命令 定义 语法格式 参数及作用 常用选项 创建&#xff08;非压缩的&#xff09;包文件 ​编辑 创建带压缩的包文件 列出包文件中的文件列表 提取包文件到指定目录 tar打包时排除 --exclude -X或--exclude-from Linux之tar归档命令 定义 用于打…

全面的软件测试

1 全过程的软件测试图解 传统的软件测试&#xff0c;开发人员完成任务之后&#xff0c;最后交付给测试人员&#xff0c;这种模式下&#xff0c;测试人员不能及早发现需求阶段的缺陷&#xff0c;同时测试工作的开展也滞后了&#xff0c;产品质量得不到有效的过程控制和分析&…

echarts折线图使用记录

1项目中引入echarts文档api介绍&#xff0c;链接地址如下 https://echarts.apache.org/handbook/zh/basics/import 2 官网基础样例介绍,链接地址如下 https://echarts.apache.org/handbook/zh/get-started/ 3 基本折线图介绍内容及链接 3.1 最简单的折线图 3.2 笛卡尔坐标系中…

【Python】Step Into Python Class

【Python】Step Into Python Class Before All Python作为一门面向过程兼容面向对象的语言&#xff0c;在面向对象中&#xff0c;使用class关键字来申明一个类。 But&#xff0c;是不是应该深入考虑一下这个class的底层实现过程呢&#xff1f;&#xff08;不考虑CPython&…

msvcp110.dll丢失怎么修复(一键修复办法)

msvcp110.dll是C编程中非常重要的库文件之一。它实现了运行时库的大部分功能&#xff0c;并提供了许多标准库和其他功能的具体实现&#xff0c;如多线程编程和IO操作等。提高程序的运行效率和稳定性。下面是详细解决msvcp110.dll丢失问题的方法跟msvcp110.dll文件的介绍。 msvc…

npm install报错 -> npm ERR! Unexpected token ‘.‘ 报错解决办法

原因&#xff1a; 我遇到这个问题的场景是用nvm1.1.7的版本安装了16.x以上的node, 然后再下载依赖的时候就报错了 总结一下就是nvm版本太低了&#xff0c;他的里面没有集成高版本node导致的 解决&#xff1a; 我们把nvm版本换到最新的就可以了 1. 卸载掉当前所有的node nvm …

ABIDE Preprocessed 结构态MRI数据集介绍及下载

ABIDE数据集介绍及下载 ABIDE Prerocessed项目是在ABIDE I 项目的基础上发展而来&#xff0c;主要是对ABIDE I中采集到的原始数据进行了一定的预处理和初步的特征提取。针对于fMRI和sMRI数据有着不同的处理方式&#xff0c;本次主要对其中提供的sMRI预处理结果进行介绍&#xf…

Python程序设计基础:标识符、变量与赋值、输入输出

文章目录 一、标识符二、变量与赋值三、输入输出 一、标识符 Python对每个标识符的命名存在要求&#xff1a; 1、每个标识符必须以字母或下划线“_”开头&#xff0c;后跟字母、数字或下划线的任意序列。根据这个规则&#xff0c;以下都是Python中的合法名称&#xff1a;a&…

excel如何实现识别文本在对应单元格填上数据?

要实现 Excel 识别文本在对应单元格填上数据&#xff0c;有以下两种方法&#xff1a; 方法一&#xff1a;使用 VLOOKUP 函数 1. 在 Excel 工作表中&#xff0c;输入一个表格&#xff0c;列名为对应的文本&#xff0c;行名为不同条目。 2. 准备输入数据&#xff0c;在一个新的…

python使用requests+excel进行接口自动化测试

在当今的互联网时代中&#xff0c;接口自动化测试越来越成为软件测试的重要组成部分。Python是一种简单易学&#xff0c;高效且可扩展的语言&#xff0c;自然而然地成为了开发人员的首选开发语言。而requests和xlwt这两个常用的Python标准库&#xff0c;能够帮助我们轻松地开发…

LInux之find查找

目录 LInux之find查找 定义 详解 格式 参数及作用 详解 1.按照文件名搜索 2.按照文件大小搜索 3.按照修改时间搜索 4.按照权限搜索 5.按照所有者和所属组搜索 6.按照文件类型搜索 7.逻辑运算符 8.其他选项 -exec参数 获取到该目录中所有以host开头的文件列表 如在…

【测试入门】测试用例经典设计方法 —— 因果图法

01、因果图设计测试用例的步骤 1、分析需求 阅读需求文档&#xff0c;如果User Case很复杂&#xff0c;尽量将它分解成若干个简单的部分。这样做的好处是&#xff0c;不必在一次处理过程中考虑所有的原因。没有固定的流程说明究竟分解到何种程度才算简单&#xff0c;需要测试…

3D打印机分类汇总

1 根据市场定位分类 当今市面上应用比较多的3D打印机是SLS、SLA、DLP、FDM四种3D打印机&#xff0c;按照用途可分为两类&#xff1a;一类是高精度工业打印机&#xff0c;比如SLA、DLP、SLS&#xff1b;一类是以FDM、SLA&#xff08;用于工业打印机更多&#xff09;为主的桌面级…

NRF52832空中升级DFU

1.工具环境搭建 gcc-arm-none-eabi编译环境&#xff1a;GCC编译环境 Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer mingw 平台&#xff08;win版的Linux命令行&#xff09; Download MinGW - Minimalist GNU for Windows micro-ecc-master源码 GitHu…

永不磨灭的设计模式(23种设计模式全集)

永不磨灭的设计模式 概述七大基本原则23种设计模式1、单例模式2、工厂(方法)模式3、抽象工厂模式4、原型模式5、建造者模式6、适配器模式7、桥接模式8、组合模式9、装饰器模式10、外观模式11、享元模式12、代理模式13、责任链模式14、命令模式15、迭代器模式16、中介者模式17、…