12-容器之间link
这篇主要讲 容器之间如何 link。
需要准备的是,创建两个容器 test1 和 test2 通过 busybox。
在之前的课程中已经创建的只需要重新启动即可。
什么情况下需要link
例如有一个容器是 web 服务器,并且跑在一个docker容器内,这个web程序需要访问后台数据库,一般来说我们会把数据库也运行在一个docker的容器内,那么此时就需要两个容器进行 link。
访问数据库需要知道数据库的ip地址和端口,那么我们在开发的时候是不能确定数据库的ip地址的,而且也有可能数据库地址会发生变化,那么我们将很难修改配置。
查看容器的ip地址命令
docker inspect test1
但是我们可以通过一种方式,给容器起一个名字,然后可以通过这个名字就可以代替ip地址访问数据库。这时只需要在开发的时候先想好这个数据库容器的名字即可。
link容器
-  删除 test2 容器 docker stop test2 && docker rm test2查看当前容器情况 docker ps[vagrant@10 ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da991beadf34 busybox "/bin/sh -c 'while t…" 5 hours ago Up 5 hours test1
-  重新创建 test2 通过 link 连接到 test1 容器 docker run -d --name test2 --link test1 busybox /bin/sh -c "while true; do sleep 3600; done"
-  进入 test2 容器 docker exec -it test2 /bin/sh
-  查看ip情况 / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever 27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ffinet 172.17.0.3/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft foreverping test1 容器的地址 / # ping 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.225 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.156 ms是可以ping通的,那么我们ping test1 这个名字呢? / # ping test1 PING test1 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.167 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.190 msping 这个 test1 名字也是可以的。这是为什么呢?原因就是 --link参数会增加一个 DNS 记录。
这样我们在 test2 中是不需要知道 test1 的具体地址的,我们就可以访问。但是在test1中去ping test2 名字是不可以的,ip是可以的。说明 --link是具有方向性的。
通过自定义bridge连接容器
-  重新创建一个 test2 docker stop test2 && docker rm test2docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done"
-  查看docker network [vagrant@10 ~]$ docker network ls NETWORK ID NAME DRIVER SCOPE 056d0ece100f bridge bridge local a78b081f0bda host host local 51a236124cac none null local其实我们在创建容器的时候,默认会去连 bridge,但是我们也可以设定连接 host 或者 none。 
-  手动创建一个bridge docker network create -d bridge my-bridge-d 为选择驱动driver 查看创建情况 [vagrant@10 ~]$ docker network ls NETWORK ID NAME DRIVER SCOPE 056d0ece100f bridge bridge local a78b081f0bda host host local 283184c10e65 my-bridge bridge local 51a236124cac none null local通过brctl查看 [vagrant@10 ~]$ brctl show bridge name bridge id STP enabled interfaces br-283184c10e65 8000.02421fd39394 no docker0 8000.024257ac11fe no veth01f8da0veth06618ed这里的 br-283184c10e65就是我们刚刚创建的bridge。
-  创建 test3 指定连接新的bridge docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 3600; done"如果不指定则默认连接bridge 查看容器 [vagrant@10 ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cadffadd2dcf busybox "/bin/sh -c 'while t…" 28 seconds ago Up 27 seconds test3 f984609b03ee busybox "/bin/sh -c 'while t…" 14 minutes ago Up 14 minutes test2 da991beadf34 busybox "/bin/sh -c 'while t…" 5 hours ago Up 5 hours test1通过brctl查看 [vagrant@10 ~]$ brctl show bridge name bridge id STP enabled interfaces br-283184c10e65 8000.02421fd39394 no veth7092b9a docker0 8000.024257ac11fe no veth01f8da0veth06618ed从上面可以看到 test3 连接到了 我们自己创建的bridge。 查看我们创建的 my-bridge 网络情况。 $:docker inspect network 283184c10e65 "Containers": { "cadffadd2dcf756d982c219c819b66ba1b6dea9224bbededa9a5069654427bd0": {"Name": "test3","EndpointID": "f0a6e3343b0deeb420d63faf378affbacbec6714b674b1a5fbe472545f1ed674","MacAddress": "02:42:ac:12:00:02","IPv4Address": "172.18.0.2/16","IPv6Address": "" }这里可以看到 test3 确实是连接到了我们自己创建的bridge上。 
-  更改 test2 连接到 my-bridge上$: docker network connect my-bridge test2 "Containers": { "cadffadd2dcf756d982c219c819b66ba1b6dea9224bbededa9a5069654427bd0": {"Name": "test3","EndpointID": "f0a6e3343b0deeb420d63faf378affbacbec6714b674b1a5fbe472545f1ed674","MacAddress": "02:42:ac:12:00:02","IPv4Address": "172.18.0.2/16","IPv6Address": "" }, "f984609b03ee96dc20a90053699cc46cc41969c20d07625826100535b4369a57": {"Name": "test2","EndpointID": "0bf52944835e82a689f863764ac8b4309ff157d566857913fca4da76278aa9d8","MacAddress": "02:42:ac:12:00:03","IPv4Address": "172.18.0.3/16","IPv6Address": "" }可以看到 test2 已经连接到了 my-bridge上。也可以通过brctl查看[vagrant@10 ~]$ brctl show bridge name bridge id STP enabled interfaces br-283184c10e65 8000.02421fd39394 no veth7092b9avethd05370d docker0 8000.024257ac11fe no veth01f8da0veth06618ed再查看默认的 bridge$: docker network inspect bridge "Containers": { "da991beadf34ef53be9cf3de8f0c5ba1599b76f4433f6627f96c46c09751ecf5": {"Name": "test1","EndpointID": "4764dcc3a29b9ee7efb6ea5dc5c905840362c8ddc0d944356a4c0e7b07a99d98","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": "" }, "f984609b03ee96dc20a90053699cc46cc41969c20d07625826100535b4369a57": {"Name": "test2","EndpointID": "024a2dfeb6b74aac46c3d61a6b2d834fa20c63f47e3a0f0db5aaad78c84442af","MacAddress": "02:42:ac:11:00:03","IPv4Address": "172.17.0.3/16","IPv6Address": "" }那么 test2 既连接到 bridge也连接到了我们创建的my-bridge上。
-  测试连通情况 进入 test3 docker exec -it test3 /bin/sh查看ip / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever 32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ffinet 172.18.0.2/16 brd 172.18.255.255 scope global eth0valid_lft forever preferred_lft forever刚刚查看 test2 在 my-bridge上的ip地址为 172.18.0.3,那我们ping测试/ # ping 172.18.0.3 PING 172.18.0.3 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.171 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.179 ms是可以ping通的。现在我们去ping test2 这个名字。 / # ping test2 PING test2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.151 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.178 ms是可以ping通的。这是为什么呢?我们并没有设定 link参数,这是因为 test2 和 test3 都连接到了我们创建的my-bridge上。到这里也许会有疑问,之前 test1 和 test2 也是连接到同一个bridge上的,不加link参数为什么就不能ping通呢?这是因为在创建自定义my-bridge的时候是和默认bridge不一样的,如果两个容器都连接到了自定义的bridge上,那么这两个容器默认是项目link的。这时可以测试一下在 test2 中是否可以 ping 通 test3,答案是可以的。 [vagrant@10 ~]$ docker exec -it test2 /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever 29: eth0@if30: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ffinet 172.17.0.3/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever 34: eth1@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ffinet 172.18.0.3/16 brd 172.18.255.255 scope global eth1valid_lft forever preferred_lft forever我们可以看到这里有两个ip地址,一个是 172.17.0.3,另一个是 172.18.0.3,这是因为 test2 连接到了两个bridge上,从而分配了两个ip地址。 测测ping test3 / # ping test3 PING test3 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.248 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.173 ms结果是连通的。那么ping test1 呢,其实很明显,是不通的。 / # ping test1 ping: bad address 'test1'那么如果我们把 test1 也连接到自定义的 my-bridge上,也是可以ping通的,那我们实验一下。将 test1 连接到 my-bridge上。[vagrant@10 ~]$ docker network connect my-bridge test1进入 test2 并 ping test1 [vagrant@10 ~]$ docker exec -it test2 /bin/sh / # ping test1 PING test1 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.217 ms
其实一般来说,在实际项目中很少使用
--link参数,而是使用 创建自定义bridge的方式进行连接。