Linux Namespace 简单理解
本文将介绍Linux Namespace
。
一提到容器技术,随之想到的便是namespace
是容器化的基石,本篇文章将对Namespace
进行简单的了解。
本文所依赖的环境为:
root@debian:~# hostnamectl
Static hostname: windows11pro
Icon name: windowsBooks
Chassis: laptop 💻
Operating System: Debian GNU/Linux 12 (bookworm)
Kernel: Linux 6.1.0-26-amd64
Architecture: x86-64
Hardware Vendor: ASUSTeK COMPUTER INC.
Hardware Model: X441UVK
Firmware Version: X441UVK.314
root@debian:~#
Namepace
也称之为命名空间,最早出现在内核2.4.19
上,后期逐步迭代的,它的作用是将Linux
的资源隔离开来,可以这样理解,Nmaespace
就是为了虚拟化而存在的。
Namespace
类型众多,这里列举一个表格说明。
内核版本 | Namespace | 系统调用参数 | 含义 |
---|---|---|---|
2.4.19 | Mount Namespace | CLONE_NEWNS | 文件系统的隔离 |
2.6.19 | UTS Namespace | CLONE_NEWUTS | nodename和damainname的隔离 |
2.6.19 | IPC Namespace | CLONE_NEWIPC | 进程间通信资源隔离 |
2.6.24 | PID Namespace | CLONE_NEWPID | 进程ID的隔离 |
2.6.29 | Network Namespace | CLONE_NEWNET | 网络的隔离 |
3.8 | User Namespace | CLIONE_NEWUSER | 用户和组的隔离 |
5.6 | Time Namespace | CLONE_NEWTIME | 系统时钟的隔离 |
前置准备
陆游曾说,”纸上得来终觉浅,绝知此事要躬行。“,实践才是检验真理的唯一标准,所以,在正式了解Namespace
之前,得先了解下关于Namespace
相关的工具:unshare
,如果要解释该工具,用unshare - run program in new namespaces
表达再合适不过了,它可以在新的命名空间中运行要指定的程序。
unshare工具的使用
创建Namespace
主要的参数有以下几种:
-m
、--mount
:用以创建Mount namespace
。-u
、--uts
:用以创建Uts Namespace
。-i
、--ipc
:用以创建IPC Namespace
。-p
、--pid
:用以创建Pid Namespace
。-n
、--net
:用以创建Network Namespace
。-U
、--user
:用以创建User Namespace
。-T
、--time
:用以创建Time Namespace
。
举一个最简单的例子,在Network Namespace
启动一个bash
进程,可以使用如下命令:
在此之前,我们需要先获取一下当前机器的IP
信息,已做参考:
root@debian:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:7c:92:af brd ff:ff:ff:ff:ff:ff
root@debian:~#
在Network Namespace
中执行命令
root@debian:~# unshare -n /usr/bin/bash
root@debian-linux:~#
root@debian-linux:~# ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@debian-linux:~#
使用unshare -n /usr/bin/bash
会创建一个Network Namespace
,并且在该Namespace
中执行bash
操作,使用exit
即可退出该Namespace
。
这是unshare
的最简单的用法。
修改提示符
Linux
的提示符格式都被记录到了PS1
的内置变量中,可以使用echo
查看其内容。
root@debian:~# echo $PS1
${debian_chroot:+($debian_chroot)}\u@\h:\w\$
root@debian:~#
为了方便使用unshare
启动新进程更加直观,所以需要修改一下命令提示符,首先在/root/.bashrc
文件末尾添加如下代码:
# 打开调试
set -x
# 定义默认的PS1值
export PS1="${debian_chroot:+($debian_chroot)}[\u@\h]:[\w][tty:\l]\\$ "
# 设置别名
alias unshare="UNSHARE=1 unshare "
# 如果变量中的UNSHARE值为1,则修改PS1值
if [ ! -e ${UNSHARE} ] && [ ${UNSHARE} -eq 1 ];then
export PS1="(unshare) ${debian_chroot:+($debian_chroot)}[\u@\h]:[\w][tty:\l]\\$ "
fi
# 关闭调试
set +x
增加上述代码后,重新加载一下/root/.bashrc
就可以使用unshare
启动bash
进程了。
首先先重新加载一下/root/.bashrc
文件
root@debian:~# source /root/.bashrc
++ export 'PS1=[\u@\h]:[\w][tty:\l]\$ '
++ PS1='[\u@\h]:[\w][tty:\l]\$ '
++ alias 'unshare=UNSHARE=1 unshare '
++ '[' '!' -e ']'
++ set +x
[root@debian]:[~][tty:1]#
使用unshare
启动bash
进程
[root@debian]:[~][tty:1]# unshare -n /usr/bin/bash
+ export 'PS1=[\u@\h]:[\w][tty:\l]\$ '
+ PS1='[\u@\h]:[\w][tty:\l]\$ '
+ alias 'unshare=UNSHARE=1 unshare '
+ '[' '!' -e 1 ']'
+ '[' 1 -eq 1 ']'
+ export 'PS1=(unshare) [\u@\h]:[\w][tty:\l]\$ '
+ PS1='(unshare) [\u@\h]:[\w][tty:\l]\$ '
+ set +x
(unshare) [root@debian]:[~][tty:1]#
通过上面设置,就可以更加直观的看出当前shell
是否在Namespace
中,后续为了信息更加简洁,所以就暂时将调试给关闭了。
命名空间文件描述符
在Linux
中,查看2个进程是否属于同一个命名空间,可以查看/proc/进程ID/ns/*
下面的文件描述符,如果文件描述符一致,则证明是处于同一命名空间的。
例如,如下2个进程的namespace
文件描述符如下:
[root@debian]:[~][tty:0]# readlink /proc/983/ns/*
cgroup:[4026531835]
ipc:[4026531839]
mnt:[4026531841]
net:[4026531840]
pid:[4026531836]
pid:[4026531836]
time:[4026531834]
time:[4026531834]
user:[4026531837]
uts:[4026531838]
[root@debian]:[~][tty:0]# readlink /proc/998/ns/*
cgroup:[4026531835]
ipc:[4026531839]
mnt:[4026531841]
net:[4026531840]
pid:[4026531836]
pid:[4026531836]
time:[4026531834]
time:[4026531834]
user:[4026531837]
uts:[4026531838]
[root@debian]:[~][tty:0]#
可以看到,其每项namespace
的文件描述符都是一致的,所以证明该2个进程属于同一命名空间。
如果是使用unshare
创建的命名空间,其namespace
文件描述符应该不一致。
# unshare -m /usr/bin/bash
(unshare) [root@debian]:[~][tty:0]# echo $$
1000
(unshare) [root@debian]:[~][tty:0]#
(unshare) [root@debian]:[~][tty:0]# readlink /proc/1000/ns/*
cgroup:[4026531835]
ipc:[4026531839]
mnt:[4026532316]
net:[4026531840]
pid:[4026531836]
pid:[4026531836]
time:[4026531834]
time:[4026531834]
user:[4026531837]
uts:[4026531838]
(unshare) [root@debian]:[~][tty:0]#
在该mount namespace
中,其mount namespace
文件描述符为4026532316。
(unshare) [root@debian]:[~][tty:0]# exit
exit
[root@debian]:[~][tty:0]# echo $$
983
[root@debian]:[~][tty:0]# readlink /proc/983/ns/*
cgroup:[4026531835]
ipc:[4026531839]
mnt:[4026531841]
net:[4026531840]
pid:[4026531836]
pid:[4026531836]
time:[4026531834]
time:[4026531834]
user:[4026531837]
uts:[4026531838]
[root@debian]:[~][tty:0]#
在该宿主机中,其mount namespace
文件描述符为4026531841。在宿主机的namespace
,也称之为默认namespace
。
可以看到,2个文件描述符不一致,说明2个进程是在不同的mount namespace
中。
各个Nmaespace介绍
UTS Namespace
UTS Namespace
是用来隔离主机名和域名的,可以使不同的Namespace
拥有不同的主机名。
使用unshare
进入bash
后尝试修改主机名,不会影响到宿主机的,例如如下:
[root@debian]:[~][tty:1]# unshare -u /usr/bin/bash
(unshare) [root@debian]:[~][tty:1]#
(unshare) [root@debian]:[~][tty:1]# echo $$
13858
(unshare) [root@debian]:[~][tty:1]#
(unshare) [root@debian]:[~][tty:1]# hostname new-debian-uts
(unshare) [root@debian]:[~][tty:1]#
(unshare) [root@debian]:[~][tty:1]# hostname
new-debian-uts
(unshare) [root@debian]:[~][tty:1]#
上述命令使用unshare
创建了一个uts namespace
,并且将bash
放入其中执行,首先打印了其进程的PID
为13858
、而后进行了主机名设置。
同时在不关闭该shell
的前提下,打开另一个终端,获取主机名信息。
[root@debian]:[~][tty:5]# hostname
debian
[root@debian]:[~][tty:5]#
[root@debian]:[~][tty:5]# echo $$
13863
[root@debian]:[~][tty:5]#
[root@debian]:[~][tty:5]#
可以看到,在uts namespace
命名空间中修改主机名,并不影响宿主机环境,同时,还可以查询一下2个进程的ns
值:
# readlink /proc/{13858,13863}/ns/uts
uts:[4026532256]
uts:[4026531838]
[root@debian]:[~][tty:5]#
可以看到,上述2个进程的uts namespace
文件描述符并不一致,所以是2个不同的命名空间,所以,修改主机名才不会互相影响。
IPC Namespace
ipc namespace
是隔离进程间的通信资源,但不是所有的进程间通信都会被隔离,它主要隔离 消息队列、信号量、共享内存等。
关于IPC
通信,是否可以被ipc namespace
隔离,可以查看如下表格:
IPC机制 | 需求 | IPC Namespace隔离 |
---|---|---|
管道、命名管道 | 进程间简单数据交换 | 不会隔离 |
消息队列 | 进程间异步信息交换 | 隔离 |
信号量 | 进程间同步和互斥 | 隔离 |
共享内存 | 进程间大块数据共享 | 隔离 |
套接字 | 进程间网络通信 | 不会隔离 |
这里举个简单的例子。
在宿主机上查询共享内存段信息。
[root@debian]:[~][tty:0]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 3 lightdm 600 524288 2 dest
0x00000000 4 lightdm 600 33554432 2 dest
[root@debian]:[~][tty:0]#
在宿主机创建一个新的共享内存段。
[root@debian]:[~][tty:0]# ipcmk -M 128
Shared memory id: 6
[root@debian]:[~][tty:0]#
[root@debian]:[~][tty:0]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 3 lightdm 600 524288 2 dest
0x00000000 4 lightdm 600 33554432 2 dest
0x8b111882 6 root 644 128 0
[root@debian]:[~][tty:0]#
而后在ipc namespace
中来查询共享内存段。
# unshare -i -u /usr/bin/bash
(unshare) [root@debian]:[~][tty:0]#
(unshare) [root@debian]:[~][tty:0]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
(unshare) [root@debian]:[~][tty:0]#
可以看到,在ipc namespace
中共享内存段都没了,同样的,在该namespace
中创建共享内存段,其宿主机也不可以间。
(unshare) [root@debian]:[~][tty:0]# ipcmk -M 128
Shared memory id: 0
(unshare) [root@debian]:[~][tty:0]#
(unshare) [root@debian]:[~][tty:0]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x4ec24363 0 root 644 128 0
(unshare) [root@debian]:[~][tty:0]#
在上述namespace
不退出的情况下,在宿主机中查询共享内存段。
[root@debian]:[~][tty:1]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 3 lightdm 600 524288 2 dest
0x00000000 4 lightdm 600 33554432 2 dest
0x8b111882 6 root 644 128 0
[root@debian]:[~][tty:1]#
如上例子说明,在ipc namespace
中,IPC
资源已被隔离。
Pid Namespace
Pid Namespace
是用来隔离进程ID
的,在Pid Namespace
中的进程都有独立的PID
。
使用unshare
创建pid namespace
并且获取当前PID
[root@debian]:[~][tty:2]# unshare -u -i -p --fork /usr/bin/bash
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]# echo $$
1
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]#
创建pid namespace
的时候,一定要加--fork
来fork
一个新的进程,因为只有新的子进程才会分配pid
,在使用pid namespace
后,新的命名空间中的pid
都会从1开始计数。
实际上查询进程树信息,可以发现linux
是做了一个转换,将宿主机的pid
会映射进pid namespace
中的进程ID
。
[root@debian]:[~][tty:1]# ps axjf | head -n 1
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 756 756 756 ? -1 SLsl 0 0:00 /usr/sbin/lightdm
756 777 777 777 tty7 777 Ssl+ 0 0:02 \_ /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
756 1104 756 756 ? -1 Sl 0 0:00 \_ lightdm --session-child 15 26
1104 1133 1133 1133 ? -1 Ssl 0 0:00 \_ /usr/bin/lxsession -s LXDE -e LXDE
1133 1228 1228 1228 ? -1 Ss 0 0:00 \_ /usr/bin/ssh-agent x-session-manager
1133 1259 1133 1133 ? -1 S 0 0:00 \_ openbox --config-file /root/.config/openbox/lxde-rc.xml
1133 1264 1133 1133 ? -1 Sl 0 0:00 \_ lxpolkit
1133 1266 1133 1133 ? -1 Sl 0 0:00 \_ lxpanel --profile LXDE
1133 1269 1133 1133 ? -1 Sl 0 0:00 \_ pcmanfm --desktop --profile LXDE
1269 1431 1133 1133 ? -1 Sl 0 0:00 | \_ lxterminal
1431 1434 1434 1434 pts/2 1469 Ss 0 0:00 | \_ bash
1434 1468 1468 1434 pts/2 1469 S 0 0:00 | \_ unshare -u -i -p --fork /usr/bin/bash
1468 1469 1469 1434 pts/2 1469 S+ 0 0:00 | \_ /usr/bin/bash
其实该bash
的进程id
为1469
,但是使用了pid namespace
,所以在该namesapce
中会被映射为了1
,此时若在宿主机上kill -9 1469
,则会影响到命名空间的进程。
[root@debian]:[~][tty:1]# kill -9 1469
[root@debian]:[~][tty:1]#
同样在命名空间中的进程会被kill
掉。
(unshare) [root@debian]:[~][tty:2]# unshare: sigprocmask unblock failed: Invalid argument
[root@debian]:[~][tty:2]#
Mount Namespace
Mount Namespace
是最早出现的Namespace
,可以看到其系统调用参数为 CLONE_NEWNS
,和后续出现的Namespace
系统调用参数都不同,这是因为最开始的时候,大佬们认为,不会在出现其他Namespace
了,所以就以此为命名,后面的事情,大家就都知道了,为了兼容,所以该Mount Namespace
还是以CLONE_NEWNS
来命名的。
Mount Namespace
的作用是实现文件系统的隔离和管理。
使用unshare
创建mount namespace
并且重新挂载proc
分区。
[root@debian]:[~][tty:2]# unshare -u -i -p -m --fork /usr/bin/bash
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]# echo $$
1
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]# mount -t proc proc /proc
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 7196 3996 pts/2 S 03:40 0:00 /usr/bin/bash
root 3 0.0 0.2 11084 4456 pts/2 R+ 03:40 0:00 ps aux
(unshare) [root@debian]:[~][tty:2]#
上述使用unshare
创建了mount namespace
,并且将bash
放入其执行,在该mount namespace
中,使用mount
重新挂载了proc
,接着查询所有进程,由于pid namesapce
隔离,所以只能查询到当前命名空间中的进程了。
默认的mount namespace
会继承宿主机的命名空间,若不进行重新挂载proc
,查看到的信息就是宿主机的信息。
同样的,在该namesapce
中设置的挂载,在宿主机是隔离开来的,例如:
(unshare) [root@debian]:[~][tty:2]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 19G 3.9G 14G 23% /
udev 953M 0 953M 0% /dev
tmpfs 984M 4.0K 984M 1% /dev/shm
tmpfs 197M 1004K 196M 1% /run
tmpfs 5.0M 8.0K 5.0M 1% /run/lock
tmpfs 197M 44K 197M 1% /run/user/1000
tmpfs 197M 44K 197M 1% /run/user/0
/dev/sda5 6.4G 348M 5.8G 6% /var
/dev/sda8 71G 1.2G 67G 2% /home
/dev/sda7 1.2G 68K 1.1G 1% /tmp
(unshare) [root@debian]:[~][tty:2]# mount /dev/sda1 /data
(unshare) [root@debian]:[~][tty:2]# mount | grep /data
/dev/sda1 on /data type ext4 (rw,relatime,errors=remount-ro)
(unshare) [root@debian]:[~][tty:2]#
在不退出当前mount namesapce
环境下,查询宿主机关于/data
的挂载。
[root@debian]:[~][tty:1]# mount /dev/sda1 /data
[root@debian]:[~][tty:1]#
如此,mount namespace
隔离了文件系统挂载。
Network Namespace
network namespace
隔离的是网络环境,网络通信是较为复杂的操作,这里先仅仅证明network namesapce
隔离性。
使用unshare
创建network namespace
,并且使bash
在其运行。
(unshare) [root@debian]:[~][tty:2]# unshare -u -i -p -m -n --fork /usr/bin/bash
(unshare) [root@debian]:[~][tty:2]#
(unshare) [root@debian]:[~][tty:2]# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
(unshare) [root@debian]:[~][tty:2]#
创建了network namespace
之后,查询其ip
信息,只有本地回环地址,状态还是关闭的,说明 network namespace
隔离了其网络环境。
User Namespace
user namespace
隔离的是用户和用户组,换句话说,不同的user namespace
中的user id
和group id
可以是不同的。最为常用的是在宿主机以一个非root
用户运行创建了一个user namespace
,然后在该user namespace
中却被映射成了root
用户。
使用unshare
创建user namespace
,并且使bash
在其运行。
[root@debian]:[~][tty:2]# unshare -u -i -p -m -n -U --fork /usr/bin/bash
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
(unshare) [nobody@debian]:[~][tty:2]$
可以看到,增加了user namespace
后,其用户被映射为了nobody
用户。
如果想要修改其容器中的userid
值,可以使用newuidmap
进行uid
映射。
首先,需要找到其user namespace
下运行进程的pid
。
[root@debian]:[~][tty:0]# ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 756 756 756 ? -1 SLsl 0 0:00 /usr/sbin/lightdm
756 2547 2547 2547 tty7 2547 Ssl+ 0 0:01 \_ /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
756 2633 756 756 ? -1 Sl 0 0:00 \_ lightdm --session-child 15 26
2633 2637 2637 2637 ? -1 Ssl 0 0:00 \_ /usr/bin/lxsession -s LXDE -e LXDE
2637 2729 2729 2729 ? -1 Ss 0 0:00 \_ /usr/bin/ssh-agent x-session-manager
2637 2749 2637 2637 ? -1 S 0 0:00 \_ openbox --config-file /root/.config/openbox/lxde-rc.xml
2637 2750 2637 2637 ? -1 Sl 0 0:00 \_ lxpolkit
2637 2752 2637 2637 ? -1 Sl 0 0:00 \_ lxpanel --profile LXDE
2637 2754 2637 2637 ? -1 Sl 0 0:00 \_ pcmanfm --desktop --profile LXDE
2754 2886 2637 2637 ? -1 Sl 0 0:00 | \_ lxterminal
2886 2889 2889 2889 pts/2 2916 Ss 0 0:00 | \_ bash
2889 2915 2915 2889 pts/2 2916 S 0 0:00 | \_ unshare -u -i -p -m -n -U --fork /usr/bin/bash
2915 2916 2916 2889 pts/2 2916 S+ 0 0:00 | \_ /usr/bin/bash
可以看到,其真实的pid
是2916
,则在宿主机上需要执行如下映射。
[root@debian]:[~][tty:1]# newuidmap 2916 0 0 1
[root@debian]:[~][tty:1]#
此时,再回到user namespace
中,查看用户信息。
(unshare) [nobody@debian]:[~][tty:2]$ id
uid=0(root) gid=65534(nogroup) groups=65534(nogroup)
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$ mount -t proc proc /proc
(unshare) [nobody@debian]:[~][tty:2]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 7196 3876 pts/2 S 04:42 0:00 /usr/bin/bash
root 8 0.0 0.2 11084 4328 pts/2 R+ 04:49 0:00 ps aux
(unshare) [nobody@debian]:[~][tty:2]$
其uid
则变为了root
,也可以进行磁盘挂载。
当然,在普通用户下,也是同理。
使用普通用户使用unshare
创建user namespace
并且启动bash
命令。
[wangli@debian]:[~][tty:2]$ unshare -u -i -p -m -n -U --fork /usr/bin/bash
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$
查询其真实的pid
。
[root@debian]:[~][tty:0]# ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 756 756 756 ? -1 SLsl 0 0:00 /usr/sbin/lightdm
756 2992 2992 2992 tty7 2992 Ssl+ 0 0:01 \_ /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
756 3077 756 756 ? -1 Sl 0 0:00 \_ lightdm --session-child 14 26
3077 3083 3083 3083 ? -1 Ssl 1000 0:00 \_ /usr/bin/lxsession -s LXDE -e LXDE
3083 3169 3169 3169 ? -1 Ss 1000 0:00 \_ /usr/bin/ssh-agent x-session-manager
3083 3185 3083 3083 ? -1 S 1000 0:00 \_ openbox --config-file /home/wangli/.config/openbox/lxde-rc.xml
3083 3186 3083 3083 ? -1 Sl 1000 0:00 \_ lxpolkit
3083 3189 3083 3083 ? -1 Sl 1000 0:00 \_ lxpanel --profile LXDE
3083 3192 3083 3083 ? -1 Sl 1000 0:00 \_ pcmanfm --desktop --profile LXDE
3192 3387 3083 3083 ? -1 Sl 1000 0:00 | \_ lxterminal
3387 3390 3390 3390 pts/2 3418 Ss 1000 0:00 | \_ bash
3390 3417 3417 3390 pts/2 3418 S 1000 0:00 | \_ unshare -u -i -p -m -n -U --fork /usr/bin/bash
3417 3418 3418 3390 pts/2 3418 S+ 1000 0:00 | \_ /usr/bin/bash
查询到其PID
为3418,在另外的终端,执行newuidmap
操作
[wangli@debian]:[/root][tty:1]$ id
uid=1000(wangli) gid=1000(wangli) groups=1000(wangli),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),111(lpadmin),114(scanner)
[wangli@debian]:[/root][tty:1]$
[wangli@debian]:[/root][tty:1]$ newuidmap 3418 0 1000 1
[wangli@debian]:[/root][tty:1]$
请注意,这里loweruid
设置为了1000,这是因为wangli
这个用户的uid
为1000。
此时再到user namespace
中查看id
信息。
(unshare) [nobody@debian]:[~][tty:2]$ id
uid=0(root) gid=65534(nogroup) groups=65534(nogroup)
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$ mount -t proc proc /proc
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 8008 4720 pts/2 S 04:55 0:00 /usr/bin/bash
root 6 0.0 0.2 11084 4440 pts/2 R+ 05:02 0:00 ps aux
(unshare) [nobody@debian]:[~][tty:2]$
可以看到,其uid
已经被映射为了root
,此时,执行mount
进行挂载也可以实现。
Time Namespace
Time Nmaespace
允许进程在独立的时间上下文中运行。使用了time namespace
的进程可以拥有自己独立的时间视图并且和其他time namespace
和宿主机隔离开来。
下面举一个最简单的例子:
先查询系统启动的秒数
[wangli@debian]:[~][tty:2]$ cat /proc/uptime
11397.34 10829.19
[wangli@debian]:[~][tty:2]$
使用unshare
启动time namespace
命名空间,且运行bash
进程。
[wangli@debian]:[~][tty:2]$ unshare -u -i -p -m -n -U -T --boottime -11397 --fork /usr/bin/bash
(unshare) [nobody@debian]:[~][tty:2]$ uptime
05:36:09 up 0 min, 3 users, load average: 0.00, 0.01, 0.00
(unshare) [nobody@debian]:[~][tty:2]$
(unshare) [nobody@debian]:[~][tty:2]$
在命名空间中,可以看到,其uptime
的启动时间已经为0了。
在不退出time namespace
的情况下,开一个新的shell
来查看uptime
信息
[wangli@debian]:[~][tty:3]$ uptime
05:39:01 up 3:12, 3 users, load average: 0.00, 0.01, 0.00
[wangli@debian]:[~][tty:3]$
由此证明,time namespace
对于系统时间的隔离性。
总结
首先,在介绍Linux Nmaespace
之前先进行了前置准备,包括 unshare
工具的使用、修改提示符、命名空间文件描述符的基本说明等。
而后就介绍了Linux Namespace
基本信息,归纳如下:
Linux Nmaespace
是Linux
内核一项强大的功能,是容器化的基石,至目前为止,一共有7种类别的Namespace
,按照发布时间顺序,分别是:
Mount Namespace
:隔离文件系统。UTS Namespace
: 隔离主机名和域名。IPC Namespace
:隔离进程间通信。PID Namespace
:隔离进程ID。Network Namespace
:隔离网络。User Namespace
:隔离用户和组。Time Namespace
:隔离系统时钟。
如上众多的Namespace
使得在同一台机器上运行多个“独立”的进程环境,称为可能,所以Linux Namespace
才是容器化的基础。
Linux Namespace 简单理解
https://wangli2025.github.io/2024/11/05/Linux-Namespace.html
本站均为原创文章,采用 CC BY-NC-ND 4.0 协议。转载请注明出处,不得用于商业用途。