一、Docker 网络简介
1、网络模式
Docker 基础网络类型一共有三种(bridge、host 和 none),还有两种由基础网络类型派生的网络类型(container 和 custom)。本文详细讲解这五种网络类型。
查看 docker 网络:
1 2 3 4 5 [root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 994c4bd64f70 bridge bridge local 9eeb43076ad2 host host local ad2da4225045 none null local
网络模式说明:
网络模式
配置
说明
host
--network=host
容器不会创建自己的网卡,配置 IP 等,而是使用宿主机的 IP 和端口
none
--network=none
容器关闭网络功能,不进行任何网路设置
bridge
--network=bridge
为每个容器分配 IP 。并将容器连接到 docker0
虚拟网桥上,这种模式是默认模式
container
--network=container:NAME_or_ID
容器不会创建自己的网卡和IP,而是和一个指定的容器共享 IP 和端口
custom
--network=new_bridge
为每个容器分配 IP 。并将容器连接到自定义的虚拟网桥上
2、组件原理
(1)网络命名空间(network namespace)
Network Namespace 是 linux 内核提供的用于实现网络虚拟化的重要功能,是 Linux 内核用来隔离不同容器间的网络资源(每个 Docker 容器都拥有一个独立的网络命名空间),网络命名空间主要隔离的资源包括:
网络空间结构如下图所示,当系统中拥有 2 个网络命名空间:
由于不同的网络命名空间之间是相互隔离的,所以不同的网络命名空间之间并不能直接通信。 就好比两台电脑,如果没有任何网线连接,它们之间是不能通信的。所以,Linux 内核提供了 虚拟网络设备对(veth) 这个功能,用于解决不同网络命名空间之间的通信。
(2)虚拟网络设备对(veth-pair)
虚拟网络设备对(veth-pair)用于解决不同网络命名空间之间的通信,可以将其看成是两块有网线连接的网卡。只要将其中一块网卡放置到网络命名空间A,另外一块网卡放置到网络命名空间B,那么两个不同的网络命名空间就能够通信,如下图所示:
如上图所示,veth0 与 veth1 组成一个虚拟网络设备对。虚拟网络设备对就像管道一样,只要向其中一端发送数据,就可以从另外一端接收到数据。
Docker 就是使用 虚拟网络设备对 来实现不同容器之间的通信,其原理如下图:
(3)docker0 网桥
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
查看 docker0 网桥:
1 2 3 4 5 6 7 8 9 [root@localhost ~]# ip a ... 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:60:fc:72:3b 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:60ff:fefc:723b/64 scope link valid_lft forever preferred_lft forever ...
查看 docker0 详细:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 [root@localhost ~]# docker network inspect bridge [ { "Name": "bridge", "Id": "b2f23dec622af41e1976542bc1633f6c785f7a6ff4eeaaf2a779c761dba03941", "Created": "2022-09-04T22:15:41.831270638-04:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ]
查看连接到 docker0 的虚拟网络设备对(veth-pair):
1 2 3 4 5 6 [root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.024260fc723b no veth1870812 veth1de92fe veth5b85033 vethbfd4b66
注意:每启动一个容器,就会生成一个 veth-pair 。
如果没有 brctl 这个命令,可以通过以下命令进行安装:
1 yum install -y bridge-utils
二、网络模式详细说明
1、Host 模式
在 host 模式下,容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
结构如下图所示:
查看该网络模式配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [root@localhost ~]# docker network inspect host [ { "Name": "host", "Id": "9eeb43076ad21e4891954ab2f6682213adaa52c64f3c3668ad8fa8d4493785e4", "Created": "2022-06-19T23:25:06.060598453-04:00", "Scope": "local", "Driver": "host", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
2、None 模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
结构如下图所示:
查看该网络模式配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [root@localhost ~]# docker network inspect none [ { "Name": "none", "Id": "ad2da4225045337a2192fc016ca7d7fc984a82a1452221e19e07d9a5dce0cb71", "Created": "2022-06-19T23:25:05.946788343-04:00", "Scope": "local", "Driver": "null", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
3、Bridge 模式
Bridge 模式是 docker 的默认网络模式,不写 --network
参数,就是 bridge 网桥模式。
当 Docker 进程启动时,会在主机上创建一个名为 docker0
的虚拟网桥,此主机上启动的Docker容器默认都会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从 docker0子网中分配一个IP给容器使用,并设置 docker0
的IP地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair
设备,Docker 将 veth pair
设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以 vethxxx
这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过 brctl show
命令查看。
结构如下图所示:
查看该网络模式配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 [root@localhost ~]# docker network inspect bridge [ { "Name": "bridge", "Id": "44529eeb55f59f1af6d75c7d54fab3a5283b0e021ee91b7a1163c710d5dbc573", "Created": "2022-09-05T04:34:26.929819942-04:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ]
4、Container 模式
Container 模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
结构如下图所示:
在以上示例中,Docker 2
容器可以通过--network=container:Docker 1
参数,指定自己的网络和一个容器 Docker 1
共享 IP 和端口。
示例:
1 docker run -it --name docker2 --network=container:docker1 nginx:latest /bin/bash
5、Custom 模式
Custom 模式用于自定义 docker 网络。
结构如下图所示:
如上图所示,新建自定义网桥 custom ,指定网络(192.168.10.0/24)和网关(192.168.10.1)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 新建自定义网络 docker network create --driver bridge --subnet 192.168.10.0/24 --gateway 192.168.10.1 Custom # 查看自定义网络,查看定义网络 docker network ls NETWORK ID NAME DRIVER SCOPE 994c4bd64f70 bridge bridge local 9eeb43076ad2 host host local 24cd1b0769bd Custom bridge local ad2da4225045 none null local # 查看自定义网桥 IP 地址 [root@localhost ~]# ip addr 316: br-24cd1b0769bd: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:cb:b3:6c:a3 brd ff:ff:ff:ff:ff:ff inet 192.168.10.1/24 brd 192.168.10.255 scope global br-24cd1b0769bd valid_lft forever preferred_lft forever
三、自定义网络实战 - 网络联通
在没有使用 connect 命令的情况下,不同网络间的容器是无法进行网络连接的。
如下图所示:container1 和 container2,使用不同的网络,所以无法联通。
1、验证不同网络无法联通性
(1)创建容器 container1
1 2 3 4 5 6 7 8 9 10 11 12 13 # 创建容器 docker run -it --name container1 centosjava:latest /bin/bash # 查看容器 IP [root@41eea42d9980 /]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.8 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:08 txqueuelen 0 (Ethernet) RX packets 8 bytes 656 (656.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 ...
(2)创建容器 container2
1 2 3 4 5 6 7 8 9 10 11 12 13 # 创建容器 docker run -it --name container2 --network Custom centosjava:latest /bin/bash # 查看容器 IP [root@7279af38152a /]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.10.2 netmask 255.255.255.0 broadcast 192.168.10.255 ether 02:42:c0:a8:0a:02 txqueuelen 0 (Ethernet) RX packets 12 bytes 1032 (1.0 KiB) 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 ...
(3)两台容器之间互相 ping
测试
1 2 3 4 5 6 7 # 容器 container1 ping container2 ,不通 [root@41eea42d9980 /]# ping 192.168.10.2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. # 容器 container2 ping container1 ,不通 [root@7279af38152a /]# ping 172.17.0.8 PING 172.17.0.8 (172.17.0.8) 56(84) bytes of data.
2、不同网络之间网络联通
(1)将容器 container1 和容器 container2 分别添加到对方所在的网络中
1 2 docker network connect Custom container1 docker network connect bridge container2
(2)再次检查两台容器之间网络联通性
1 2 3 4 5 6 7 8 9 10 11 12 # 容器 container1 ping container2 ,通 [root@41eea42d9980 /]# ping 192.168.10.2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=123 ttl=64 time=0.087 ms 64 bytes from 192.168.10.2: icmp_seq=124 ttl=64 time=0.085 ms # 容器 container2 ping container1 ,通 [root@7279af38152a /]# ping 172.17.0.8 PING 172.17.0.8 (172.17.0.8) 56(84) bytes of data. 64 bytes from 172.17.0.8: icmp_seq=229 ttl=64 time=0.090 ms 64 bytes from 172.17.0.8: icmp_seq=230 ttl=64 time=0.077 ms
通过以上实战说明,docker 不同网络之间互联需要使用 connect 命令进行网络发布!!!