文章转自简书:点我传送

Linux 3.8内核中包括了6种命名空间:

命名空间描述
Mount(mnt)隔离挂载点
Process ID(process)隔离进程ID
Network(net)隔离网络设备、协议栈、端口等
InterProcess Communication(ipc)隔离进程间通信
UTS隔离Hostname和NIS域名
User ID(user)隔离用户和group ID

创建一个新的network namespace

ip netns add blue

查看新创建network namespace

ip netns list

分配一个网络接口给Network Namespaces

首先我们考虑一下虚拟网卡Veth, veth很有意思;它都是成对出现的,就像一个管道的两端,从这个管道的一端的veth进去的数据会从另一端的veth再出来。也就是说,你可以使用veth接口把一个网络命名空间连接到外部的默认命名空间或者global命名空间,而物理网卡就存在这些命名空间里。
首先我们来创建一个veth对:

ip link add veth0 type veth peer name veth1

这一条命令就会同时创建veth0和veth1两个虚拟网卡,运行如下命令来验证一下

ip link list

这个时候你就可以看到这一对veth接口了

9: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether be:68:5b:da:60:1d brd ff:ff:ff:ff:ff:ff
10: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether d2:70:e9:c1:31:2f brd ff:ff:ff:ff:ff:ff

这个时候这两个网卡还都属于“default”或“global”命名空间,和物理网卡一样。
现在我们要把这个global namesapce连接到blue namespace,做法就是把其中的一个veth转移到blue命名空间中去。

ip link set veth1 netns blue

这个时候再用命令ip link list来查看就会发现veth1不见了,这个时候veth1以及设置到了blue命名空间中了,运行如下命令查看。

sudo ip netns exec blue ip link

这个时候你可以看到里面有两个网络接口

  • 一个是回环网络lo
  • 另一个是veth1
[vagrant@docker-node1 ~]$ sudo ip netns exec blue  ip link
1: lo: &lt;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
5: veth1@if6: &lt;BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 42:f1:e7:f7:b5:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0

配置Network Namespaces里面的网络接口

可以通过运行如下命令来配置blue命名空间中的veth1接口

 ip netns exec blue ip addr add 10.1.1.1/24 dev veth1
 ip netns exec blue ip link set veth1 up
 ip netns exec blue ip link set lo up

这个命令中,通过ip addr add命令给veth1分配了一个IP 地址,并且把这个网卡启动了;同时也启动了回环网卡;
然后查看一下blue命名空间里面的两个网卡的状态

[vagrant@docker-node1 ~]$ sudo ip netns exec blue ip addr show
1: lo: &lt;LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
5: veth1@if6: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
    link/ether 42:f1:e7:f7:b5:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.1.1/24 scope global veth1
       valid_lft forever preferred_lft forever

同时还需要配置一下host上面对端网卡的ip

 ip addr add 10.1.1.2/24 dev veth0
 ip link set veth0 up

这个时候在blue命名空间里面ping 10.1.1.1(veth1)已经ok了

[vagrant@docker-node1 ~]$ sudo ip netns exec blue ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.026 ms

但是依旧ping不通10.1.1.2(veth0)
这是因为blue命名空间中的路由还没有设置。

设置命名空间内的路由

通过如下命令来设置一个默认路由

 sudo ip netns exec blue ip route add default via 10.1.1.1
 sudo ip netns exec blue ip route show
default via 10.1.1.1 dev veth1

所有找不到目的地址的数据包都通过设备veth1转发出去。
这个时候就可以成功ping通host上的veth0网卡了

sudo ip netns exec blue ping 10.1.1.2

PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.052 ms

但是到了这里依旧还不够,blue命名空间中已经可以联通主机上的网络,但是依旧连不同主机以外的外部网络。这个时候必须在host主机上启动转发,并且在iptables中设置伪装

使能IP转发:IP_FORWARD

Linux系统的IP转发的意思是,当Linux主机存在多个网卡的时候,允许一个网卡的数据包转发到另外一张网卡;在linux系统中默认禁止IP转发功能,可以打开如下文件查看,如果值为0说明禁止进行IP转发

cat /proc/sys/net/ipv4/ip_forward

运行如下的命令,其中ens160是host的一个对外网卡,这样的就允许ens160和veth0之间的转发;也就是说blue命名空间可以和外网联通了。

#使能ip转发

echo 1 > /proc/sys/net/ipv4/ip_forward

#刷新forward规则
iptables -F FORWARD
iptables -t nat -F

#刷新nat规则
iptables -t nat -L -n

#使能IP伪装
iptables -t nat -A POSTROUTING -s 10.1.1.0/255.255.255.0 -o ens160 -j MASQUERADE

#允许veth0和ens160之间的转发
iptables -A FORWARD -i ens160 -o veth0 -j ACCEPT
iptables -A FORWARD -o ens160 -i veth0 -j ACCEPT
  • 使能IP伪装这条语句,添加了一条规则到NAT表的POSTROUTING链中,对于源IP地址为10.1.1.0网段的数据包,用ens160网口的IP地址替换并发送。
  • iptables -A FORWARD这两条语句使能物理网口ens160和veth0之间的数据转发

演示一下整个流程

图

完整的示例代码

#!/bin/bash
#Create new namesapce
ip netns delete ns1
ip netns add ns1

ip link add veth0 type veth peer name veth1
ip link set veth0 netns ns1

echo "====Create New Network namespace and spcify a eth===="
ip netns list
ip netns ns exec if config -a

#Assign the IP and bring up
ip addr add 10.100.1.1/24 dev veth1
ip link set veth1 up

ip netns exec ns1 ip addr add 10.100.1.2/24 dev veth0
ip netns exec ns1 ip link set veth0 up
ip netns exec ns1 ip link set lo up

echo "====Bring up the veth0 and lo inside Namespace===="
ip netns exec ns1 ip addr show

#add route inside namespace
ip netns exec ns1 ip route add default via 10.100.1.1

echo "====Add new default rout inside the namespace===="
ip netns exec ns1 ip route show

echo "====Tryting to ping the veth1 on host===="
ip netns exec ns1 ping 10.100.1.1 -c 4

#Config the host to enable forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -P FORWARD DROP
iptables -F FORWARD

iptables -t nat -F

#enalbe masquerading of 10.100.1.0
iptables -t nat -A POSTROUTING -s 10.100.1.0/255.255.255.0 -o ens160 -j MASQUERADE

#Allow forwarding
iptables -A FORWARD -i ens160 -o veth1 -j ACCEPT
iptables -A FORWARD -o ens160 -i veth1 -j ACCEPT

echo "====Enable the forwarding of veth1 to ens160(NIC)on host ===="
echo "Show the iptables of filter"
iptables -L -n

echo "Show the iptables of nat"
iptables -t nat -L -n

用linux网络命名空间模拟docker里面两个容器相互通信

图

重启新设置网络环境

ip link add veth0 type veth peer name veth1

把veth0放入到test0的ip网络命名空间里面

 sudo  ip link set veth0 netns test0
 sudo ip netns exec test0 ip link

图

把veth1放入到test1的ip网络命名空间里面

sudo  ip link set veth1 netns test1
sudo ip link #这时候的ip link 里面少了两个

这时候test1的命名空间ip link是两个

sudo ip netns exec test1 ip link

给test0 和 test1这两个命名空间下的veth0和veth1添加ip地址

 sudo ip netns exec test0 ip addr add 192.168.1.1/24 dev veth0
 sudo ip netns exec test1 ip addr add 192.168.1.2/24 dev veth1

把两个命名空间的网卡veth0和veth1启动

sudo ip netns exec test0 ip link set dev veth0 up
sudo ip netns exec test1 ip link set dev veth1 up

两个已经链接起来通过ping命令测试

[vagrant@docker-node1 ~]$ sudo ip netns exec test0 ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.068 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.062 ms
[vagrant@docker-node1 ~]$ sudo ip netns exec test1 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.035 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.063 ms

docker模拟结束。

相关好文:https://segmentfault.com/a/1190000009251098

原文地址:https://www.jianshu.com/p/369e50201bce

类似文章:https://blog.csdn.net/zhanglidn013/article/details/70241732

Last modification:January 31, 2020
如果觉得我的文章对你有用,请随意赞赏