当前位置: 首页 > article >正文

【Linux】资源隔离机制 — 命名空间(Namespace)详解

文章目录

  • 一、什么是Namespace
    • 1.1 Namespace 的作用与原理
    • 1.2 命名空间的操作
    • 1.3 常见命名空间
    • 1.4 如何隔离两个容器中的进程
  • 二、相关命令
    • 2.1 dd 命令
    • 2.2 mkfs 命令
    • 2.3 df 命令
    • 2.4 mount 命令
    • 2.5 unshare 命令
  • 三、实际操作
    • 3.1 PID 隔离
    • 3.2 Mount 隔离


一、什么是Namespace

Namespace(命名空间) 是 Linux 内核提供的一种资源隔离机制

  • 它允许将系统资源分隔成多个虚拟的“空间”,每个命名空间内的进程只能访问该命名空间下的资源,而不能访问其他命名空间中的资源。

  • 通过 namespace,不同的进程可以在同一个操作系统内共享硬件资源,但又能感知到各自独立的环境。具体来说,namespace 可以将一个或多个进程的资源隔离到同一个命名空间中,确保这些进程只能看到和操作该命名空间内的资源。


1.1 Namespace 的作用与原理

Linux namespaces对全局系统资源的一种封装与隔离。处于不同 namespace 的进程拥有独立的全局系统资源。修改某个 namespace 中的资源(如网络、PID、文件系统等)只会影响该命名空间中的进程,不会影响其他命名空间中的进程。

例如:

  • 一个进程可能在一个独立的网络命名空间中运行,无法看到其他命名空间的网络接口和路由。
  • 另一个进程可能在不同的用户命名空间中运行,从而拥有不同的用户ID和权限。

1.2 命名空间的操作

Linux 提供了几个系统调用来操作命名空间,常用的 API 包括:

  • clone():创建新进程并指定要使用的命名空间。
  • setns():使当前进程加入指定的命名空间。
  • unshare():将当前进程从现有的命名空间中分离出来,并创建新的命名空间。

在使用这些 API 时,通常需要指定一些参数来选择隔离的资源类型。

例如,可以通过按位或 | 组合多个命名空间类型来同时隔离多个资源。


1.3 常见命名空间

下面是一些常见的命名空间及其对应的系统调用参数和功能:

命名空间系统调用参数被隔离的全局系统资源引入内核版本
UTSCLONE_NEWUTS主机名和域名2.6.19
IPCCLONE_NEWIPC信号量、消息队列和共享内存(进程间通信)2.6.19
PIDCLONE_NEWPID进程编号2.6.24
NetworkCLONE_NEWNET网络设备、网络栈、端口等2.6.29
MountCLONE_NEWNS文件系统挂载点2.4.19
UserCLONE_NEWUSER用户和用户组3.8

下面是上面的命名空间容器下的隔离效果:

  1. UTS:每个容器可以拥有独立的主机名和域名,容器内的进程只看到自己的 hostname,互不干扰。
  2. IPC:同一个 IPC 命名空间内的进程可以相互通信,而不同的 IPC 命名空间中的进程则无法通信。
  3. PID:每个 PID 命名空间内的进程有独立的进程编号,因此每个容器可以有一个 PID 为 1 的 root 进程。
  4. Network:每个容器拥有独立的网络环境,包括网络设备、IP 地址、路由表、端口号等。容器内的网络与主机或其他容器的网络互相隔离。
  5. Mount:每个容器拥有独立的文件系统层次结构,容器内的进程只能看到自己的文件系统挂载点。
  6. User:每个容器内的进程可以拥有独立的用户和组 ID,与主机或其他容器的用户和组 ID 隔离。

1.4 如何隔离两个容器中的进程

