使用命令docker network ls
,执行结果以下。html
NETWORK ID NAME DRIVER SCOPE 82e8822065c7 bridge bridge local a36f938bc6c6 host host local 55ee9a442ee8 none null local
用ifconfig
能够看到多了个【docker0】。linux
【docker0】既能够做为交换机,也能够做为网卡。不给它地址就是交换机,给它地址就既能当交换机也能当网卡。nginx
一头链接到本身进程所属的网络命名空间,另外一头链接任何地方。c++
C1(192.168.1.3)和C5(192.168.1.4)在同一个网段,物理机器h1(10.1.1.3)和h2(10.1.1.4)链接在同一个交换机上。由于C1和C5在同一个网段,因此它们2个能够互相看见,当C1要发送数据给C5时,ip报文里是C1:C5,而后通过虚拟网桥(docker0),转发给物理机器h1,物理机器h1在【ip报文C1:C5】外面再包裹一层【h1:h2】,物理机器h2接受到报文后,拆掉外层的【h1:h2】,发现里面还有【C1:C5】,因此经过虚拟网桥(docker0),转发给C5。web
上图里面的【docker0】,就是在运行docker daemon进程的机器上,执行ifconfig,看到的【docker0】,它是nat bridge。每启动一个容器,就产生一条网线,一端就插在【docker0】上,一端插在本身容器的网络命名空间上。。docker
那么如何查看,【docker0】上插了几根网线呢?shell
使用【yum install bridge-utils】里面的【brctl show】命令,查看网桥上插了哪些网线。微信
[root@localhost ys]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242af11c649 no veth93593bc vethc7cb2ca
从上面的执行结果能够看出来,在【docker0】上插了2根网线分别是veth93593bc和vethc7cb2ca。用在宿主机上使用ifconfig,能够看到这2个网线。网络
[root@localhost ys]# ifconfig veth93593bc: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 ..... prefixlen 64 scopeid 0x20<link> ether ..... txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 vethc7cb2ca: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 .. prefixlen 64 scopeid 0x20<link> ether ..... txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
使用【ip link show】也能够看到veth93593bc和vethc7cb2ca,并且还能够发现veth93593bc的另外一端是if14,vethc7cb2ca的另外一端是if12tcp
[root@localhost ys]# ip link show 5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:af:11:c6:49 brd ff:ff:ff:ff:ff:ff 13: vethc7cb2ca@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether a2:a3:b8:3c:8c:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0 15: veth93593bc@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether b2:24:a8:13:4d:56 brd ff:ff:ff:ff:ff:ff link-netnsid 1
【iptables -t nat -vnL】查看,发现了下面的规则,因此说明docker0是nat bridge。
Chain POSTROUTING (policy ACCEPT 47 packets, 3073 bytes) pkts bytes target prot opt in out source destination 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
in:*,表明:从任何接口进来
out:!docker0,表明:不从docker0出去
source:172.17.0.0/16,表明:原地址来自172.17.0.0/16的任何主机地址,
destination:0.0.0.0/0,表明:发送到任何主机地址,
target:MASQUERADE,表明:作源地址转换 (SNAT ),也就是自动在本机上选择一个源地址。
把上面的话链接起来的意思:从任何接口进来,不从docker0出去,原地址是来自172.17.0.0/16的任何主机地址,发送到任何主机地址,作源地址转换。
查看ip命令的工具包是否安装:rpm -q iproute
使用ip命令,看到object里有网络命名空间(netns),因此咱们用ip命令就能够建立网络命名空间。
[root@localhost ys]# 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 | fou | macsec | tcp_metrics | token | netconf | ila | vrf } OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] | -h[uman-readable] | -iec | -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } | -4 | -6 | -I | -D | -B | -0 | -l[oops] { maximum-addr-flush-attempts } | -br[ief] | -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] | -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}
得到ip netns命令的帮助信息:
[root@localhost ys]# 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
命令ip netns
使用例子:建立网络命名空间和查看网络命名空间
[root@localhost ys]# ip netns list [root@localhost ys]# ip netns add ns1 [root@localhost ys]# ip netns add ns2 [root@localhost ys]# ip netns list ns2 ns1
获取ip link命令的帮助信息:ip link help
[root@localhost ys]# ip link help Usage: ip link add [link DEV] [ name ] NAME [ txqueuelen PACKETS ] [ address LLADDR ] [ broadcast LLADDR ] [ mtu MTU ] [index IDX ] [ numtxqueues QUEUE_COUNT ] [ numrxqueues QUEUE_COUNT ] type TYPE [ ARGS ] ...后面太多了,省略了。
在指定的网络命名空间里执行网络命令:
# ip netns exec ns1 ifconfig
给网络命名空间建立网线(虚拟网卡对),命令里面的【type】是网卡对的类型,veth是以太网。
# ip link add name veth1.1 type veth peer name veth1.2
使用ip link show
能够看到刚建立的veth1.1和veth1.2,他们互为一对,并且他们都是插宿主机上的。
22: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 4e:e3:65:60:bb:08 brd ff:ff:ff:ff:ff:ff 23: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 2a:16:5b:ce:fe:f6 brd ff:ff:ff:ff:ff:ff
使用ifconfig
,发现他们都没有被显示出来,由于尚未激活他们。用ifconfig -a
是能够显示出来的。
先建立一个网络命名空间:ip netns add ns1
,而后让veth1.2插在ns1上。
# ip link set dev veth1.2 netns ns1
而后在宿主机网络命名空间上执行ip link show
,发现veth1.2没有了。由于veth1.2已经到ns1网络命名空间里了。
23: veth1.1@if22: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 2a:16:5b:ce:fe:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
再去ns1网络命名空间里,执行ip netns exec ns1 ifconfig -a
,发现veth1.2在里面。
veth1.2: flags=4098<BROADCAST,MULTICAST> mtu 1500 ether 4e:e3:65:60:bb:08 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
也能够修改veth1.2的名字,修改为eth0.
# ip netns exec ns1 ip link set dev veth1.2 name eth0
执行ip netns exec ns1 ifconfig -a
,发现变成了eth0了。
eth0: flags=4098<BROADCAST,MULTICAST> mtu 1500 ether 4e:e3:65:60:bb:08 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
让虚拟网卡插在某个网络命名空间。
# ip link set dev veth1.2 netns ns1
激活虚拟网卡(赋给它IP就是激活)。
激活veth1.1
# ifconfig veth1.1 10.1.0.1/24 up
执行ifconfig
,发现虚拟网卡veth1.1有ip地址了。
veth1.1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 10.1.0.1 netmask 255.255.255.0 broadcast 10.1.0.255 ether 2a:16:5b:ce:fe:f6 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里的eth0
# ip netns exec ns1 ifconfig eth0 10.1.0.2/24 up
执行ifconfig
,发现虚拟网卡eth0有ip地址了。
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.1.0.2 netmask 255.255.255.0 broadcast 10.1.0.255 inet6 fe80::4ce3:65ff:fe60:bb08 prefixlen 64 scopeid 0x20<link> ether 4e:e3:65:60:bb:08 txqueuelen 1000 (Ethernet) RX packets 11 bytes 1447 (1.4 KiB) 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
从宿主机ping一下ns1里的eth0,是能够ping通的。
# ping 10.1.0.2 PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data. 64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.073 ms
再从ns1ping一下宿主机的veth1.1,也是能够ping通的。
# ip netns exec ns1 ping 10.1.0.1 PING 10.1.0.1 (10.1.0.1) 56(84) bytes of data. 64 bytes from 10.1.0.1: icmp_seq=1 ttl=64 time=0.039 ms
使用ip
命令能够建立虚拟网卡,使用brctl
,能够建立虚拟交换机,有了它俩,就能够模拟不少虚拟网络,好比物理桥,nat桥等,不须要安装额外的虚拟机,很轻量。
假设容器都是以bridge方式启动
2个容器都插在docker0上,那么这2个容器都在172.17网段上,互相通讯没有任何问题。
容器和宿主机互相通讯没有问题。
客户端CL1,要经过80端口访问nginx容器WEB1,可是客户端CL1同nginx容器WEB1在不一样的网络,如何通讯呢?nginx容器WEB1所在的宿主机只能使用DNAT技术,才能实现通讯。也就是说客户端CL1访问的是宿主机,宿主机再转发给nginx容器WEB1。
这就有个问题了,若是web2和web3也是nginx,也要使用80端口,那么宿主机转发的时候就不知道转给哪一个容器了。
另外一种方式:容器能够有独立的6个命名空间,为了2个容器间能够用lo(127.0.0.1)通讯,让他们只拥有3个(user,mount, pid)独立的命名空间,另外3个(uts, net, ipc)他们共享使用。
容器间能够共用3个(uts, net, ipc)空间,那么容器能够和宿主机(docker daemon进程所运行的机器)共用吗?是能够的。让一个容器A和宿主机共用3个(uts, net, ipc)空间,让其余的容器使用桥接,这样一来容器A就有了管理网络的特权。这就是docker的host链接方式。
查看网络链接具体信息的命令(inspect 能够查看任何docker object):
# docker network inspect bridge/host/none
查看容器的网络链接具体信息。
# docker container inspect ng1