Docker network --容器网络
参考文章:https://www.jianshu.com/p/14a3663c9756
https://www.jianshu.com/p/04b33284f742
https://www.jianshu.com/p/0a03b68023e1
官网文档:https://docs.docker.com/network/
一、什么是docker network
Docker 网络管理起来需要用到这个,因为docker每个container可能所在的网段ip都不一样,但是每个容器又都是一个虚拟机,有的时候不同的容器之间要通信,要是不设置,彼此之间都ping不通,所以还是要用到这个。
总之,使用docker network可以更方便的使容器之间进行通信
二、docker network的基础知识
1、四种驱动
1)bridge:这是docker 默认的网络驱动程序,如果未制定驱动程序,当run 镜像的时候,容器中使用的就是bridge网络
# 这是更详尽的解释
就网络而言,桥接网络是链路层设备,用于在网络段之间转发通信。桥接可以是运行在主机内核中的硬件设备或软件设备。
对docker而言,桥接网络使用的软件桥接方式,它允许容器之间使用相同桥接网络进行通信,同时与使用其他桥接网络的的容器进行隔离。docker的桥接驱动在宿主机上有自己独特的安装规则,以至于在不同的桥接网络上的容器彼此不能直接通信。
桥接网络作用于同一个宿主机上的docker守护进程的容器上。对于在不同宿主机上的守护进程的容器来说,你既可以通过OS系统级别的方式来管理通信,也可以通过使用overlay网络来管理。
当你启动docker,一个默认的桥接网络会被自动创建,除非另有指定,否则新启动的容器会链接它。你也可以创建自定义桥接网络。自定义桥接网络优先级会高于默认网络。
2)host 对于独立容器,请删除容器与Docker主机之间的网络隔离,然后直接使用主机的网络。host
仅可用于Docker 17.06及更高版本上的集群服务。请参阅 使用主机网络。
如果你对一个容器使用的是host网络驱动,这个容器的网络栈并不是和docker宿主机隔离的。例如,你启动了一个容器绑定的是80端口,使用的host网络驱动,而你的应用程序将使用主机的ip和80端口。
#注:由于使用时容器不拥有自己的IP地址 host模式的网络,端口映射不生效,并且-p,--publish,-P,和--publish-all选项都将被忽略,产生一个警告:WARNING: Published ports are discarded when using host network mode
host网络驱动仅能在Linux上工作,不支持docker的宿主机是Mac、Windows、Windows Server.
在docker 17.06 或者更高版本,你也可以在swarm service 上使用host网络,通过在docker container create 命令上设置--network host。在这种情况下,管理swarm集群和服务上仍然用overlay 网络,但是在单独的集群容器使用的主机网络和端口来发送数据的。 这样也是有一些额外限制的,例如, 如果一个服务容器,绑定的是80端口,那么仅有一个服务容器可以在指定的swarm 节点上运行。
如果你的容器或者服务没有对外端口,host网络就没办法生效。
3)、overlay:覆盖网络将多个Docker守护程序连接在一起,并使群集服务能够相互通信。您还可以使用覆盖网络来促进群集服务和独立容器之间或不同Docker守护程序上的两个独立容器之间的通信。这种策略消除了在这些容器之间进行操作系统级路由的需要。请参阅叠加网络。https://docs.docker.com/network/overlay/
4)macvlan
:Macvlan网络允许您将MAC地址分配给容器,使其在网络上显示为物理设备。Docker守护程序通过其MAC地址将流量路由到容器。macvlan
在处理希望直接连接到物理网络而不是通过Docker主机的网络堆栈进行路由的旧应用程序时,使用驱动程序有时是最佳选择。请参阅 Macvlan网络。https://docs.docker.com/network/macvlan/
5)none::对于此容器,请禁用所有联网。通常与自定义网络驱动程序一起使用。none
不适用于群体服务。请参阅 禁用容器联网。https://docs.docker.com/network/none/
6)[Network plugins:网络插件,可以在Docker上安装和使用第三方网络插件。这些插件可从 Docker Hub 或第三方供应商处获得。有关安装和使用给定网络插件的信息,请参阅供应商的文档。
三、使用bridge network
-
用户定义的网桥可在容器之间提供自动DNS解析。
使用默认桥接网络上的容器只能通过IP地址相互访问,除非您使用被认为是传统的
--link
选项。在用户定义的网桥网络上,容器可以通过名称或别名相互解析。想象一个具有Web前端和数据库后端的应用程序。如果调用容器
web
和db
,则db
无论应用程序堆栈在哪个Docker主机上运行,Web容器都可以在处连接到db容器。如果在默认网桥网络上运行相同的应用程序堆栈,则需要在容器之间手动创建链接(使用旧式
--link
标志)。这些链接需要双向创建,因此您可以看到,要进行通信的容器超过两个,这将变得很复杂。另外,您可以操纵/etc/hosts
容器中的文件,但这会产生难以调试的问题。 -
用户定义的桥可提供更好的隔离。
所有未
--network
指定的容器都将连接到默认桥网络。这可能是一种风险,因为不相关的堆栈/服务/容器随后能够进行通信。使用用户定义的网络可提供作用域网络,其中只有连接到该网络的容器才能通信。
-
容器可以随时随地从用户定义的网络连接和分离。
在容器的生命周期内,您可以即时将其与用户定义的网络连接或断开连接。要从默认桥接网络中删除容器,您需要停止容器并使用其他网络选项重新创建它。
-
每个用户定义的网络都会创建一个可配置的网桥。
如果您的容器使用默认桥接网络,则可以对其进行配置,但是所有容器都使用相同的设置,例如MTU和
iptables
规则。另外,配置默认桥接网络发生在Docker本身之外,并且需要重新启动Docker。用户定义的桥接网络是使用创建和配置的
docker network create
。如果不同的应用程序组具有不同的网络要求,则可以在创建时分别配置每个用户定义的网桥。 -
默认网桥网络上的链接容器共享环境变量。
最初,在两个容器之间共享环境变量的唯一方法是使用
--link
flag链接它们。用户定义的网络无法进行这种类型的变量共享。但是,存在共享环境变量的高级方法。一些想法:
连接到同一用户定义网桥网络的容器可以有效地将所有端口彼此公开。为了使容器或不同网络上的非Docker主机可以访问该端口,必须使用或 标志发布该端口。-p``--publish
四、管理自定义的bridge network
1、)创建用户自定义的bridge network
docker network create my-net
2、)高级用法
创建网络时,默认情况下,引擎会为该网络创建一个不重叠的子网。该子网不是现有网络的细分。它仅用于ip寻址目的。您可以覆盖此默认值,并使用该--subnet
选项直接指定子网值。在 bridge
网络上,只能创建一个子网:
docker network create --driver=bridge --subnet=192.168.0.0/16 br0
还可以指定 --gateway --ip-range 和 --aux-address
docker network create \
--driver=bridge \
--subnet=172.28.0.0/16 \
--ip-range=172.28.5.0/24 \
--gateway=172.28.5.254 \
br0
3)实例演示
-
创建
alpine-net
网络。--driver bridge
因为它是默认标志,所以您不需要该标志,但是此示例显示了如何指定它。$ docker network create --driver bridge alpine-net
-
列出Docker的网络:
$ docker network ls NETWORK ID NAME DRIVER SCOPE cf14bc513683 alpine-net bridge local ece97494f10a bridge bridge local 7af8033afdac host host local aab810098d7e none null local
检查
alpine-net
网络。这显示了它的IP地址以及没有容器连接到它的事实:$ docker network inspect alpine-net [ { "Name": "alpine-net", "Id": "cf14bc51368365f6593ec646acf0d1201165b2ff78954767088c39d71aeb63cb", "Created": "2020-06-04T10:34:58.9148507Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ]
请注意,
172.18.0.1
与默认网桥网络相反,该网络的网关为172.17.0.1
。不同主机系统上确切的ip地址可能不同 -
创建四个容器。注意
--network
标志。您只能在docker run
命令期间连接到一个网络,因此您docker network connect
以后也需要使用它 来连接alpine4
到bridge
网络。$ docker run -dit --name alpine1 --network alpine-net alpine ash $ docker run -dit --name alpine2 --network alpine-net alpine ash $ docker run -dit --name alpine3 alpine ash $ docker run -dit --name alpine4 --network alpine-net alpine ash $ docker network connect bridge alpine4
验证所有容器都在运行:
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 156849ccd902 alpine "ash" 41 seconds ago Up 41 seconds alpine4 fa1340b8d83e alpine "ash" 51 seconds ago Up 51 seconds alpine3 a535d969081e alpine "ash" About a minute ago Up About a minute alpine2 0a02c449a6e9 alpine "ash" About a minute ago Up About a minute alpine1
-
检查
bridge
网络并alpine-net
再次检查网络:$ docker network inspect bridge [ { "Name": "bridge", "Id": "ece97494f10aa9f0f413b59fd9f8ee534e1968e25e75140e2dc03955d5294734", "Created": "2020-05-31T12:11:02.429271054Z", "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": { "65d3956e717de99a602e8c72d3c5894e1a72cbda75344d83e2f7a799ae2573b5": { "Name": "alpine3", "EndpointID": "87e41b5848231b9cdccc0a66efbf580defeaf8572168dbe6435fb0f014719463", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "9a3349a7c7cf38867c124dc2e5df3e26c9c2b16f1fb043c09fef60c05c700f68": { "Name": "alpine4", "EndpointID": "b0003fcac081d6a87ddf0c71f4e6e20723eeeb9c265e22fadc06f6f3a07b404a", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" } }, "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": {} } ]
容器
alpine3
和alpine4
连接到bridge
网络。$ docker network inspect alpine-net [ { "Name": "alpine-net", "Id": "cf14bc51368365f6593ec646acf0d1201165b2ff78954767088c39d71aeb63cb", "Created": "2020-06-04T10:34:58.9148507Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "182ec6930d20216ac4ad364bd088e425579a785106df222fff39ef580259d033": { "Name": "alpine1", "EndpointID": "11e08085970ce4e5376fa3be53aea6eb841a56c8df7d04c96c5ad7f25fa4af8a", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "4aeee9a1df21cdaae36341286599b3b4ee72881a3d55b9e52e0dfaff7f0d8ecd": { "Name": "alpine2", "EndpointID": "d86e88403d14fe1ed54378a57c1db4beb624495b532aeaacd5b8ef706eb08f41", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" }, "9a3349a7c7cf38867c124dc2e5df3e26c9c2b16f1fb043c09fef60c05c700f68": { "Name": "alpine4", "EndpointID": "950f1bfe323c9b4afb630e02461f9b3c2a81ce5610c8559f05e8f32527bd8b90", "MacAddress": "02:42:ac:12:00:04", "IPv4Address": "172.18.0.4/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
容器
alpine1
,alpine2
和alpine4
连接到alpine-net
网络。 -
在诸如的用户定义网络上
alpine-net
,容器不仅可以通过IP地址进行通信,还可以将容器名称解析为IP地址。此功能称为自动服务发现(automatic service discovery.)。让我们连接alpine1
并测试一下。alpine1
应该能够解析alpine2
和alpine4
(以及alpine1
本身)为IP地址。$ docker container attach alpine1 # ping -c 2 alpine2 PING alpine2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=2.401 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.198 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.085/0.087/0.090 ms # ping -c 2 alpine4 PING alpine4 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.560 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.172 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.076/0.083/0.091 ms # ping -c 2 alpine1 PING alpine1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.026 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.054 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.026/0.040/0.054 ms
-
从中
alpine1
,您根本无法连接alpine3
,因为它不在alpine-net
网络上。# ping -c 2 alpine3 ping: bad address 'alpine3'
不仅如此,您也无法通过其IP地址
alpine3
从alpine1
进行连接。回顾网络的docker network inspect
输出bridge
,找到alpine3
的IP地址:172.17.0.2
尝试ping通它。# ping -c 2 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes --- 172.17.0.2 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
分离从
alpine1
用分离序列,CTRL
+p
+
q(压紧
CTRL和
p,随后
q`)。 -
请记住,这
alpine4
已连接到默认bridge
网络和alpine-net
。它应该能够到达所有其他容器。但是,您将需要alpine3
按其IP地址进行寻址。附加到它并运行测试。$ docker container attach alpine4 # ping -c 2 alpine1 PING alpine1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.074/0.078/0.082 ms # ping -c 2 alpine2 PING alpine2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.075/0.077/0.080 ms # ping -c 2 alpine3 ping: bad address 'alpine3' # ping -c 2 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.089 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms --- 172.17.0.2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.075/0.082/0.089 ms # ping -c 2 alpine4 PING alpine4 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.033 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.064 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.033/0.048/0.064 ms
-
作为最终测试,请通过ping确保您的容器都可以连接到互联网
google.com
。您已经很迷恋,alpine4
因此请从那里开始尝试。接下来,断开alpine4
并连接到alpine3
(仅连接到bridge
网络)并重试。最后,连接到alpine1
(仅连接到alpine-net
网络),然后重试。/ # ping -c 2 baidu.com PING baidu.com (220.181.38.148): 56 data bytes 64 bytes from 220.181.38.148: seq=0 ttl=37 time=51.866 ms 64 bytes from 220.181.38.148: seq=1 ttl=37 time=48.766 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 48.766/50.316/51.866 ms CTRL+p CTRL+q $ docker container attach alpine3 # ping -c 2 baidu.com PING baidu.com (220.181.38.148): 56 data bytes 64 bytes from 220.181.38.148: seq=0 ttl=37 time=54.179 ms 64 bytes from 220.181.38.148: seq=1 ttl=37 time=55.131 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 54.179/54.655/55.131 ms CTRL+p CTRL+q $ docker container attach alpine1 # ping -c 2 baidu.com PING baidu.com (220.181.38.148): 56 data bytes 64 bytes from 220.181.38.148: seq=0 ttl=37 time=41.888 ms 64 bytes from 220.181.38.148: seq=1 ttl=37 time=68.809 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 41.888/55.348/68.809 ms CTRL+p CTRL+q
-
停止并卸下所有容器和
alpine-net
网络。$ docker container stop alpine1 alpine2 alpine3 alpine4 $ docker container rm alpine1 alpine2 alpine3 alpine4 $ docker network rm alpine-net