Linux - Namespace

一、namespace 是什么?

Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

二、namespace 解决了什么问题?

Linux 内核出现 namespace 的一个主要目的就是实现轻量级虚拟化(容器)服务。在同一个 namespace 下的进程可以感知彼此的变化,而对外界的进程一无所知,从而达到隔离的目的。

其实换个说法,Linux 内核所提供的 namespace 技术为 docker 等容器技术的出现和发展提供了基础条件。没有 Linux 内核中的 namespace 的出现,可能 docker 容器化技术还不会那么快出现。

三、namespace 具体有哪些呢?

1. Mount Namespace 文件系统隔离。隔离了一组进程所看到的文件系统挂载点的集合,在不同的Mount Namespace 的进程所看到的文件是不同的。

2. UTS Namespace 隔离主机和域名信息。隔离了 uname() 系统调用返回的两个系统标识符 nodename 和 domainname. 在容器的上下文中,UTS namespace 允许每个容器拥有自己的hostname 和 UNIX domainname,这对于初始化和配置脚本是十分有用的,这些脚本根据这些名称来定制他们的操作。

3. IPC Namespace 隔离进程间通信。隔离了某些IPC资源(interprocess community,进程间通信)使划分到不同IPC Namespace 的进程组通信上隔离,无法通过消息队列、共享内存、信号量方式通信,这样,只有在同一个Namespace下的进程才能相互通信。如果你熟悉IPC的原理的话,你会知道,IPC需要有一个全局的ID,即然是全局的,那么就意味着我们的Namespace需要对这个ID隔离,不能让别的Namespace的进程看到。 要启动IPC隔离,我们只需要在调用clone时加上CLONE_NEWIPC参数就可以了。 int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL);

4. PID Namespace 进程隔离。隔离了进程ID空间,不同的 PID Namespace 中的进程可以拥有相同的 PID。PID Namespace 的好处之一是,容器可以在主机之间迁移,同时容器内的进程保持相同的进程ID。PID Namespace 空间还允许每个容器拥有自己的 init (PID 1),它是“所有进程的祖先”,负责管理各种系统初始化任务,并在子进程终止时收割孤儿进程。

5. Network Namespace 网络资源隔离。每个 Network Namespace 都有自己的网络设备、IP地址、IP路由表、/proc/net目录、端口号等。

6. User Namespace 用户和用户组隔离。一个进程的用户和组ID在 User Namespace 空间外可以是不同的,一个进程可以在用户命名空间外拥有一个正常的无权限用户 ID,同时在命名空间内拥有一个(root 权限) 的用户ID。

上面说到了一句,要启动IPC隔离,我们只需要在调用clone时加上CLONE_NEWIPC参数就可以了

这主要是因为 Linux 的 namespace 主要是利用下面三个系统调用:

  • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过设计上述参数达到隔离。
  • unshare() – 使某进程脱离某个namespace
  • setns() – 把某进程加入到某个namespace

深处我也不会~

四、通过实践来证明

理论结合实践才能更好的理解这些到底在说什么,我用一个简单的例子来简单阐述一下吧。

docker run -it busybox /bin/sh

 

1、我们以交互式的方式进入容器,执行 ls 命令,可以看到常规的 Linux 系统目录结构,但这并非是宿主机的文件系统。

有了文件系统隔离,我们在当前容器内对文件所做的操作并不会影响到外部宿主机的文件另外我们启动不同的容器,我们所看到的文件系统也是隔离的。

 

2、隔离主机和域名信息。这点其实很好验证,当执行 hostname 命令时,控制台会返回当前主机名称给我们。

前者是在容器内部执行,返回的是容器ID后者是在宿主机的控制台执行,输出的是ubuntu。

 

3、当我们执行 ifconfig 命令,我们会看到和我们宿主机不同的网卡和网关信息等

 

除了上面的方式,我们也可以通过 docker inspect <容器名|容器ID> 来看容器的相关信息,其中也包含了容器网络相关信息。

 

 

4、进程隔离也是同样如此,我们在宿主机和容器中分别执行 ps -ef | grep sh 命令,看看结果就知道啦 

 

在容器内明显看不到宿主机其他进程情况,并且容器内的 /bin/sh PID 为1,PID =1 的进程是系统启动时的第一个进程,也称 init 进程。其他的进程,都是由它管理产生的。而此时,PID=1 却是 /bin/sh 进程。而它在宿主机上所展示时,它的PID变成了 2456。

这一点也可以换成下面这条命令来准确定位:

docker inspect -f '{{.State.Pid}}' <容器名称或ID> # 查看容器的PID

这个结论就非常好说了,在容器中,它确确实实是完成了 PID 的隔离,明明宿主机上是 2456 的进程,变成了容器内的 1 号进程,同时在容器中还看不到宿主机其他进程。

 

五、Docker 中的 User Namespace 详解

Docker 中引入的 user namespace 可以让容器中有一个 “假”的 root 用户,它在容器内是 root,在容器外是一个非 root 用户。也就是 user namespace 实现了 host user 和 container user 之间的映射。

我们拿一个简单的例子来说明:

docker run -it -v /bin:/host/bin busybox /bin/sh

先来解释下这条命令,现在是 dj(uid=1000,gid=1000)的用户,将本机上的 /bin 目录,挂载到容器中 /host/bin 目录下啦,并以交互式的方式启动了容器 busybox ,进入到容器内部。

那么现在有个问题:我在容器中的 /host/bin 目录下可以修改文件或者增加文件吗? 见下图。

答案是可以的。为什么呢?我一个非root用户,为什么可以操作root权限的文件呢?

原因:Docker容器运行的时候,如果没有专门指定user, 默认以root用户运行它并不是说按照你现在的登录的用户去分配权限的,而是没有指定就默认使用root用户运行。

另外有没有觉得这是非常恐怖的一件事情,我明明没有 root 权限,却突然之间通过 docker 给容器挂载一个文件目录,虽然我一下没想起来可以做什么,但还是有点恐怖的哈。

因为在 Docker中默认并没有开启 user namespace这并不是说 Linux 机器没有支持 user namespace ,而是 docker 中没有开启。

在说如何让 Docker 启用 user namespace 之前,我们先用另一种方式来曲线救国一下。

我之前使用 id 命令, 看到了我当前用户 dj 的(uid=1001),我们在执行 docker run 记得指定一下即可。

上面的命令改为:

docker run -it  -u 1001:1001 -v /bin:/host/bin busybox /bin/sh

我们使用了 -u 1001:1001 来指定了容器内所使用的用户。我们再重复一下上面的操作。

  

六、如何让 Docker启用 User namespace 呢?

1、备份 docker 配置文件

 因为我之前没有配置文件,所以我直接新建了一个文件

 

2、修改 docker 配置文件

添加 User Namespace 配置: 在配置文件中添加以下内容以启用 User Namespace。这将告诉 Docker 守护进程使用 User Namespace 功能。

    {
      "userns-remap": "default"
    }

 

3、保存文件,重启启动 Docker 服务,以使配置文件生效

sudo systemctl restart docker

 

4、验证配置 

cat /etc/subuid
cat /etc/subgid

dockermap 是默认的映射名称。

补充/etc/subuid 是一个系统配置文件,用于管理用户命名空间中用户的子用户标识(sub-IDs)。不多占篇幅介绍了,/etc/subgid 相应就是用户组的标识。具体感兴趣可以去了解。

现在我们再执行上面之前测试的命令。

docker run -it -v /bin:/host/bin busybox /bin/sh

我们还是使用 dj 这个用户,但是它已经没有权限修改从宿主机 /bin 映射到容器的/host/bin的目录了。

并且使用 id 命令,可以看到容器内部是 root 用户,但实际上它在容器外并不是root 用户。

另外还可以查找容器的PID(进程号),通过容器的进程号,来查看它的命名空间。

docker inspect -f '{{.State.Pid}}' <容器名称或ID> # 查看容器的PID

查看进程命名空间: 

cat /proc/${容器PID}/uid_map

 

/proc/5517/uid_map 它表示了容器内外用户的映射关系即将host 上的 231072 用户映射为容器内的 0 即 root 用户。

这说明通过使用 user namespace 使得容器内的进程运行在非 root 用户上,我们成功地限制了容器内进程的权限

 

七、Docker 为什么不默认启用 User namespace呢?

编写这一小章节的时候,我原打算去找资料啦,因为我已经猜测到一些原因,但需要验证一下,但是看到还没关闭的 GPT窗口,就打算拿它试一下。答案如下:

 

结论也很容易得出,Docker 希望降低复杂性,获取更强的兼容性,降低故障排查难度,也希望降低普通开发人员的使用门槛,更好的推广。 