在容器化环境中,如果我们要隔离容器 A 和容器 B 中的进程,需要从以下几个方面进行资源隔离:

  1. PID 隔离

    • 容器内的进程需要拥有独立的 PID(进程编号)。通过 PID 命名空间,容器 A 和容器 B 内的进程将有独立的 PID 系统,彼此无法相互识别或干扰。
  2. IPC 隔离

    • 容器 A 和容器 B 中的进程不能共享信号量、消息队列或共享内存等 IPC 资源。通过 IPC 命名空间,每个容器内的进程只能与同一容器中的进程进行通信,而无法访问其他容器的 IPC 资源。
  3. Mount 隔离

    • 容器内的文件系统应该是独立的,这样容器 A 的进程不能访问容器 B 的文件系统。通过 Mount 命名空间,每个容器的文件系统挂载点是独立的,不同容器之间的文件系统层次结构互不干扰。
  4. 网络隔离

    • 容器 A 和容器 B 的网络应该是独立的,容器 A 无法访问容器 B 的网络接口、端口或网络资源。通过 Network 命名空间,每个容器可以拥有独立的网络设备、IP 地址、路由表等资源。
  5. 主机名隔离

    • 每个容器应该有自己的主机名和域名,这样容器 A 内的进程无法读取容器 B 的主机名。通过 UTS 命名空间,每个容器可以有独立的主机名和域名。

二、相关命令

2.1 dd 命令

Linux 下 dd 命令用于读取、转换并输出数据。

dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出;

  • 语法
dd OPTION
  • 参数 / 选项:
参数说明
if=文件名输入文件名,默认为标准输入(指定源文件)。
of=文件名输出文件名,默认为标准输出(指定目标文件)。
ibs=bytes一次读取 bytes 个字节,即指定输入块的大小。
obs=bytes一次输出 bytes 个字节,即指定输出块的大小。
bs=bytes同时设置读取和输出的块大小为 bytes 个字节。
cbs=bytes一次转换 bytes 个字节,即指定转换缓冲区的大小。
skip=blocks从输入文件开头跳过 blocks 个块后再开始复制。
seek=blocks从输出文件开头跳过 blocks 个块后再开始复制。
count=blocks仅复制 blocks 个块,块大小由 ibs 指定。
conv=<关键字>文件转换方式,支持以下关键字:
ascii:将 EBCDIC 转换为 ASCII
ebcdic:将 ASCII 转换为 EBCDIC
ibm:将 ASCII 转换为 IBM 格式的 EBCDIC
block:将每行转换为长度为 cbs 的块,短于 cbs 的部分用空格填充
unblock:使每行的长度为 cbs,短于 cbs 的部分用空格填充
lcase:将大写字符转换为小写字符
ucase:将小写字符转换为大写字符
swap:交换输入中的每对字节
noerror:出错时不停止继续执行
notrunc:不截断输出文件
sync:将每个输入块填充到 ibs 字节,不足部分用 NUL 字符补齐
--help显示帮助信息
--version显示版本信息
  • 案例

    # 生成一个大小为 80MB 的空白镜像文件 image.img,内容是 0 字节。
    dd if=/dev/zero of=image.img bs=8k count=10240
    # 将 testfile 文件中的所有英文字母转换为大写,然后转成为 testfile_1 文件
    dd if=testfile_2 of=testfile_1 conv=ucase
    

2.2 mkfs 命令

mkfs 命令 用于 在设备上创建 Linux 文件系统,即格式化,比如我们使用 U 盘的时候可以格式化。

  • 语法
mkfs [-V] [-t fstype] [fs-options] filesys [blocks]
  • 参数解释
-t fstype:指定要建立何种文件系统;如 ext3, ext4filesys :指定要创建的文件系统对应的设备文件名;
blocks:指定文件系统的磁盘块数。
-V : 详细显示模式
fs-options:传递给具体的文件系统的参数
  • 案例

    # 将 sda6 分区格式化为 ext4 格式
    mkfs -t ext4 /dev/sda6
    # 格式化镜像文件为 ext4
    mkfs -t ext4 ./image.img
    

2.3 df 命令

