docker-简单说说namespace

发布时间:2024年01月04日

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

我们可以通过 ls -l /proc/$$/ns 查看服务器有哪些 namespace

[root@linjian ~]# ls -l /proc/$$/ns 
total 0
lrwxrwxrwx 1 root root 0 Jan  2 16:25 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jan  2 16:25 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Jan  2 16:25 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Jan  2 16:25 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jan  2 16:25 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jan  2 16:25 uts -> uts:[4026531838]

常见操作

clone: 创建一个新的进程并把他放到新的namespace中

setns:?将当前进程加入到已有的namespace中

unshare: 使当前进程退出指定类型的namespace,并加入到新创建的namespace(相当于创建并加入新的namespace)

nsenter -t <pid> -n ip addr: 进入某 namespace 运行命令

lsns –t <type>: 查看当前系统的 namespace

ls -la /proc/<pid>/ns/: 查看某进程的 namespace

我很重要!!!

clone和unshare区别:

  • unshare是使当前进程加入新的namespace
  • clone是创建一个新子进程,然后让子进程加入新的namespace并当保持前进程不变

类型

Linux 中有以下 6 种不同的 namespace,每种 namespace 对于容器技术的实现具有不同的作用和意义:

  1. ipc 每个容器有其自己的 System V IPCPOSIX?消息队列文件系统,因此,只有在同一个 IPC namespace 的进程之间才能互相通信
  2. mnt: 隔离文件系统的挂载点, 使得不同的mount namespace拥有自己独立的挂载点信息,不同的namespace之间不会相互影响
  3. net: 容器拥有独立的网络设备(网络栈,路由表,防火墙规则,socket,端口号等等)。这也使得一个 host 上多个容器内的同一个应用都绑定到各自容器的 80 端口上。
  4. pid: 用于隔离容器内的进程编号空间,使得在不同的 PID Namespace 中运行的进程看起来像是在独立的进程空间中运行
  5. user: User Namespace 用于隔离用户和用户组的id。在容器中运行的进程可以拥有唯一的 UID 和 GID,这样做可以避免容器进程干扰宿主机进程,提高容器进程的独立性。
  6. uts:UTS Namespace 用于隔离主机名和域名等系统识别信息。为不同的容器分配不同的容器名,从而避免名称冲突,提高了容器之间的独立性。

IPC

ipc namespace 的一种用例是将两个进程之间的共享内存 (SHM) 分开,以避免误用。相反每个进程将能够对共享内存段使用相同的标识符并生成两个不同的区域。当一个IPC命名空间被销毁时,该命名空间中的所有IPC对象也会自动被销毁

常见操作

ipcmk: 创建队列(-q),信号量(-s),共享内存(-m),权限(-p)

ipcms: 查看队列(-q),查看信号量(-s),查看共享内存(-m),

ipc隔离案例

终端1

# 创建队列
[root@linjian ~]# ipcmk -Q  
Message queue id: 0
# 发送消息 
[root@linjian ~]# ipcmk -Q
Message queue id: 0
# 查看队列
[root@linjian ~]# ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x9c65478f 0          root       644        0            0
# 查询ipc 信息
[root@linjian ~]# readlink /proc/$$/ns/ipc
ipc:[4026531839]

终端2

# 查看队列
[root@linjian ~]# ipcs -q
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x9c65478f 0          root       644        0            0 
# 查询ipc 信息
[root@linjian ~]# readlink /proc/$$/ns/ipc 
ipc:[4026531839]
# 启动新的ipc namespace (-i)
[root@linjian ~]# sudo unshare -i /bin/bash
# 看不到刚才那个队列消息
[root@linjian ~]#  ipcs -q 
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    

mnt

mnt 是第一个实现的命名空间。之前大部分人认为不需要多个命名空间,因此他们决定命名空间 取名为 CLONE_NEWNS。通过 mnt 命名空间,Linux 能够通过一组进程隔离一组挂载点,对构建用户或者容器自己的文件系统目录非常有用。

当前进程所在mount ns 里的所有挂载信息可以在/proc/[pid]/mounts、/proc/[pid]/mountinfo和/proc/[pid]/mountstats里面找到。每个mount namespace都拥有一份自己的挂载点列表,当用clone或者unshare函数创建新的mount namespace时,新创建的namespace将拷贝一份老namespace里的挂载点列表,但从这之后,他们就没有关系了,通过mount和umount增加和删除各自namespace里面的挂载点都不会相互影响。

