对于复杂的应用,不可避免须要多个服务部署在多个容器中,而且服务间存在相互间通讯的状况。好比服务A须要链接mysql的容器。本文将介绍docker的容器网络,并经过实践解决在同一个docker Host主机下的容器间通讯的问题。node
在安装好docker后,docker将建立一个linux网桥docker0,它在内核层连通了其余的物理或虚拟网卡,也就是全部容器和本地主机都放到同一个物理网络。咱们能够经过 brctl 命令查看网桥的信息,brctl是须要自行安装的。mysql
[root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces br-1a83283cbf04 8000.0242123432ad no br-70590112bbda 8000.0242927ea6d9 no docker0 8000.024232ccc082 no
另外,docker还会给咱们建立三个网络:bridge/host/none。咱们能够经过network ls命令查看当前宿主机中全部的docker网络。linux
[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 5a9ac72df73f bridge bridge local 7d9eb4bd321c host host local 4b740dab2aab none null local
其中,网桥bridge模式是在实际项目中经常使用的。接下来,以交互模式启动两个busybox容器。在没有指定相关网络的状况下,容器都会链接到默认的bridge网络。咱们能够经过 --network 参数指定容器链接的网络。sql
[root@localhost ~]# docker run -itd --name=busybox1 busybox 2813aba53acd688fa69807158830bef27b4ea8dc2ecfe13e7e357ce98a204f0b [root@localhost ~]# docker run -itd --name=busybox2 busybox 83fbeeb4e0527ece0602729415a57383b474284143a381e0a27561a69d75b1f5
启动容器后,检查当前默认bridge网络状况。busybox1和busybox2容器已经链接到了bridge网络,除此以外,还能够获取到两个容器的IP地址。docker
[root@localhost ~]# docker network inspect bridge [ { "Name": "bridge", "Id": "5a9ac72df73f19beaade92a28d705509fd24c350497dd90ecae224fdb18214bc", "Created": "2018-12-25T16:30:26.58008782+08: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": { "2813aba53acd688fa69807158830bef27b4ea8dc2ecfe13e7e357ce98a204f0b": { "Name": "busybox1", "EndpointID": "522f2b4b072098525939cc6b313f5673f82444d8ef6807bac0efcdce6a7c8418", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "83fbeeb4e0527ece0602729415a57383b474284143a381e0a27561a69d75b1f5": { "Name": "busybox2", "EndpointID": "e277940484662a341730766300149c2f63974d0b9e9cbd6c531bc7c8c37f31f9", "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": {} } ]
接下来,咱们测试下两个容器的互通状况。bash
进入busybox1容器,分别ping 容器busybox2的IP和容器名,能够发现能够经过IP地址ping通busybox2,可是不能经过容器ping通。其中,172.17.0.3是busybox2的IP地址。服务器
[root@localhost ~]# docker attach 2813aba53acd / # ping 172.17.0.3 PING 172.17.0.3 (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.090 ms 64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.193 ms / # ping busybox2
在容器中,能够查看容器的hosts文件,里面没有任何关于busybox2容器的信息。网络
/ # cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 2813aba53acd
在计算机网络中,想经过域名ping通其它网站,有两种方法:一种是本地的hosts文件,里面配置的是路由规则;另外一种是DNS服务,经过DNS服务器返回正确的IP地址。那么docker是否也能够经过容器名访问其它容器的方式呢?oop
(1)link链接测试
默认的桥接网络支持使用端口映射和 docker run --link 命令,实现容器间互相通讯。该方法已经在官方文档中标识为不推荐使用。
https://docs.docker.com/network/links/
下面,继续介绍经过 --link 参数时间容器间通讯。咱们将建立busybox3和busybox4两个容器,其中busybox4能够经过busybox3容器名与busybox3容器进行通讯。
新建busybox3和busybox4,其中busybox4经过 --link 参数指定链接到 busybox3容器。
[root@localhost ~]# docker run -itd --name=busybox3 busybox a539a74a9ecad6782f88944604bbdd045f4a1fd6965a3484e04d1dbbec1e511d [root@localhost ~]# docker run -itd --link busybox3 --name=busybox4 busybox f6c470354b55300106a3a8960c4c935dcdd0cb0f7ad6c941c8f040fdb0cd0a04
从新进入容器busybox4,查看hosts文件,能够看到host文件中已经出现busybox3容器,并配置了路由规则。
/ # cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.4 busybox3 a539a74a9eca 172.17.0.5 f6c470354b55
测试busybox4链接容器busybox3
/ # ping busybox3 PING busybox3 (172.17.0.4): 56 data bytes 64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.077 ms 64 bytes from 172.17.0.4: seq=1 ttl=64 time=0.125 ms ^C --- busybox3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss
(2)自定义bridge网络,实现容器间通讯
从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器能够直接经过“容器名”通讯。使用默认的bridge网络,不能经过DNS server实现经过容器名通讯,可是使用自定义bridge网络能够作到经过容器名互相通讯。
经过 docker network create 命令建立一个自定义的bridge网络
[root@localhost ~]# docker network create --driver bridge busybox_bridge 1a83283cbf047fea14231daef7edb67e8a11383f61c176e5c4983e961e757a1e [root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 53c7e86fc3ec bridge bridge local 1a83283cbf04 busybox_bridge bridge local 7d9eb4bd321c host host local 4b740dab2aab none null local
分别建立busybox5/busybox6容器,在run命令里加入--network参数使两个容器绑定到前面自定义的网络中。
[root@localhost ~]# docker run -itd --network busybox_bridge --name busybox5 busybox ccd81a357cf48af2c01c64cd1ef7a4c463b415bd477d965f19a3b47be3760208 [root@localhost ~]# docker run -itd --network busybox_bridge --name busybox6 busybox d3e5af0eeb86a480fe868bb9ea7cea2cb29b7f12b7f680cbd5b48288c15b10e9
查看busybox_bridge网络状况,能够看到,busybox5/busybox6容器已经绑定到该网络中。
[root@localhost ~]# docker network inspect busybox_bridge [ { "Name": "busybox_bridge", "Id": "1a83283cbf047fea14231daef7edb67e8a11383f61c176e5c4983e961e757a1e", "Created": "2018-12-25T22:17:10.981291803+08:00", "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": { "ccd81a357cf48af2c01c64cd1ef7a4c463b415bd477d965f19a3b47be3760208": { "Name": "busybox5", "EndpointID": "4da57d779c14bdee415eee69a92dd802250bf6e89cd744f8543c4498e32aebdc", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" }, "d3e5af0eeb86a480fe868bb9ea7cea2cb29b7f12b7f680cbd5b48288c15b10e9": { "Name": "busybox6", "EndpointID": "6f130cc2055399c051cd556e20835793332605f9ee636885c602f2b257f9db80", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ]
接下来进入busybox5容器,测试是否能够经过容器名ping通busybox6
[root@localhost ~]# docker attach busybox5 / # ping busybox6 PING busybox6 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.107 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.149 ms
看下容器的hosts文件,文件里是没有busybox6的映射配置的。那么它是怎么经过容器名访问到另外一个容器的呢?答案就是内嵌的dns服务器。
/ # cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.18.0.2 ccd81a357cf4
查看DNS服务,能够看到指定了DNS解析服务地址:nameserver 127.0.0.11 。若是是链接到默认bridge网络的容器,在resolv.conf文件是没有127.0.0.11这个DNS服务器配置的
/ # cat /etc/resolv.conf nameserver 127.0.0.11 options ndots:0
容器中的DNS名称解析优先级顺序为:
文章收录于: