linux容器基础-namespace-3(pid)

pid namespace

pid namespace表示隔离一个具有独立PID的运行环境。

在每一个pid namespace中,进程的pid都从1开始,且和其他pid namespace中的PID互不影响。

这意味着,不同pid namespace中可以有相同的PID值。

在介绍pid namespace之前,先创建其他类型的namespace然后查看进程关系:

shell 复制代码
#在root namesapce查看当前进程的id是4048028
root@ubuntu-server:~# echo $$
4048028

root@ubuntu-server:~# pstree -p |grep 4048028
|-sshd(3944519)---sshd(4047935)---bash(4048028)-+-grep(4074182)

#进程的关系:
#systemd(1) |-sshd(3944519 这个是sshd服务server)|-sshd(4047935,这个是ssh连接的进程)|---bash(4048028)-+-grep(4074182)

root@ubuntu-server:~# ps -ef|grep 3944519
root     3944519       1  0 Jan15 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

创建一个uts namespace

shell 复制代码
root@ubuntu-server:~# unshare -u /bin/bash

在uts namespace中查看当前进程

shell 复制代码
root@ubuntu-server:~# pstree -p |grep grep
|-sshd(3944519)---sshd(4047935)---bash(4048028)---bash(4074716)-+-grep(4074764)

root@ubuntu-server:# ls -l /proc/4074716/ns|grep uts
lrwxrwxrwx 1 root root 0 Jan 16 15:07 uts -> uts:[4026532372]
root@ubuntu-server:# ls -l /proc/4048028/ns|grep uts
lrwxrwxrwx 1 root root 0 Jan 16 11:17 uts -> uts:[4026531838]
root@ubuntu-server:~# ls -l /proc/4047935/ns|grep uts
lrwxrwxrwx 1 root root 0 Jan 16 11:17 uts -> uts:[4026531838]

#从上面输出的结果可知,创建uts类型namespace时,unshare进程会在创建新的namespace后被该namespace中的第一个进程给替换掉。
#并且我们可以看到unshare创建的bash(4074716)进程与其父进程(4048028),2者的uts namespace是不一致的。

创建pid namespace:

shell 复制代码
unshare --pid --fork [--mount-proc] <CMD>
--pid(-p):    表示创建pid namespace
--mount-proc: 表示创建pid namespace时重新挂载procfs
--fork(-f):   表示创建pid namespace时,不是直接替换unshare进程,而是fork unshare进程,并使用CMD替换fork出来的子进程

我们使用fork的参数来验证一下:

shell 复制代码
root@ubuntu-server:~# echo $$
4048028

root@ubuntu-server:# unshare -p -f  --mount-proc /bin/bash
root@ubuntu-server:# pstree -p |grep grep
bash(1)-+-grep(9)

#终端2,重新打开一个终端
root@ubuntu-server:~# pstree -p 4048028
bash(4048028)───unshare(4090558)───bash(4090559)

root@ubuntu-server:# ls -l /proc/4048028/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 11:17 /proc/4048028/ns/pid -> 'pid:[4026531836]'
root@ubuntu-server:# ls -l /proc/4090558/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 17:27 /proc/4090558/ns/pid -> 'pid:[4026531836]'
root@ubuntu-server:~# ls -l /proc/4090559/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 17:27 /proc/4090559/ns/pid -> 'pid:[4026532379]'

#通过这个实验,我们可以看到unshare(4090558)这个进程还是在原来的namespace,并不会加入新的namespace,
而fork出来的bash(4090559)进程,他是加入到了一个新的namespace当中。

嵌套pid namespace

这个很容易理解,就是不同namespace之间可以相互嵌套,所有的子孙pid namespace中的进程信息都会保存在父级以及祖先级namespace中,

只不过在不同嵌套层级中,同一个进程对应的PID不同。

shell 复制代码
#我们这里在namespace1之中在创建一个namespace2看看进程的关系是什么样的
#------第一个终端------
#namespace1
root@ubuntu-server:~# unshare -p -f -u --mount-proc /bin/bash
root@ubuntu-server:~# hostname namespace1
root@ubuntu-server:~# exec bash

#在namespace1中创建namespace2
root@namespace1:~# unshare -p -f -u --mount-proc /bin/bash
root@namespace1:~# hostname namespace2
root@namespace1:~# exec bash
root@namespace2:~# pstree -p |grep grep
bash(1)-+-grep(16)

##------第二个终端------,也就是root namespace下面
root@ubuntu-server:~# pstree -p 4048028
bash(4048028)───unshare(4097920)───bash(4097921)───unshare(4098083)───bash(4098084)

#在上面fork测试中我们知道unshare进程还在原来的namespace,而unshare创建的bash是在新的namespace中。
所以bash(4048028)───unshare(4097920)在同一个ns,bash(4097921)───unshare(4098083)在同一个ns,bash(4098084)在一个ns