Linux df(disk free) 命令用于显示目前在 Linux 系统上的文件系统磁盘使用情况

  • 语法

    df [OPTION]... [FILE]...
    
  • 参数

  • -a, --all:包含所有的具有 0 Blocks 的文件系统

  • -h, --human-readable:使用人类可读的格式(预设值是不加这个选项的…)

  • -H, --si:很像 -h, 但是用 1000 为单位而不是用 1024

  • -t, --type=TYPE:限制列出文件系统的 TYPE

  • -T, --print-type:显示文件系统的形式

  • 案例

    # 查看磁盘使用情况
    df -h
    # 查看磁盘的系统类型
    df -Th
    

2.4 mount 命令

mount 命令用于加载文件系统到指定的加载点。也常用于挂载光盘,使我们可以访问光盘中的数据,因为将光盘插入光驱中后,Linux 并不会自动挂载,必须使用 mount 命令来手动完成挂载。

Linux 系统下不同目录可以挂载不同分区和磁盘设备,它的目录和磁盘分区是分离的,可以自由组合(通过挂载)不同的目录数据可以跨越不同的磁盘分区或者不同的磁盘设备。

挂载的实质是为磁盘添加入口(挂载点)。

  • 语法

    mount [-l]
    mount [-t vfstype] [-o options] device dir
    
  • 参数

    • -l:显示已加载的文件系统列表;
    • -t: 加载文件系统类型支持常见系统类型的ext3 / ext4 / iso9660 / tmpfs / xfs 等,大部分情况可以不指定, mount 可以自己识别;
    • -o [options] 主要用来描述设备或档案的挂接方式。
      • loop:用来把一个文件当成硬盘分区挂接上系统
      • ro:采用只读方式挂接设备
      • rw:采用读写方式挂接设备
      • device: 要挂接(mount)的设备。
    • dir: 挂载点的目录
  • 案例

    # 将 /dev/hda1 挂在 /mnt 之下。
    mount /dev/hda1 /mnt
    # 将镜像挂载到/mnt/testext4 下面,需要确保挂载点(目录)存在
    mkdir -p /mnt/testext4
    mount ./fdimage.img /mnt/testext4
    

2.5 unshare 命令

unshare 命令用于启动一个新的进程并与当前进程分离不同的命名空间

  • 语法
unshare [options] program [arguments]
  • 参数
参数含义
-i, --ipc不共享 IPC 空间
-m, --mount不共享 Mount 空间
-n, --net不共享 Net 空间
-p, --pid不共享 PID 空间
-u, --uts不共享 UTS 空间
-U, --user不共享用户
-V, --version查看版本信息
--fork执行 unshare 的进程 fork 一个新的子进程,在子进程里执行传入的参数
--mount-proc执行子进程前,将 proc 文件系统优先挂载过去
  • 案例

    # 启动一个完全隔离的进程,既有独立的网络、进程 ID 和挂载空间
    unshare --net --pid --mount /bin/bash
    

三、实际操作

3.1 PID 隔离

  1. 首先在主机 shell 上执行 ps -ef 命令,可以查看进程列表,启动进程PID 为1的是init进程;

    在这里插入图片描述

  2. 我们另开一个shell,新建一个PID的Namespace,执行下面的命令,进行进程隔离:

    sudo unshare --fork --pid --mount-proc /bin/bash
    
    • --fork:新建了一个 bash 进程,如果不创建新进程,新的命名空间会将 unshare 的 PID 作为新的空间的父进程。但这个 unshare 进程并不在新的命名空间中,就会报错:Cannot allocate memory

    • --pid:表示进程通过 PID 隔离,而其他命名空间并没有隔离。

    • --mount-proc:在 Linux 下,每个进程都有一个对应的 /proc/PID 目录,该目录包含了大量有关当前进程的信息。对于一个 PID 命名空间而言,/proc 目录只包含当前命名空间及其所有子命名空间中的进程信息。

      创建一个新的 PID 命名空间后,如果想让子进程中的 topps 等依赖 /proc 文件系统的命令正常工作,需要挂载 /proc 文件系统。文件系统隔离是由 mount 命名空间管理的,因此 Linux 提供了 --mount-proc 选项来解决该问题。如果不带这个选项,我们仍然会看到宿主机的进程信息,而不是当前命名空间中的进程信息。

  3. 执行 ps -ef 查看进程信息,可以观察到进程空间内的内容已经更改,启动进程变成了bash进程