隔离案例

客户端1

[root@linjian testMnt]# readlink /proc/$$/ns/mnt
mnt:[4026531840]
# 创建好对应文件
[root@linjian testMnt]# tree
.
├── mnt01
│?? └── mnt011
├── mnt01.iso
├── mnt02
│?? └── mnt021
└── mnt02.iso

4 directories, 2 files
# 挂载
[root@linjian testMnt]# mount ./mnt01.iso ./mnt01/mnt011
mount: /dev/loop0 is write-protected, mounting read-only
[root@linjian testMnt]# mount |grep mnt01.iso
/home/testMnt/mnt01.iso on /home/testMnt/mnt01/mnt011 type iso9660 (ro,relatime)
# mnt namespace
[root@linjian testMnt]# unshare --mount --uts /bin/bash
[root@linjian testMnt]# exec bash
[root@linjian testMnt]# readlink /proc/$$/ns/mnt
mnt:[4026532715]
[root@linjian testMnt]# mount |grep mnt01.iso
/home/testMnt/mnt01.iso on /home/testMnt/mnt01/mnt011 type iso9660 (ro,relatime)
[root@linjian testMnt]# mount ./mnt02.iso ./mnt02/mnt021
mount: /dev/loop1 is write-protected, mounting read-only
[root@linjian testMnt]# mount |grep mnt
/home/testMnt/mnt01.iso on /home/testMnt/mnt01/mnt011 type iso9660 (ro,relatime)
/home/testMnt/mnt02.iso on /home/testMnt/mnt02/mnt021 type iso9660 (ro,relatime)
[root@linjian testMnt]# umount ./mnt01.iso 
[root@linjian testMnt]# mount |grep mnt
/home/testMnt/mnt02.iso on /home/testMnt/mnt02/mnt021 type iso9660 (ro,relatime)

客户端2

[root@linjian ~]# readlink /proc/$$/ns/mnt
mnt:[4026531840]
[root@linjian ~]# mount |grep mnt
/home/testMnt/mnt01.iso on /home/testMnt/mnt01/mnt011 type iso9660 (ro,relatime)

net

network namespace用来隔离网络设备, IP地址, 端口等. 每个namespace将会有自己独立的网络栈,路由表,防火墙规则,socket等。

每个新的network namespace默认有一个本地环回接口,除了lo接口外,所有的其他网络设备(物理/虚拟网络接口,网桥等)只能属于一个network namespace。每个socket也只能属于一个network namespace。

当新的network namespace被创建时,lo接口默认是关闭的,需要自己手动启动起

标记为"local devices"的设备不能从一个namespace移动到另一个namespace,比如loopback, bridge, ppp等,我们可以通过ethtool -k命令来查看设备的netns-local属性。

[root@linjian ~]# ethtool -k lo|grep netns-local
netns-local: on [fixed]

net隔离案例

客户端1

[root@linjian ~]# readlink /proc/$$/ns/net
net:[4026531956]
# 新建network namespace
[root@linjian ~]# unshare --uts --net /bin/bash
[root@linjian ~]# readlink /proc/$$/ns/net
net:[4026532719]
[root@linjian ~]# ifconfig
[root@linjian ~]# ip link set lo up
[root@linjian ~]# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@linjian ~]# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.046 ms
[root@linjian ~]# echo $$
13619

客户端2

[root@linjian ~]# readlink /proc/$$/ns/net
net:[4026531956]
[root@linjian ~]# echo $$
13586
[root@linjian ~]# ip link add veth0 type veth peer name veth1
[root@linjian ~]# ip link set veth1 netns 13619(这个是客户端1的进程id)
[root@linjian ~]# ip address add dev veth0 192.168.1.1/24
[root@linjian ~]# ip link set veth0 up
[root@linjian ~]# ifconfig veth0
veth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.1.1  netmask 255.255.255.0  broadcast 0.0.0.0
        ether d2:58:8f:c4:9a:40  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@linjian ~]# echo $$
13586

客户端1