root@ubuntu-server:~# ls -l -h  /proc/4048028/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 11:17 /proc/4048028/ns/pid -> 'pid:[4026531836]'
root@ubuntu-server:~# ls -l -h  /proc/4097920/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 18:31 /proc/4097920/ns/pid -> 'pid:[4026531836]'
root@ubuntu-server:~# ls -l -h  /proc/4097921/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 18:31 /proc/4097921/ns/pid -> 'pid:[4026532386]'
root@ubuntu-server:~# ls -l -h  /proc/4098083/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 18:31 /proc/4098083/ns/pid -> 'pid:[4026532386]'
root@ubuntu-server:~# ls -l -h  /proc/4098084/ns/pid
lrwxrwxrwx 1 root root 0 Jan 16 18:31 /proc/4098084/ns/pid -> 'pid:[4026532391]'

pid namespace和procfs

/proc目录是内核对外暴露的可供用户查看或修改的内核中所记录的信息,包括内核自身的部分信息以及每个进程的信息。

比如对于pid=N的进程来说,它的信息保存在/proc/目录下。在操作系统启动的过程中,会挂载procfs到/proc目录,它存在于root namespace中。

但是,创建新的pid namespace时不会自动重新挂载procfs,而是直接拷贝父级namespace的挂载点信息。

这使得在新的pid namespace中仍然保留了父级namespace的/proc目录,也就是在新创建的这个pid namespace中仍然保留了父级的进程信息。

shell 复制代码
#不挂载 --mount-proc此时namespace还是继承宿主机的进程树
root@ubuntu-server:~# unshare -p -u -f /bin/bash
root@ubuntu-server:~# hostname namepsace1
root@ubuntu-server:~# exec bash
root@namepsace1:~# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        ├─agetty
        ├─cron
        ├─dbus-daemon
        ├─dnsmasq───dnsmasq
        ├─irqbalance───{irqbalance}
        ......

之所以有上述问题,其原因是在pid namespace中保留了root namespace中的/proc目录,而不是属于pid namespace自己的/proc。

但用户创建pid namespace时希望的是有完全独立的进程运行环境。

这时,需要在pid namespace中重新挂载procfs,或者在创建pid namespace时指定--mount-proc选项。

shell 复制代码
# 注意这儿添加了mount-proc参数
root@ubuntu-server:~# unshare -p -u -f --mount-proc /bin/bash
root@ubuntu-server:~# hostname namespace1
root@ubuntu-server:~# exec bash

# 进程树中展示了bash 为init进程
[root@namespace1 ~]# pstree -p
bash(1)───pstree(24)

pid namespace信号量

pid=1的进程是每一个pid namespace的核心进程(init进程),它不仅负责收养其所在pid namespace中的孤儿进程,还影响整个pid namespace。

当pid namespace中pid=1的进程退出或终止,内核默认会发送SIGKILL信号给该pid namespace中的所有进程以便杀掉它们(如果该pid namespace中有子孙namespace,也会直接被杀)。

在创建pid namespace时可以通过--kill-child选项指定pid=1的进程终止后内核要发送给pid namespace中进程的信号,其默认信号便是SIGKILL。

shell 复制代码
root@ubuntu-server:~# lsns
4026532379 pid         1 4099754 root             bash

root@ubuntu-server:~# kill -9 4099754
#在namespace1的进程,kill掉这个进程后这个namespace1整个namespace都被干掉了
root@namepsace1:~# Killed

#也可以指定为其他信号
unshare -p -f -m -u --mount-proc --kill-child=SIGHUP /bin/bash

我们在这里通过一些简单的例子来熟悉了一下pid namespace是如何工作的,当以后我们在玩k8s和docker的时候看到容器中的进程

是如何与宿主机隔离的就不会感到疑惑了。

相关推荐
.生产的驴3 分钟前
Docker 消息队列RabbitMQ 安装延迟消息插件
运维·spring boot·后端·docker·容器·rabbitmq·java-rabbitmq
霸道流氓气质16 分钟前
CentOS上使用Mosquitto实现Mqtt主题消息发布和订阅mqtt主题消息连同时间戳记录到文件
linux·运维·mqtt·centos·mosquitto
高危型19 分钟前
CentOS 入门
linux·运维·centos
mit6.82422 分钟前
[Linux#49][UDP] 2w字详解 | socketaddr | 常用API | 实操:实现简易Udp传输
linux·网络·c++·笔记·后端
桃花岛主7032 分钟前
Nginx搭建直播服务器,并用rtmp,http-flv,hls三种模式拉流观看直播的流程
运维·服务器·nginx
醉卧雕龙舫 、1 小时前
Linux中安装maven
linux·运维·maven
爱吃香蕉的阿豪1 小时前
828华为云征文|Flexus X实例Docker+Jenkins+gitee实现CI/CD自动化部署-解放你的双手~
ci/cd·docker·gitee·华为云·jenkins
不悔哥1 小时前
openwrt wsdd模块介绍
linux·c语言·网络·tcp/ip·智能路由器
IT枫斗者1 小时前
集合工具类
java·linux·数据库·windows·算法·microsoft
鲸鱼姐1 小时前
在linux注册服务并开机启动springboot程序
linux·运维·服务器