在这里插入图片描述

  1. 执行exit命令退出命名空间
    exit
    

3.2 Mount 隔离

  1. 打开第一个 shell 窗口 A,执行命令, df -h ,查看主机默认命名空间的磁盘挂载情况
    在这里插入图片描述

  2. 打开新的 shell 窗口 B,执行 Mount 隔离命令:

    unshare --mount --fork /bin/bash
    mkdir -p /data/tmpmount
    
  3. 在窗口B 上 添加磁盘挂载:

    dd if=/dev/zero of=image.img bs=8k count=10240
    mkfs -t ext4 ./image.img
    mount ./image.img /data/tmpmount
    
  4. 在窗口B挂载的磁盘 添加文件:

    echo "Hello world!" > /data/tmpmount/hello.txt
    
  5. 使用 df -h 命令查看窗口 B 中的磁盘挂载信息:

在这里插入图片描述

  1. 分别查看磁盘A、B的文件信息:

    • 磁盘A:
      在这里插入图片描述

    • 磁盘B:
      在这里插入图片描述

  2. 再次查看窗口A的磁盘挂在信息,输出结果与第一次一致,根据磁盘挂载信息与文件信息,可以看出磁盘B中的文件在磁盘A中不存在,即成功实现了文件隔离。

  3. 窗口B通过 exit 命令进行退出

    exit
    
  4. 关于文件的生命周期:

    • 如果窗口B在新的命名空间中创建了文件,它们的生命周期将由该命名空间控制。
    • 当执行 exit 命令时,窗口B的 Bash 进程退出并终止,新的命名空间也会被销毁。
    • 新命名空间中的所有挂载和文件都会被销毁,因为命名空间的生命周期与执行该命令的进程相关。当进程退出时,整个命名空间也会被清理,从而删除其中的所有文件。

http://www.kler.cn/a/448965.html

相关文章:

  • ubuntu22.04安装PaddleX3
  • linux中docker命令大全
  • 运维工程师面试系统监控与优化自动化与脚本云计算的理解虚拟化技术的优点和缺点
  • ARM异常处理 M33
  • Hmsc包开展群落数据联合物种分布模型分析通用流程(Pipelines)
  • Day13 用Excel表体验梯度下降法
  • Python实战:基于表单的暴力破解——以Pikachu靶机系统为例
  • vue中使用echarts做一个基础可滚动的折线图及dataZoom滚动配置项
  • SQL,生成指定时间间隔内的事件次序号
  • Hadoop完全分布式环境部署
  • malloc 分配大堆块(128KB)的一次探索
  • **Adversarial Demonstration Attacks on Large Language Models**
  • 【Leetcode】855. 考场就座
  • 小程序 - 模拟时钟
  • Echarts连接数据库,实时绘制图表详解
  • 微服务拆分 示例:黑马商城拆分商品服务模块
  • YOLOv9-0.1部分代码阅读笔记-dataloaders.py
  • C语言(一)——初识C语言
  • Django 视图中使用 Redis 缓存优化查询性能
  • 初识C语言之二维数组(下)
  • npm install vue-router失败解决办法
  • 4.2V单节锂电池充电电路(TP4056)、USB与锂电池切换电路分享
  • Github优质项目推荐(第九期)
  • QT_Demo(1)之实现多线程实现简单的电脑摄像头视频流开关
  • 叉车作业如何确认安全距离——UWB测距防撞系统的应用
  • Kubernetes APF(API 优先级和公平调度)简介