[root@linjian ~]# ip address add dev veth1 192.168.1.2/24
[root@linjian ~]# ip link set veth1 up
[root@linjian ~]# ifconfig veth1
veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.2  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::3090:b2ff:fe5a:89b8  prefixlen 64  scopeid 0x20<link>
        ether 32:90:b2:5a:89:b8  txqueuelen 1000  (Ethernet)
        RX packets 7  bytes 586 (586.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 7  bytes 586 (586.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@linjian ~]# ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.058 ms
^C
--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.058/0.061/0.063/0.002 ms

pid

PID namespaces用来隔离进程的ID空间,使得不同pid namespace里的进程ID可以重复且相互之间不影响。PID namespace可以嵌套,父namespace里面可以看到所有子孙后代namespace里的进程信息,而子namespace里看不到祖先或者兄弟namespace里的进程信息。

在 PID 命名空间中创建的第一个进程的 id 为 1,并获得外面 init 进程相同的特殊待遇。例如,命名空间内的所有进程将重新设置为命名空间的 PID 1,而不是主机 PID 1。此外,终止此进程将立即终止其 PID 命名空间中的所有进程及其任何后代。

隔离案例

# namespace的ID
[root@linjian ~]# readlink /proc/self/ns/pid
pid:[4026531836]
# 创建新的pod namespace
[root@linjian ~]# unshare --uts --pid --mount --fork /bin/bash
# 切换到一个新的 bash shell 环境
[root@linjian ~]# exec bash
# 找到你执行unshare进程
[root@linjian ~]# pstree -pl
           ├─sshd(1173)─┬─sshd(2526)───bash(2534)
           │            └─sshd(2914)───bash(2916)───unshare(2952)───bash(2953)───pstree(2982)
# 	其实你可以看到当前已经是 进程 id 1了
[root@linjian ~]# echo $$
1
# 和刚刚开始ns id一样
[root@linjian ~]# readlink /proc/2952/ns/pid
pid:[4026531836]
# 新的ns id
[root@linjian ~]# readlink /proc/2953/ns/pid
pid:[4026532718]
# 这里一样是需要把信息文件挂载过去
[root@linjian ~]# readlink /proc/$$/ns/pid
pid:[4026531836]
[root@linjian ~]# mount -t proc proc /proc
[root@linjian ~]# readlink /proc/$$/ns/pid
pid:[4026532718]
[root@linjian ~]# 
[root@linjian ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:35 pts/1    00:00:00 bash
root        32     1  0 13:39 pts/1    00:00:00 ps -ef
[root@linjian ~]# exit
exit
[root@linjian ~]# readlink /proc/self/ns/pid
pid:[4026531836]

user

用户命名空间使得进程的用户和组 ID 在命名空间内部和外部可以不同。进程可以在用户命名空间之外拥有非root 用户 ID,同时在内部拥有root 权限。换句话说,该进程没有权限进行用户命名空间之外的操作,但在命名空间内具有 root 权限

隔离案例

[root@linjian ~]# readlink /proc/$$/ns/user
user:[4026531837]
[root@linjian ~]# id
uid=0(root) gid=0(root) groups=0(root)
[root@linjian ~]# unshare --user /bin/bash
/usr/bin/id: cannot find name for group ID 65534
/usr/bin/id: cannot find name for user ID 65534
[I have no name!@linjian ~]$ id
uid=65534 gid=65534 groups=65534
[I have no name!@linjian ~]$ readlink /proc/$$/ns/user
user:[4026532718]

这里我执行unshare --user /bin/bash 报错了,/proc/sys/user/max_user_namespaces是0(可修改user ns 数量),将max_user_namespaces 修改非0 就行了

uts

UTS Namespace 用于隔离主机名和域名等系统识别信息。为不同的容器分配不同的容器名,从而避免名称冲突,提高了容器之间的独立性。

隔离案例

以hostname 为例

客户端1:

[root@linjian ~]# hostname
linjian

客户端2:l

[root@linjian ~]# hostname
linjian
[root@linjian ~]# unshare -u
[root@linjian ~]# hostname testUts
[root@linjian ~]# hostname 
testUts

链接?

https://www.cnblogs.com/sammyliu/p/5878973.html

文章来源:https://blog.csdn.net/lin_keys/article/details/135365454
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。