Skip to content

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 放入其中执行,首先打印了其进程的PID13858 、而后进行了主机名设置。

同时在不关闭该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 的时候,一定要加--forkfork一个新的进程,因为只有新的子进程才会分配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 的进程id1469 ,但是使用了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 idgroup 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

可以看到,其真实的pid2916,则在宿主机上需要执行如下映射。

[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 NmaespaceLinux内核一项强大的功能,是容器化的基石,至目前为止,一共有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 协议。转载请注明出处,不得用于商业用途。

Comments