Docker容器技术之容器虚拟化网络(4)

1. 虚拟化网络


Network Namespace 是 Linux 内核提供的功能,是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己都在独立的网络中。而且不同Network Namespace的资源相互不可见,彼此之间无法通信。

假如我们的物理机有4块物理网卡,我们要创建4个名称空间,而这些设备是可以单独关联至某个单独的名称空间使用的
在这里插入图片描述
如上图所示,把第一块网卡分配给第一个名称空间,第二块分给第二个名称空间,第三块分给第三个名称空间,第四块分给第四个名称空间。此时其它名称空间都是看不见当前所在名称空间的,因为一个设备只能属于一个名称空间。

这种方式使得每一个名称空间都能配置IP地址,并且与外部网络直接通信,因为它们使用的是物理网卡。

但如果我们所拥有的名称空间数量超过物理网卡数量呢?此时我们可以使用虚拟网卡设备,用纯软件的方式来模拟一组设备来使用。Linux内核级支持2种级别设备的模拟,一种是二层设备,一种是三层设备。

Linux内核模拟的二层设备,每个网络接口设备是成对出现的,可以模拟为一根网线的两端,其中一端模拟主机的虚拟网卡,另一端模拟虚拟交换机,就相当于让一个主机连到一个交换机上去。Linux内核原生支持二层虚拟网桥设备,即用软件虚拟交换机的功能。如下图所示:
在这里插入图片描述
那么此时如果再有一个名称空间,它有创建了一对虚拟网卡,一端连接名称空间,一端连接虚拟交换机,此时就相当于两个名称空间连接到了同一个交换机网络中,此时如果两个名称空间的网卡地址配置在同一网段,那么很显然他们之间是可以互相通信的。如下图所示:

在这里插入图片描述
从网络通信的物理设备到网卡都是用纯软件的方式来实现,这种实现方式就叫做虚拟化网络。

2. 单节点容器间通信


如果在同一个物理机上的两个容器想通信,我们的办法就是在这台主机上建立一个虚拟交换机,而后让两个容器各自用纯软件的方式创建一对虚拟网卡,一半在容器上,一半在虚拟交换机上,从而实现通信。如下图所示:
在这里插入图片描述
这就是单节点上两个容器间的通信方式。单节点上两个容器之间的通信也有一些复杂情况,比如我们期望构建的容器要跨交换机通信呢?

在这里插入图片描述
我们做两个虚拟交换机,两个交换机上各自连接不同的容器,如上图所示,此时如果要C1和C3通信又该如何实现呢?其实我们可以通过名称空间创建一对网卡,一端连SW1,另一端连SW2,这样一来两个交换机就连起来了,照理说这样一来C1和C3这两个处于不同交换机的容器就可以实现通信了,但是这样一来又存在另一个问题,那就是如果C1和C3在不同网络呢?如果不在同一网络我们就必须要通过路由转发才能使其通信,也就是我们得在两台交换机之间加一个路由器,其实Linux内核本身就是支持路由转发的,只需要我们将路由转发功能打开即可。此时我们可以再启动一个容器,这个容器里面就跑一个内核,并将其转发功能打开,这样一来就模拟了一台路由器,通过这台路由器来实现路由转发。
在这里插入图片描述

3. 不同节点容器间通信


在这里插入图片描述
如上图所示,此时如果C1要与C5进行通信又该如何实现呢?如果我们采用桥接的方式,很容易产生广播风暴,因此,在大规模的虚拟机或容器的场景中,使用桥接的方式无疑是自取灭亡,所以我们不应该使用桥接的方式来实现通信。

如果一来,我们既不能桥接,又需要与外部来实现通信,那就只能使用NAT技术了。通过DNAT将容器的端口暴露到宿主机上,通过访问宿主机的端口来实现访问容器内部的目的,而在请求端我们需要做SNAT将数据包通过宿主机的真实网卡转发出去。但这样做的话,因为要进行两次NAT转换,所以效率会比较低。

此时我们可以采用一种叫做Overlay Network(叠加网络)的技术来实现不同节点间容器的相互通信功能。
在这里插入图片描述
Overlay Network会将报文进行隧道转发,也就是在报文发出去之前要为其添加一个IP首部,也就是上图的1.1和1.2这部分,这里的1.1是源,1.2是目标,当宿主机2收到报文后解封装发现要找的目标容器是C2,于是把包转发给C2。

4. docker容器网络


Docker在安装后自动提供3种网络,可以使用docker network ls命令查看

