路漫漫其修远兮
吾将上下而求索

docker学习:网络名称空间

下面是简单介绍

image.png

linux 的强大的网络配置命令:ip
[root@master ~]#ip
Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
       ip [ -force ] -batch filename
where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
                   netns | l2tp | macsec | tcp_metrics | token }
       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
                    -h[uman-readable] | -iec |
                    -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |
                    -4 | -6 | -I | -D | -B | -0 |
                    -l[oops] { maximum-addr-flush-attempts } |
                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
                    -rc[vbuf] [size] | -n[etns] name | -a[ll] }

netns可以让一台机器上模拟多个网络设备,是网络虚拟化的重要组成,将不同类型的网络应用隔离。
一个net namespace有自己独立的路由表,iptables策略,设备管理。说来说去,它就是用来隔离的。比如将eth0加入了netns 1,
那么netns 2中的应用程序就找不到eth0了。netns 1中的iptables策略,不会去影响netns 2中的iptables策略。

netns的用法
[root@master ~]#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

先打开内核的网络转发功能。
[root@master ~]#vim /etc/sysctl.conf 
[root@master ~]#sysctl -p
net.ipv4.ip_forward = 1

添加两个namespace
[root@master ~]#ip netns add ns1
[root@master ~]#ip netns add ns2

[root@master ~]#ip netns list
ns2
ns1

