Namespace介绍

Posted by 胡伟煌 on 2021-07-20

1. Namespace简介

Namespace是内核的一个功能,用来给进程隔离一系列系统资源(视图隔离)。

2. 类别

namespace类别 隔离资源 系统调用参数 内核版本 Docker中的例子
Mount namespace 挂载点 CLONE_NEWNS 2.4.19 独立的挂载点
UTS Namespace hostname和domainname CLONE_NEWUTS 2.6.19 独立的hostname
IPC Namespace System V IPC, POSIX message queues CLONE_NEWIPC 2.6.19
PID Namespace 进程ID CLONE_NEWPID 2.6.24 容器进程PID为1
Network Namespace 网络设备,端口,网络栈 CLONE_NEWNET 2.6.24 独立的网络和端口
User Namespace 用户ID,group ID CLONE_NEWUSER 3.8 独立的用户ID

3. Namespace API

API 说明
clone() 基于某namespace创建新进程,他们的子进程也包含在该namespace中
unshare() 将进程移出某个namespace
setns() 将进程加入某个namespace

4. namespace细分

4.1. Mount Namespace

Mount Namespace可以用了隔离各个进程的挂载点视图。不同的namespace中文件系统层次不一样,在其中调用mount和umount仅影响当前namespace。

4.2. Network Namespace

Network Namespace用来隔离网络设备,IP地址端口等网络栈。容器内可以绑定自己的端口,在宿主机建立网桥,就可以实现容器之间的通信。

ip netns 命令用来管理 network namespace。

1
2
3
4
5
6
7
8
9
10
# ip netns help
Usage: ip netns list
ip netns add NAME
ip netns set NAME NETNSID
ip [-all] netns delete [NAME]
ip netns identify [PID]
ip netns pids NAME
ip [-all] netns exec [NAME] cmd ...
ip netns monitor
ip netns list-id

示例:

模拟创建docker0及docker网络

1、创建lxcbr0,相当于docker0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加一个网桥lxcbr0,相当于docker0
brctl addbr lxcbr0
brctl stp lxcbr0 off
ifconfig lxcbr0 192.168.10.1/24 up # 配置网桥IP地址

# 查看网桥
# ifconfig
lxcbr0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.1 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::94cb:eaff:fe48:cdd5 prefixlen 64 scopeid 0x20<link>
ether 96:cb:ea:48:cd:d5 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 426 (426.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

添加网络命名空间

1
2
3
4
# 添加网络命名空间ns1
ip netns add ns1
# 激活namespace中的loopback,即127.0.0.1
ip netns exec ns1 ip link set dev lo up

3、添加虚拟网卡

1
2
3
4
# 增加一个pair虚拟网卡,注意其中的veth类型,其中一个网卡要按进容器中
ip link add veth-ns1 type veth peer name lxcbr0.1
# 把 veth-ns1 按到namespace ns1中,这样容器中就会有一个新的网卡了
ip link set veth-ns1 netns ns1

4、修改容器内网卡为eth0,并分配IP

1
2
3
4
# 把容器里的 veth-ns1改名为 eth0 (容器外会冲突,容器内就不会了)
ip netns exec ns1 ip link set dev veth-ns1 name eth0
# 为容器中的网卡分配一个IP地址,并激活它
ip netns exec ns1 ifconfig eth0 192.168.10.11/24 up

5、将lxcbr0.1添加上网桥

1
2
# 上面我们把veth-ns1这个网卡按到了容器中,然后我们要把lxcbr0.1添加上网桥上
brctl addif lxcbr0 lxcbr0.1

6、添加路由

1
2
# 为容器增加一个路由规则,让容器可以访问外面的网络
ip netns exec ns1 ip route add default via 192.168.10.1

7、添加nameserver

1
2
3
4
# 在/etc/netns下创建network namespce名称为ns1的目录,
# 然后为这个namespace设置resolv.conf,这样,容器内就可以访问域名了
mkdir -p /etc/netns/ns1
echo "nameserver 8.8.8.8" > /etc/netns/ns1/resolv.conf

8、查看网络空间内的网络配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 进入网络命名空间
ip netns exec ns1 bash
# 查看网络配置
ifconfig
eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.10.11 netmask 255.255.255.0 broadcast 192.168.10.255
ether 2a:0c:a8:b7:bc:32 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

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 4 bytes 240 (240.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4 bytes 240 (240.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

9、进入现有docker容器的网络命名空间

由于docker默认隐藏了/var/run/netns下的命名空间,因此需要做软链接,容器的1号进程的pid下的ns软链到/var/run/netns

1
2
ln -sf /proc/<container-pid>/ns/net "/var/run/netns/<container-id>"
ip netns exec <container-id> bash

参考:



支付宝打赏 微信打赏

赞赏一下