[root@node02 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1b093120d2bb        bridge              bridge              local
7362e537cc7b        host                host                local
910a5741bb77        none                null                local

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

5. docker的4种网络模式


网络模式配置说明
host–network host容器和宿主机共享Network namespace
container–network container:NAME_OR_ID容器和另外一个容器共享Network namespace
none–network none容器有独立的Network namespace,
但并没有对其进行任何网络设置,
如分配veth pair 和网桥连接,配置IP等
bridge–network bridge默认模式

在这里插入图片描述

5.1 bridge模式

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。

[root@node02 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.024206c52942	no		veth1c4e358
							veth3b5c82d
							veth664302c
							veth710559c

bridge模式是docker的默认网络模式,不写–network参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

[root@node02 ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 9 packets, 676 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    4   204 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

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

Chain OUTPUT (policy ACCEPT 18 packets, 1804 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 18 packets, 1804 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           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.5           172.17.0.5           tcp dpt:80

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.5:80

bridge模式如下图所示:
在这里插入图片描述
演示

[root@node02 ~]# docker run -d nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
bf5952930446: Pull complete 
cb9a6de05e5a: Pull complete 
9513ea0afb93: Pull complete 
b49ea07d2e93: Pull complete 
a5e4a503d449: Pull complete 
Digest: sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661
Status: Downloaded newer image for nginx:latest
13452140347d7365d07d87e563c5ef9dc13e4a1c679a95006bb357bed6692e94
[root@node02 ~]# docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS               NAMES
13452140347d        nginx                     "/docker-entrypoint.…"   11 seconds ago      Up 10 seconds       80/tcp              lucid_shamir
68bf73ee67f9        dragonyear22/nginx:v0.2   "/bin/httpd -f -h /l…"   13 hours ago        Up 13 hours                             naughty_bohr
48379c69153b        busybox                   "sh"                     14 hours ago        Up 14 hours                             eager_goldwasser
[root@node02 ~]# docker inspect 13452140347d
...........
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.4",
...........

[root@node02 ~]# ip a
1: lo: <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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:dd:54:b6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.159.161/24 brd 192.168.159.255 scope global noprefixroute dynamic ens33
       valid_lft 1791sec preferred_lft 1791sec
    inet6 fe80::2d92:6f17:5128:80f9/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:06:c5:29:42 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6ff:fec5:2942/64 scope link 
       valid_lft forever preferred_lft forever
5: veth1c4e358@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 56:17:7a:17:60:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::5417:7aff:fe17:60b4/64 scope link 
       valid_lft forever preferred_lft forever
11: veth710559c@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether a2:f8:89:83:4b:55 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::a0f8:89ff:fe83:4b55/64 scope link 
       valid_lft forever preferred_lft forever
13: veth664302c@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 16:b2:4d:f7:f6:28 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::14b2:4dff:fef7:f628/64 scope link 
       valid_lft forever preferred_lft forever

[root@node02 ~]# ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from 172.17.0.4: icmp_seq=4 ttl=64 time=0.039 ms
^C
--- 172.17.0.4 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.037/0.067/0.111/0.032 ms

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

[root@node02 ~]# docker run -d -p 80 --name t2 nginx
064251a9b7a3b84e532d47dd993405efed8bc2ea28270937a9b311f1a70ab521
[root@node02 ~]# iptables -t nat -vnL |tail -1
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.5:80
[root@node02 ~]# ss -antl |grep 32768
LISTEN     0      128       [::]:32768                 [::]:*

5.2 container模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

container模式如下图所示:
在这里插入图片描述
演示
在一个终端,使用bridge网络模式启动容器b1

[root@node02 ~]# docker run --name b1 -it --rm busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:06  
          inet addr:172.17.0.6  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:516 (516.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
/ # echo "hello world b1" > /tmp/index.html
/ # httpd -h /tmp/       在b1上启动httpd服务
/ # 
/ # netstat -nutl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 :::80                   :::*                    LISTEN

在另一个终端使用Container 网络模式创建容器b2

[root@node02 ~]# docker run --name b2 -it --network container:b1 --rm busybox:latest
/ # ifconfig -a
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:06  
          inet addr:172.17.0.6  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:656 (656.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
/ # wget -O - -q 127.0.0.1      b1启动的httpd服务,在b2上直接访问
hello world b1
/ # ls /tmp/      但是文件系统并不共享,只共享网络

5.3 host模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

Host模式如下图所示:
在这里插入图片描述
演示

[root@node02 ~]# docker run --name b2 -it --network host --rm busybox:latest
/ # ifconfig -a
docker0   Link encap:Ethernet  HWaddr 02:42:06:C5:29:42  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:6ff:fec5:2942/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:974 (974.0 B)  TX bytes:1484 (1.4 KiB)

ens33     Link encap:Ethernet  HWaddr 00:0C:29:DD:54:B6  
          inet addr:192.168.159.161  Bcast:192.168.159.255  Mask:255.255.255.0
          inet6 addr: fe80::2d92:6f17:5128:80f9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:117652 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14693 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:170532211 (162.6 MiB)  TX bytes:1278297 (1.2 MiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:64 errors:0 dropped:0 overruns:0 frame:0
          TX packets:64 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:5568 (5.4 KiB)  TX bytes:5568 (5.4 KiB)

veth1c4e358 Link encap:Ethernet  HWaddr 56:17:7A:17:60:B4  
          inet6 addr: fe80::5417:7aff:fe17:60b4/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:1186 (1.1 KiB)

veth3b5c82d Link encap:Ethernet  HWaddr 1A:B1:44:EB:27:D9  
          inet6 addr: fe80::18b1:44ff:feeb:27d9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:656 (656.0 B)

veth664302c Link encap:Ethernet  HWaddr 16:B2:4D:F7:F6:28  
          inet6 addr: fe80::14b2:4dff:fef7:f628/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:476 (476.0 B)  TX bytes:1132 (1.1 KiB)

veth710559c Link encap:Ethernet  HWaddr A2:F8:89:83:4B:55  
          inet6 addr: fe80::a0f8:89ff:fe83:4b55/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:17 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:694 (694.0 B)  TX bytes:1260 (1.2 KiB)

通过查看IP,可以发现和宿主机是一样的

5.4 none模式

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

应用场景:

  • 启动一个容器处理数据,比如转换数据格式
  • 一些后台的计算和处理任务

none模式如下图所示:
在这里插入图片描述
演示

[root@node02 ~]# docker run --name b1 -it --network none --rm busybox:latest 
/ # ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
docker network inspect bridge   #查看bridge网络的详细配置
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值