查看ns1的网络
[root@master ~]#ip netns exec ns1 ifconfig -a
lo: flags=8<LOOPBACK>  mtu 65536
        loop  txqueuelen 0  (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

为ns1的回环接口添加一个ip地址
[root@master ~]#ip netns exec ns1 ifconfig lo 127.0.0.1 up
[root@master ~]#ip netns exec ns1 ifconfig -a
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 0  (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

此时的ns2并没有地址,因为他们是被隔离的
在网络名称空间上添加一对网卡,一个在ns1,一个在ns2.
[root@master ~]#ip link show 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 00:50:56:34:bc:93 brd ff:ff:ff:ff:ff:ff

这里可以看做是创建了一条线,这条线有两个接口,叫做veth1.1和veth1.2,后面会用这条线连接两个网络名称空间
[root@master ~]#ip link add veth1.1 type veth peer name veth1.2

[root@master ~]#ip link show 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 00:50:56:34:bc:93 brd ff:ff:ff:ff:ff:ff
3: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 32:97:c0:a3:ed:1d brd ff:ff:ff:ff:ff:ff
4: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether ba:68:96:8e:83:53 brd ff:ff:ff:ff:ff:ff

将一对网卡分别添加给2个名称空间。
[root@master ~]#ip link set veth1.1 netns ns1
[root@master ~]#ip link set veth1.2 netns ns2

[root@master ~]#ip netns exec ns1 ifconfig -a
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 0  (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

veth1.1: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether ba:68:96:8e:83:53  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@master ~]#ip netns exec ns2 ifconfig -a
lo: flags=8<LOOPBACK>  mtu 65536
        loop  txqueuelen 0  (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

veth1.2: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 32:97:c0:a3:ed:1d  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


给ns1的veth1.1改个名字eth0        
[root@master ~]#ip netns exec ns1 ip link set veth1.1 name eth0
[root@master ~]#ip netns exec ns1 ifconfig -a
eth0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether ba:68:96:8e:83:53  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 0  (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

给ns2的veth1.2改个名字eth0
[root@master ~]#ip netns exec ns2 ip link set veth1.2 name eth0
[root@master ~]#ip netns exec ns2 ifconfig -a
eth0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 32:97:c0:a3:ed:1d  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=8<LOOPBACK>  mtu 65536
        loop  txqueuelen 0  (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

        
为两个网卡添加ip地址
[root@master ~]#ip netns exec ns1 ifconfig eth0 10.0.1.1/24 up
[root@master ~]#ip netns exec ns2 ifconfig eth0 10.0.1.2/24 up

[root@master ~]#ip netns exec ns1 ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.1.1  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::b868:96ff:fe8e:8353  prefixlen 64  scopeid 0x20<link>
        ether ba:68:96:8e:83:53  txqueuelen 1000  (Ethernet)
        RX packets 8  bytes 648 (648.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@master ~]#ip netns exec ns2 ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.1.2  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::3097:c0ff:fea3:ed1d  prefixlen 64  scopeid 0x20<link>
        ether 32:97:c0:a3:ed:1d  txqueuelen 1000  (Ethernet)
        RX packets 8  bytes 648 (648.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


两个网络名称空间的网络是通的
[root@master ~]#ip netns exec ns1 ping 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.108 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.085 ms
^C
--- 10.0.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.085/0.096/0.108/0.015 ms

到目前为止,看吧,此时就好像创建了两个虚拟机一样。两个网络是互相独立的。但是在一个网段内的时候,又可以互相联通。(图4)

下面是一个实际例子,用到了docker,理解了这个例子,docker里面的网络就基本掌握了

image.png

下面是一个单独的例子,是在一台centos7.2虚拟机上,并安装好docker服务

先打开内核的网络转发功能。
[root@master ~]#vim /etc/sysctl.conf 
[root@master ~]#sysctl -p
net.ipv4.ip_forward = 1

下面是brctl命令,网桥相关的命令,需安装bridge-utils包
[root@master ~]#brctl 
Usage: brctl [commands]
commands:
	addbr     	<bridge>		add bridge
	delbr     	<bridge>		delete bridge
	addif     	<bridge> <device>	add interface to bridge
	delif     	<bridge> <device>	delete interface from bridge
	hairpin   	<bridge> <port> {on|off}	turn hairpin on/off
	setageing 	<bridge> <time>		set ageing time
	setbridgeprio	<bridge> <prio>		set bridge priority
	setfd     	<bridge> <time>		set bridge forward delay
	sethello  	<bridge> <time>		set hello time
	setmaxage 	<bridge> <time>		set max message age
	setpathcost	<bridge> <port> <cost>	set path cost
	setportprio	<bridge> <port> <prio>	set port priority
	show      	[ <bridge> ]		show a list of bridges
	showmacs  	<bridge>		show a list of mac addrs
	showstp   	<bridge>		show bridge stp info
	stp       	<bridge> {on|off}	turn stp on/off

添加一个网桥,并启动网桥
[root@master ~]#brctl addbr br-ex
[root@master ~]#brctl show
bridge name	bridge id		STP enabled	interfaces
br-ex		8000.000000000000	no		

[root@master ~]#ip link set br-ex up

[root@master ~]#ifconfig
br-ex: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::2460:4ff:fe9f:9ea1  prefixlen 64  scopeid 0x20<link>
        ether 26:60:04:9f:9e:a1  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

        
[root@master ~]#cat ab.sh 
ip addr del 192.168.170.20/24 dev eth0
ip addr add 192.168.170.20/24 dev br-ex
brctl addif br-ex eth0

必须放到脚本中执行,如果一条一条命令行执行,终端会断掉
[root@master ~]#bash ab.sh 

[root@master ~]#ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-ex state UP qlen 1000
    link/ether 00:50:56:34:bc:93 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::250:56ff:fe34:bc93/64 scope link 
       valid_lft forever preferred_lft forever
5: br-ex: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 00:50:56:34:bc:93 brd ff:ff:ff:ff:ff:ff
    inet 192.168.170.20/24 scope global br-ex
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe34:bc93/64 scope link 
       valid_lft forever preferred_lft forever

[root@master ~]#brctl show 
bridge name	bridge id		STP enabled	interfaces
br-ex		8000.00505634bc93	no		eth0

为路由器R1添加一对网卡并且启动。
[root@master ~]#ip netns add r1
[root@master ~]#ip link add rinr type veth peer name rins
[root@master ~]#ip link set rinr up
[root@master ~]#ip link set rins up

创建网桥,并将rins网卡添加到网桥上
[root@master ~]#brctl addbr br-in
[root@master ~]#ip link set br-in up
[root@master ~]#brctl addif br-in rins
[root@master ~]#brctl show
bridge name	bridge id		STP enabled	interfaces
br-ex		8000.00505634bc93	no		eth0
br-in		8000.d28a979f4b40	no		rins

将rinr加入r1
[root@master ~]#ip link set rinr netns r1
给rinr改个名字,并且启动
[root@master ~]#ip netns exec r1 ip link set rinr name eth0
[root@master ~]#ip netns exec r1 ip link set eth0 up
[root@master ~]#ip netns exec r1 ifconfig eth0 10.0.1.254/24 up
[root@master ~]#ip netns exec r1 ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.1.254  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::2c94:d0ff:fe59:6028  prefixlen 64  scopeid 0x20<link>
        ether 2e:94:d0:59:60:28  txqueuelen 1000  (Ethernet)
        RX packets 16  bytes 1296 (1.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 16  bytes 1296 (1.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

两个虚拟机的网关都指向10.0.1.254
启动一个容器,不要关闭
[root@master ~]#docker run --rm --name docker2 --hostname=docker2 -it --net=none centos:latest /bin/bash

执行下面的脚本来安装docker2网络
[root@master ~]#cat docker2.sh 
#!/bin/bash
pid=`docker inspect -f '{{.State.Pid}}' docker2`
mkdir -p /var/run/netns
ln -s /proc/$pid/ns/net /var/run/netns/$pid
ip link add vetha type veth peer name vethb
brctl addif br-in vethb
ip link set vethb up
ip link set vetha netns $pid
ip netns exec $pid ip link set dev vetha name eth0
ip netns exec $pid ip link set eth0 up 
ip netns exec $pid ip addr add 10.0.1.2/24 dev eth0
ip netns exec $pid ip route add default via 10.0.1.254

启动另外一个容器,不要关闭
[root@master ~]#docker run --rm --name docker3 --hostname=docker3 -it --net=none centos:latest /bin/bash

执行下面的脚本来安装docker3网络
[root@master ~]#cat docker3.sh 
#!/bin/bash
pid=`docker inspect -f '{{.State.Pid}}' docker3`
mkdir -p /var/run/netns
ln -s /proc/$pid/ns/net /var/run/netns/$pid
ip link add vethc type veth peer name vethd
brctl addif br-in vethd
ip link set vethd up
ip link set vethc netns $pid
ip netns exec $pid ip link set dev vethc name eth0
ip netns exec $pid ip link set eth0 up 
ip netns exec $pid ip addr add 10.0.1.3/24 dev eth0
ip netns exec $pid ip route add default via 10.0.1.254


执行后如下
[root@master ~]#brctl show 
bridge name	bridge id		STP enabled	interfaces
br-ex		8000.00505634bc93	no		eth0
br-in		8000.62e2dd6c5f69	no		rins
							vethb
							vethd

==============================================================
目前来说整幅图的右半边完全好了。
开始左半边。

添加一对网卡,再把其中一个桥接
[root@master ~]#ip link add rexr type veth peer name rexs
[root@master ~]#brctl addif br-ex rexs
[root@master ~]#ip link set rexs up

[root@master ~]#brctl show
bridge name	bridge id		STP enabled	interfaces
br-ex		8000.00505634bc93	no		eth0
							rexs
br-in		8000.62e2dd6c5f69	no		rins
							vethb
							vethd

将另一个网卡添加到路由器的另一边,且给个另一个网络的地址
[root@master ~]#ip link set rexr netns r1
[root@master ~]#ip netns exec r1 ip link set rexr name eth1
[root@master ~]#ip netns exec r1 ifconfig eth1 192.168.170.40/24 up

[root@master ~]#ip netns exec r1 ifconfig 
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.1.254  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::78bc:62ff:fed7:2626  prefixlen 64  scopeid 0x20<link>
        ether 7a:bc:62:d7:26:26  txqueuelen 1000  (Ethernet)
        RX packets 13  bytes 858 (858.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27  bytes 2150 (2.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.170.30  netmask 255.255.255.0  broadcast 192.168.170.255
        inet6 fe80::6cd0:8ff:fe47:64ff  prefixlen 64  scopeid 0x20<link>
        ether 6e:d0:08:47:64:ff  txqueuelen 1000  (Ethernet)
        RX packets 19  bytes 1308 (1.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 648 (648.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


[root@master ~]#ip netns exec r1 iptables -t nat -A POSTROUTING -s 10.0.1.0/24  -j SNAT --to-source 192.168.170.40
[root@master ~]#ip netns exec r1 iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 SNAT       all  --  *      *       10.0.1.0/24         !10.0.1.0/24          to:192.168.170.30

物理机添加网关
[root@master ~]#route add -net 0.0.0.0 gw 192.168.170.2
[root@master ~]#ip netns exec r1 route add default gw 192.168.170.2

到这里,两个docker容器就可以正常访问外部网络了,如果需要外部网络访问内部网络,需要做dnat,原理类似

下面的命令来获取容器对应的pid
[root@master ~]#docker inspect -f '{{.State.Pid}}' docker3
2649
[root@master ~]#docker inspect -f '{{.State.Pid}}' docker2
2598

文件:

网络名称空间.zip

参考文档:

http://blog.csdn.net/ghost_leader/article/details/71075551

http://blog.csdn.net/ghost_leader/article/details/68174126

未经允许不得转载:江哥架构师笔记 » docker学习:网络名称空间

分享到:更多 ()

评论 抢沙发

评论前必须登录!