很多时候,同一台机器上,需要运行多个docker容器,前文提到的docker-compose就是方便同时管理多个容器的工具,那么,容器与容器之间如何访问、通信呢?本文对此问题进行探讨。
方式一:内部网络 在安装docker时,会自动创建一个默认的bridge网络docker0。如下:
1 2 3 4 5 6 7 8 9 $ ifconfig docker0 Link encap:以太网 硬件地址 02:42:7b:b6:74:3b inet 地址:172.17.0.1 广播:0.0.0.0 掩码:255.255.0.0 inet6 地址: fe80::42:7bff:feb6:743b/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 跃点数:1 接收数据包:575938 错误:0 丢弃:0 过载:0 帧数:0 发送数据包:700716 错误:0 丢弃:0 过载:0 载波:0 碰撞:0 发送队列长度:0 接收字节:47416735 (47.4 MB) 发送字节:1246042404 (1.2 GB)
每个容器启动时,都会创建对应的网卡,地址为172.17.0.X,因此,容器之间都可以通过对应的IP地址进行访问。 然后,运行ubuntu镜像:
1 docker run -it –rm ubuntu bash
在同一台电脑启动另一个终端,启动ubuntu镜像,使用同样的命令启动ubuntu镜像:
1 docker run -it --rm ubuntu bash
两个容器的IP如下(因为都是相同的镜像,所以直接列出IP地址):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 root@4e097f487019:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02 inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:25 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:3653 (3.6 KB) TX bytes:0 (0.0 B) root@c02729d604f6:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03 inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:23 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:3380 (3.3 KB) TX bytes:0 (0.0 B)
Ping测试结果如下:
1 2 3 4 5 6 7 8 root@c02729d604f6:/# ping -c 3 172.17.0.2 PING 172.17.0.3 (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.178 ms 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.118 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.119 ms --- 172.17.0.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.118/0.138/0.178/0.028 ms
这个方式只能通过IP形式,前提是要知道每个容器的IP地址。这种方式实用性不强。
方式二:使用link 在方式一基础上,使用–link选项,则可以将网络别名(或容器别名)的方法进行ping。 先启动ubuntu镜像:
1 docker run -it --rm --name ubuntu1 ubuntu bash
这里将其命名为ubnntu1。 接着在另一个终端启动再启动ubuntu镜像:
1 docker run -it --rm --name ubuntu2 --link ubuntu1:ubuntu1 ubuntu bash
这个容器命名为ubuntu2,而且将其连接到ubuntu1中。注意–link ubuntu1:ubuntu1第一个ubuntu1表示容器,第二个ubuntu1表示网络/容器别名。为了统一性,建议两者相同(这种情况下,只需要写–link ubuntu1即可,文中只是为了示例其选项用法)。 在这个容器中查看hosts文件,内容如下:
1 2 3 4 5 6 7 8 9 root@f8199115a731:/# 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 ubuntu1 e288b5d2f0a4 172.17.0.3 f8199115a731
倒数第二行看到,已经将IP地址172.17.0.2和ubuntu1(容器ID为e288b5d2f0a4)对应起来了。 下面ping测试
1 2 3 4 5 6 7 8 9 root@f8199115a731:/# ping -c 3 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.123 ms 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.111 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.109 ms --- 172.17.0.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.109/0.114/0.123/0.000 ms root@f8199115a731:/#
使用ping -c 3 ubuntu1也可以ping通。
1 2 3 4 5 6 7 8 root@f8199115a731:/# ping -c 3 ubuntu1 PING ubuntu1 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.134 ms 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.121 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.121 ms --- ubuntu1 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.121/0.125/0.134/0.000 ms
对于容器A和容器B之间使用–link连接,必须先启动其中一个容器,比如容器A,然后在启动容器B时,将其连接到容器A。这样,就可以在容器B中使用网络别名连接容器A了。以gitlab为jenkins为例,实际应用中,需要先启动gitlab,然后启动jenkins并连接到gitlab容器。
方式三:自定义bridge网络 首先在主机上创建一个网络,命令如下:
1 docker network create mynet
在主机用ifconfig查看网络情况,对应的网卡地址如下:
1 2 3 4 5 6 7 8 br-49d34a6504d1 Link encap:以太网 硬件地址 02:42:bc:ba:62:17 inet 地址:172.18.0.1 广播:0.0.0.0 掩码:255.255.0.0 inet6 地址: fe80::42:bcff:feba:6217/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 跃点数:1 接收数据包:1400 错误:0 丢弃:0 过载:0 帧数:0 发送数据包:1558 错误:0 丢弃:0 过载:0 载波:0 碰撞:0 发送队列长度:0 接收字节:79757 (79.7 KB) 发送字节:3650465 (3.6 MB)
注:可以创建多个网络,每个网络IP范围均不相同。 然后,运行ubuntu镜像:
1 docker run -it --rm --network mynet --network-alias ubuntu1 ubuntu bash
其中,--network mynet
表示使用mynet网络,--network-alias ubuntu1
表示该容器运行时,使用的网络别名为ubuntu1。(网络别名的作用类似hostname,不管容器IP如何变化,都可以使用同一个别名。) 接着,在同一台电脑启动另一个终端,启动ubuntu镜像:
1 docker run -it --rm --network mynet --network-alias ubuntu2 ubuntu bash
命令形式同上。只是将网络别名改为ubuntu2。 在ubuntu容器中使用ifconfig查看该容器的IP地址,如下:
1 2 3 4 5 6 7 8 root@74f4089ce79c:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:12:00:02 inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1575 errors:0 dropped:0 overruns:0 frame:0 TX packets:1405 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3652734 (3.6 MB) TX bytes:99679 (99.6 KB)
再ping另一个容器ubuntu2,结果可以ping通。
1 2 3 4 root@74f4089ce79c:/# ping ubuntu2 PING jenkins (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: icmp_seq=0 ttl=64 time=0.142 ms 64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.131 ms
同样地,在ubuntu2容器中ping另一个容器ubuntu,也可以ping通。
1 2 3 4 root@927fe3bab506:/# ping ubuntu PING ubuntu (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.122 ms 64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.113 ms
推荐使用这个方式。 默认网络中的link是静态的,不允许链接容器重启,而自定义网络下的link是动态的,支持链接容器重启(以及IP变化) 因此,使用–link时链接的容器,在默认网络中必须提前创建好,而自定义网络下不必预先建好。使用网络别名后,不管容器ip地址如何变化,都可以根据别名进行连接。
docker网络相关命令 在主机上创建一个网络,命令如下:
1 docker network create mynet
查看自定义bridge网络命令如下:
1 docker network inspect mynet
移除网络要求网络中所有的容器关闭或断开与此网络的连接时,才能够使用移除命令:
1 docker network disconnet mynet 容器ID
再移除网络