八、Namespace 存在的问题

我们都知道 Namespace 的隔离是轻量化的,比起虚拟化的隔离,它的缺陷也很明显,就是无法进行彻底的隔离

因为不管如何隔离,它都是依赖于同一个内核的,那么此时内核就成了所有容器的共享变量,改动了一次,就会影响到全部。

九、检查 linux 操作系统是否启用了 namespace

运行下面的命令即可检查是否启用了:

root@ubuntu:/home# uname -a
Linux ubuntu 5.15.0-78-generic #85~20.04.1-Ubuntu SMP Mon Jul 17 09:42:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

root@ubuntu:/home# cat /boot/config-5.15.0-7
config-5.15.0-76-generic  config-5.15.0-78-generic  
    
root@ubuntu:/home# cat /boot/config-5.15.0-78-generic | grep CONFIG_USER_NS
CONFIG_USER_NS=y
    
root@ubuntu:/home#

如果是 「y」,则启用了,否则未启用。同样地,可以查看其它 namespace:

CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pikachu漏洞练习平台之XXE(XML外部实体注入)

目录 什么是 XML&#xff1f; 什么是DTD&#xff1f; 什么是XEE&#xff1f; 常见payload 什么是 XML&#xff1f; XML 指可扩展标记语言&#xff08;EXtensible Markup Language&#xff09;&#xff1b; XML 不会做任何事情&#xff0c;而是用来结构化、存储以及传输信息…

java接收前端easyui datagrid传递的数组参数

这篇文章分享一下怎么在easyui的datagrid刷新表格时&#xff0c;在后端java代码中接收datagrid传递的数组参数。 数组来源于技能的tagbox&#xff08;标签框&#xff09;&#xff0c;tagbox和combobox的区别是tagbox可以选择多项。 标签框渲染的代码为 $("#skill_ids"…

确保人工智能的公平性:生成无偏差综合数据的策略

一、介绍 合成数据生成涉及创建密切模仿现实世界数据但不包含任何实际个人信息的人工数据&#xff0c;从而保护隐私和机密性。然而&#xff0c;至关重要的是&#xff0c;这些数据必须以公平、公正的方式生成&#xff0c;以防止人工智能应用中现有的偏见长期存在或扩大。 在数据…

12-2- DCGAN -简单网络-卷积网络

功能 随机噪声→生成器→MINIST图像。 训练方法 1 判别器的训练,首先固定生成器参数不变,其次判别器应当将真实图像判别为1,生成图像判别为0 loss=loss(real_out, 1)+loss(fake_out, 0) 2 生成器的训练,首先固定判别器参数不变,其次判别器应当将生成图像判别为1 loss =…

YOLOv5独家原创改进:最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv5独家原创改进:独家首发最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度。 💡对自己数据集改进有效…

TensorFlow案例学习:图片风格迁移

准备 官方教程&#xff1a; 任意风格的快速风格转换 模型下载地址&#xff1a; https://tfhub.dev/google/magenta/arbitrary-image-stylization-v1-256/2 学习 加载要处理的内容图片和风格图片 # 用于将图像裁剪为方形def crop_center(image):# 图片原始形状shape image…

微信小程序相机相册授权后,需要重启客户端才能正常调用相机,无法调起窗口选择图片,无反应解决方案

最近微信小程序很多功能突然不能使用&#xff0c;本篇针对无法调起相册进行说明 解决方案 检查小程序隐私协议是否配置&#xff0c;操作步骤这里不在详细说明&#xff0c;点击教程按照上面的教程&#xff0c;找到入口后点击完善或者更新 选择选中的照片或视频这个权限要申请 之…

OpenCV入门4——实现图形的绘制

文章目录 OpenCV绘制直线OpenCV绘制矩形和圆画矩形画圆 OpenCV椭圆的绘制OpenCV绘制多边形OpenCV绘制文本实现鼠标绘制基本图形 OpenCV绘制直线 # -*- coding: utf-8 -*- import cv2 import numpy as npimg np.zeros((480, 640, 3), np.uint8) # 坐标点为(x, y) cv2.line(img,…

Unity | 运行时显示调试信息

「公众号&#xff1a;游戏开发手记」 1 简介 在 Unity 编辑器中&#xff0c;我们可以通过点击 Stats 按钮来查看 Statistics 面板&#xff0c;这个面板显示了许多关于游戏渲染的信息&#xff0c;如每帧的渲染时间、Tris 和 Verts 的数量、SetPass Calls 的数量等。但在其他运…

Java设计模式-结构型模式-装饰模式

装饰模式 装饰模式角色案例装饰模式与静态代理的区别 装饰模式 允许向一个现有的对象动态地添加新的功能&#xff0c;同时不改变其结构。它是继承的一种替代方案&#xff0c;可以动态地扩展对象。有点像静态代理 角色 装饰者模式有四种角色 抽象被装饰者&#xff0c;被装饰者…

基于单片机的自动循迹小车(论文+源码)

1.系统设计 此次基于单片机的自动循迹小车的设计系统&#xff0c;结合循迹模块来共同完成本次设计&#xff0c;实现小车的循迹功能&#xff0c;其其整体框架如图2.1所示。其中&#xff0c;采用STC89C52单片机来作为核心控制器&#xff0c;负责将各个传感器等模块链接起来&…

23款奔驰GLC260L升级小柏林音响 全新15个扬声器

2023年款奔驰GLC260 GLC300升级小柏林之声 3D音效系统 升级小柏林之声音响之后&#xff0c;全车一共有15个喇叭&#xff0c;1台功放&#xff0c;每一首音乐都能在车内掀起激情的音浪&#xff0c;感受纯粹的音乐享受&#xff0c;低频震撼澎湃&#xff0c;让你的心跳与音乐完美契…

js的数组

js js 的数组数组是什么为什么要使用数组数组的简单使用数组是按照顺序保存的&#xff0c;所以每个数据都有自己的编号数组的取值方法遍历数组数组的元素求和数组的最大值和最小值数组的增删改查操作数组的增加数组的筛选数组的删除 案例&#xff1a; 九九乘法表 数组是什么 数…

内置升压的单声道D类音频功率放大器:HT81293

HT81293是一款内置升压的单声道D类音频功率放大器&#xff0c;由锂电池供电时&#xff0c; THDN10%&#xff0c; 能连续输出18W功率&#xff08;4Ω负载&#xff09;。 HT81293A内置可动态调节的升压&#xff0c;可以提供一个适应不同输出功率的电压给D类功放&#xff0c;其可大…

Swagger使用

Swagger使用 1. Swagger UI 按以下步骤配置&#xff0c;项目启动后访问&#xff1a; http://localhost:8080/swagger-ui.html 1.1 添加依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><ve…

2023 年 数维杯(B题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2021年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看数维杯&#xff08;B题&#xff09;&#xff01; …

JSP在Scriptlet中编写java代码的形式

我们想在jsp界面中去写java代码&#xff0c;就需要将java代码写在Scriptlet中 虽然说 有这种方式 但是 目前 大部分都会不建议你往jsp中去写java代码 因为 目前都在推广前后端分离 这也是jsp使用面有没有少的原因 jsp也建议解耦 不要让你的程序耦合性太高 还是前端是前端 后端是…

【Ubuntu·系统·的Linux环境变量配置方法最全】

文章目录 概要读取环境变量的方法小技巧 概要 在Linux环境中&#xff0c;配置环境变量是一种常见的操作&#xff0c;用于指定系统或用户环境中可执行程序的搜索路径。 读取环境变量的方法 在Linux中&#xff0c;可以使用以下两个命令来读取环境变量&#xff1a; export 命令…

JVM——运行时数据区(程序计数器+栈)

目录 1.程序计数器2.栈Java虚拟机栈 - 栈帧的组成1.Java虚拟机栈-局部变量表3.Java虚拟机栈-操作数栈3.Java虚拟机栈-帧数据 3.Java虚拟机栈-栈内存溢出4.本地方法栈 ⚫ Java虚拟机在运行Java程序过程中管理的内存区域&#xff0c;称之为运行时数据区。 ⚫ 《Java虚拟机规范》中…

栈和队列的实现及相关面试题

栈和队列 栈概念与结构栈的功能栈的实现头文件Stack.h栈的结构体 Stack 源文件Stack.c初始化 void StackInit(Stack* ps)压栈 void StackPush(Stack* ps, STDataType data)出栈 void StackPop(Stack* ps)返回栈顶的值 STDataType StackTop(Stack* ps)返回栈中元素的个数 int St…