【Docker 内核详解】namespace 资源隔离(三):PID namespace
namespace 资源隔离(三):PID namespace
- 1.PID namespace 中的 init 进程
- 2.信号与 init 进程
- 3.挂载 proc 文件系统
- 4.unshare() 和 setns()
PID namespace 隔离非常实用,它对进程 PID 重新标号,即两个不同 namespace 下的进程可以有相同的 PID。每个 PID namespace 都有自己的计数程序。内核为所有的 PID namespace 维护了一个树状结构,最顶层的是系统初始时创建的,被称为 root namespace。它创建的新 PID namespace 被称为 child namespace(树的子节点),而原先的 PID namespace 就是新创建的 PID namespace 的 parent namespace(树的父节点)。通过这种方式,不同的 PID namespace 会形成一个层级体系。所属的父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。反过来,子节点却不能看到父节点 PID namespace 中的任何内容,由此产生如下结论。
- 每个
PID namespace中的第一个进程 “PID 1”,都会像传统 Linux 中的init进程一样拥有特权,起特殊作用。 - 一个
namespace中的进程,不可能通过kill或ptrace影响父节点或者兄弟节点中的进程,因为其他节点的 PID 在这个namespace中没有任何意义。 - 如果你在新的
PID namespace中重新挂载/proc文件系统,会发现其下只显示同属一个PID namespace中的其他进程。 - 在
root namespace中可以看到所有的进程,并且递归包含所有子节点中的进程。
到这里,大家可能已经联想到一种在外部监控 Docker 中运行程序的方法了,就是监控 Docker daemon 所在的 PID namespace 下的所有进程及其子进程,再进行筛选即可。
下面通过运行代码来感受一下 PID namespace 的隔离效果。修改 前一篇博客 中提到的代码,加入 PID namespace 的标识位,并把程序命名为 pid.c。
// [...]
int child_pid = clone(child_main, child_stack + STACK_SIZE,CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD, NULL);
// [...]
编译运行可以看到如下结果。
root@local:~# gcc -Wall pid.c -o pid.o && ./pid.o
程序开始:
在子进程中!
root@NewNamespace:~# echo $$
1 <<--注意此处 shell 的 PID 变成了 1
root@NewNamespace:~# exit
exit
已退出
打印 $$ 可以看到 shell 的 PID,退出后如果再次执行可以看到效果如下。
root@local:~# echo $$
17542
已经回到了正常状态。有的读者可能在子进程的 shell 中执行了 ps aux 或 top 之类的命令,发现还是可以看到所有父进程的 PID,那是因为还没有对文件系统挂载点进行隔离,ps 或 top 之类的命令调用的是真实系统下的 /proc 文件内容,看到的自然是所有的进程。所以,与其他的 namespace 不同的是,为了实现一个稳定安全的容器,PID namespace 还需要进行一些额外的工作才能确保进程运行顺利,下面将逐一介绍。
1.PID namespace 中的 init 进程
在传统的 Unix 系统中,PID 为 1 1 1 的进程是 init,地位非常特殊。它作为所有进程的父进程,维护一张进程表,不断检查进程的状态,一旦有某个子进程因为父进程错误成为了 孤儿 进程,init 就会负责收养这个子进程并最终回收资源,结束进程。所以在要实现的容器中,启动的第一个进程也需要实现类似 init 的功能,维护所有后续启动进程的运行状态。
当系统中存在树状嵌套结构的 PID namespace 时,若某个子进程成为孤儿进程,收养该子进程的责任就交给了该子进程所属的 PID namespace 中的 init 进程。
至此,可能读者已经明白了内核设计的良苦用心。PID namespace 维护这样一个树状结构,有利于系统的资源监控与回收。因此,如果确实需要在一个 Docker 容器中运行多个进程,最先启动的命令进程应该是具有资源监控与回收等管理能力的,如 bash。
2.信号与 init 进程
内核还为 PID namespace 中的 init 进程赋予了其他特权 —— 信号屏蔽。如果 init 中没有编写处理某个信号的代码逻辑,那么与 init 在同一个 PID namespace 下的进程(即使有超级权限)发送给它的该信号都会被屏蔽。这个功能的主要作用是防止 init 进程被误杀。
那么,父节点 PID namespace 中的进程发送同样的信号给子节点中的 init 进程,这会被忽略吗?父节点中的进程发送的信号,如果不是 SIGKILL(销毁进程)或 SIGSTOP(暂停进程)也会被忽略。但如果发送 SIGKILL 或 SIGSTOP,子节点的 init 会强制执行(无法通过代码捕捉进行特殊处理),也即是说父节点中的进程有权终止子节点中的进程。
一旦 init 进程被销毁,同一 PID namespace 中的其他进程也随之接收到 SIGKILL 信号而被销毁。理论上,该 PID namespace 也不复存在了。但是如果 /proc/[pid]/ns/pid 处于被挂载或者打开状态,namespace 就会被保留下来。然而,保留下来的 namespace 无法通过 setns() 或者 fork() 创建进程,所以实际上并没有什么作用。
当一个容器内存在多个进程时,容器内的 init 进程可以对信号进行捕获,当 SIGTERM 或 SIGINT 等信号到来时,对其子进程做信息保存、资源回收等处理工作。在 Docker daemon 的源码中也可以看到类似的处理方式,当结束信号来临时,结束容器进程并回收相应资源。
3.挂载 proc 文件系统
前文提到,如果在新的 PID namespace 中使用 ps 命令查看,看到的还是所有的进程,因为与 PID 直接相关的 /proc 文件系统(procfs)没有挂载到一个与原 /proc 不同的位置。如果只想看到 PID namespace 本身应该看到的进程,需要重新挂载 /proc,命令如下。
root@NewNamespace:~# mount -t proc proc /proc
root@NewNamespace:~# ps a
PID TTY STAT TIME COMMAND
1 pts/1 S 0:00 /bin/bash
12 pts/1 R+ 0:00 ps a
可以看到实际的 PID namespace 就只有两个进程在运行。
此时并没有进行 mount namespace 的隔离,所以该操作实际上已经影响了 root namespace 的文件系统。当退出新建的 PID namespace 以后,再执行 ps a 时,就会发现出错,再次执行 mount -t proc proc /proc 可以修复错误。后面还会介绍通过 mount namespace 来隔离文件系统,当我们基于 mount namespace 实现了容器 proc 文件系统隔离后,我们就能在 Docker 容器中使用 ps 等命令看到与 PID namespace 对应的进程列表。
4.unshare() 和 setns()
前一篇博客 就提到了 unshare() 和 setns() 这两个 API,在 PID namespace 中使用时,也有一些特别之处需要注意。
unshare() 允许用户在原有进程中建立命名空间进行隔离。但创建了PID namespace后,原先 unshare() 调用者进程并不进入新的 PID namespace,接下来创建的子进程才会进入新的 namespace,这个子进程也就随之成为新 namespace 中的 init 进程。
类似地,调用 setns() 创建新 PID namespace 时,调用者进程也不进入新的 PID namespace,而是随后创建的子进程进入。
为什么创建其他 namespace 时 unshare() 和 setns() 会直接进入新的 namespace,而唯独 PID namespace 例外呢?因为调用 getpid() 函数得到的 PID 是根据调用者所在的 PID namespace 而决定返回哪个 PID,进入新的 PID namespace 会导致 PID 产生变化。而对用户态的程序和库函数来说,它们都认为进程的 PID 是一个常量,PID 的变化会引起这些进程崩溃。
换句话说,一旦程序进程创建以后,那么它的 PID namespace 的关系就确定下来了,进程不会变更它们对应的 PID namespace。在 Docker 中,docker exec 会使用 setns() 函数加入已经存在的命名空间,但是最终还是会调用 clone() 函数,原因就在于此。
相关文章:
【Docker 内核详解】namespace 资源隔离(三):PID namespace
namespace 资源隔离(三):PID namespace 1.PID namespace 中的 init 进程2.信号与 init 进程3.挂载 proc 文件系统4.unshare() 和 setns() PID namespace 隔离非常实用,它对进程 PID 重新标号,即两个不同 namespace 下的…...
1600*C. Game On Leaves(博弈游戏树)
Problem - 1363C - Codeforces 解析: 我们将目标结点 x 当作树的根,显然,到当 x 的度为 1 的时候,此时行动的人胜利。 我们假设现在的情况为,只剩余三个点,再选择任意一个点,则对方获胜。但是两…...
Apache Ant的安装
介绍 Apache Ant是一个Java库和一个 命令行工具,可以用来构建Java应用。Ant提供了许多内置的任务(tasks),可以编译、组装、测试、运行Java应用。Ant也可以构建非Java应用,例如C、C应用。 Ant非常灵活,没有…...
考研:数学二例题--∞−∞和0⋅∞型极限
前言 本文只是例题,建议先参考具体如何做这类型例题。请到主文章中参考:https://blog.csdn.net/grd_java/article/details/132246630 ∞ − ∞ 和 0 ⋅ ∞ \infin - \infin 和 0\infin ∞−∞和0⋅∞ 例题 例1: lim x → ∞ x 2 x 2 −…...
C++算法:图中的最短环
题目 现有一个含 n 个顶点的 双向 图,每个顶点按从 0 到 n - 1 标记。图中的边由二维整数数组 edges 表示,其中 edges[i] [ui, vi] 表示顶点 ui 和 vi 之间存在一条边。每对顶点最多通过一条边连接,并且不存在与自身相连的顶点。 返回图中 …...
C++学习——类其实也是一种作用域
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 其实也是一种作用域,每个类都会定义它自己的作用域。在类的作用域之外,普通的成员只能通过对象(可以是对象本身,也可以是对象指针或对象…...
Seata入门系列【4】undo_log、global_table、branch_table、lock_table字段及作用详解
1 客户端 1.1 undo_log 在AT模式中,需要在参与全局事务的数据库中,添加一个undo_log表,建表语句如下: SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for undo_log -- --…...
虚幻引擎:数据表格的C++常用API
1.将数据表格中的所有数据存到一个数组中 //参数1 // 错误提示 //参数2 // 存储的数组 TArray<FKeyInfoHeader*> array; KeyInfoDT->GetAllRows<FKeyInfoHeader>(TEXT("错误"),array); 2.获取表格中所有的行名称 TArray<FName>array; …...
Java日期格式化(DateFormat类和SimpleDateFormat类)
格式化日期表示将日期/时间格式转换为预先定义的日期/时间格式。例如将日期“Fri May 18 15:46:24 CST2016” 格式转换为 “2016-5-18 15:46:24 星期五”的格式。 在 java 中,可以使用 DateFormat 类和 SimpleDateFormat 类来格式化日期,下面详细介绍这两…...
centos 7 lamp owncloud
OwnCloud是一款开源的云存储软件,基于PHP的自建网盘。基本上是私人使用,没有用户注册功能,但是有用户添加功能,你可以无限制地添加用户,OwnCloud支持多个平台(windows,MAC,Android&a…...
屏幕亮度调节保护您的眼睛
官方下载地址: 安果移动 视频演示:屏幕亮度调节-保护您的眼睛_哔哩哔哩_bilibili 嗨,亲爱的用户,你是否有过这样的体验:夜晚安静的时刻,想要在抖音上看看热门的舞蹈、在快手上发现生活的 趣味、或是在哔…...
CentOS Linux下CMake二进制文件安装并使用Visual Studio调试
cmake安装——二进制安装(很简单,推荐!!) 1)下载二进制包。首先就是官网下载二进制安装包(我们是64位系统,就下载对应的包),这里。 例如:在/home/DOWNLOAD目录下执行,即下载二进制…...
ASP.net相关目录,相关配置文件和.后缀名解释
App_Data:用于存储应用程序的数据文件,例如数据库文件或其他本地文件。 App_Start:包含应用程序的启动配置文件,例如路由配置、日志配置等。 Content:存放应用程序的静态资源文件,如 CSS、JavaScript、图…...
一键批量转换,轻松将TS视频转为MP4视频,实现更广泛的播放和分享!
在享受精彩视频内容的同时,有时我们可能会面临一个问题:某些视频格式可能不太适合我们的播放设备或分享平台。特别是TS格式的视频,在一些情况下可能无法直接播放或上传。但是不用担心,因为我们为您提供了一款强大的视频剪辑工具&a…...
【Redis】使用Java客户端操作Redis
目录 引入jedis依赖连接Redis命令get/setexists/delkeysexpire/ttltype 引入jedis依赖 连接Redis 命令 get/set exists/del keys expire/ttl type...
BSPHP 未授权访问 信息泄露
漏洞描述 BSPHP 存在未授权访问 泄露用户 IP 和 账户名信息 漏洞复现 访问url: 构造payload访问: /admin/index.php?madmin&clog&atable_json&jsonget&soso_ok1&tuser_login_log&page1&limit10&bsphptime16004073…...
Learning Sample Relationship for Exposure Correction 论文阅读笔记
这是中科大发表在CVPR2023的一篇论文,提出了一个module和一个损失项,能够提高现有exposure correction网络的性能。这已经是最近第三次看到这种论文了,前两篇分别是CVPR2022的ENC(和这篇文章是同一个一作作者)和CVPR20…...
Vue项目 -- 解决Eslint导致的console报错问题
在利用vue-cli3构建的项目中引入eslint进行语法检查时,使用console.log(‘xxx’)时,控制台抛出了Unexpected console statement (no-console) 异常, 例:一使用console就提示报错 解决办法是: 在 .eslintrc.js 文件中…...
uni-app 在已有的数据对象中动态添加更多的数据对象
原数据对象 flowData: {list: [], // 数据值column: 2, // 瀑布列数columnSpace: 2 // 瀑布列宽间距 } 动态添加后的数据对象 flowData: {list: [], // 数据值column: 2, // 瀑布列数columnSpace: 2, // 瀑布列宽间距column_1: [],column_2: [] } 动态添加更多的数据对象的…...
【LeetCode】17. 电话号码的字母组合
1 问题 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 1: 输入:digits “23” 输出&…...
如何利用Bebas Neue字体提升设计项目的视觉冲击力:完整实战指南
如何利用Bebas Neue字体提升设计项目的视觉冲击力:完整实战指南 【免费下载链接】Bebas-Neue Bebas Neue font 项目地址: https://gitcode.com/gh_mirrors/be/Bebas-Neue 你是否曾经在设计海报、网站标题或品牌标识时,为了找到一款既有现代感又足…...
深入解析Android Verified Boot (AVB):从启动链到镜像验证的完整机制
1. Android Verified Boot (AVB) 是什么? 当你按下手机电源键时,系统会经历一系列复杂的启动过程。AVB(Android Verified Boot)就是在这个过程中确保每一步加载的代码都未被篡改的安全卫士。想象一下,这就像机场的安检…...
造相Z-Image模型v2传统艺术风格专题:水墨、版画与油画的数字重生
造相Z-Image模型v2传统艺术风格专题:水墨、版画与油画的数字重生 当千年传统艺术遇见现代AI技术,会碰撞出怎样的数字火花? 最近深度体验了造相Z-Image模型v2在传统艺术风格方面的表现,不得不说,这个模型在模拟水墨、版…...
OpenClaw+Qwen2.5-VL-7B学术助手:论文图表解析与摘要生成
OpenClawQwen2.5-VL-7B学术助手:论文图表解析与摘要生成 1. 为什么需要AI学术助手 作为一名经常需要阅读大量文献的研究人员,我长期被三个问题困扰:首先是PDF论文中的图表数据提取困难,手动转录既耗时又容易出错;其次…...
算法调度问题中的代价模型与优化方法的技术5
算法调度问题概述定义与基本概念:任务调度、资源分配、目标函数典型应用场景:云计算、分布式系统、实时系统核心挑战:多目标权衡、动态环境、不确定性代价模型的设计与分析代价模型的组成:时间代价、资源代价、经济代价常见模型分…...
Kylin V10系统下KVM虚拟化实战:从环境配置到虚拟机部署
1. Kylin V10系统与KVM虚拟化基础 国产麒麟操作系统V10作为一款基于Linux内核的自主可控系统,在企业级应用中越来越常见。最近我在一个国产化服务器迁移项目中,需要在Kylin V10上部署KVM虚拟化环境,过程中积累了不少实战经验。KVM作为Linux内…...
GitHub 学生认证通过后,这些隐藏注意事项你一定要知道!
这篇文章,就结合实际情况,为大家详细梳理 GitHub 认证通过后的有效期机制、风控规则、权益激活技巧。一、关于认证有效期✅ 认证通过后,账号默认有效期为 2 年。但这只是一个常规周期,并不代表你一定能稳稳用满两年。GitHub 官方及…...
开源项目 Agentic OS 实战指南:手把手教你从 ANOLISA 源码安装
首个面向 Agent 的操作系统——Agentic OS发布后,收到许多询问,是否能在本地部署?当然可以,Agentic OS 已经在 GitHub 上开源,开源项目是「ANOLISA」。 本文会详细介绍如何准备开发环境、从源码构建 ANOLISA 各组件并…...
2026互联网大厂AI招聘趋势:高薪岗位解析,普通人如何抓住AI时代红利?
2026年互联网大厂招聘,AI岗已成绝对主角,百度AI岗占比超90%,阿里超6成,腾讯、字节等AI相关岗位占比也达6-7成,AI不再是“可选项”,而是“必答题”。以下是核心岗位、薪资与优势的精炼解读,帮你快…...
OpenClaw备份同步方案:Qwen3-14b_int4_awq配置跨设备无缝迁移
OpenClaw备份同步方案:Qwen3-14b_int4_awq配置跨设备无缝迁移 1. 为什么需要OpenClaw环境同步? 去年冬天,我在办公室调试了一个完美的OpenClaw工作流——用Qwen3-14b模型自动整理技术文档并生成周报。但当我回到家想继续工作时,…...
