在实践中,本身会遇到2个容器之间互相访问通讯的问题,这个时候就用到了docker run --link选项。本身也花了一段时间泡官网研究了--link的用法,把本身对--link的理解分享下。注意!docker官方已不推荐使用docker run --link来连接2个容器互相通讯,随后的版本中会删除--link,但了解其原理,对如何使2个容器之间互相通讯仍是有帮助的。node
docker run --link能够用来连接2个容器,使得源容器(被连接的容器)和接收容器(主动去连接的容器)之间能够互相通讯,而且接收容器能够获取源容器的一些数据,如源容器的环境变量。git
--link的格式:github
--link <name or id>:aliaschrome
其中,name和id是源容器的name和id,alias是源容器在link下的别名。docker
eg:ubuntu
源容器ruby
docker run -d --name selenium_hub selenium/hub
bash
建立并启动名为selenium_hub的容器。tcp
接收容器oop
docker run -d --name node --link selenium_hub:hub selenium/node-chrome-debug
建立并启动名为node的容器,并把该容器和名为selenium_hub的容器连接起来。其中:
--link selenium_hub:hub
selenium_hub是上面启动的1cbbf6f07804容器的名字,这里做为源容器,hub是该容器在link下的别名(alias),通俗易懂的讲,站在node容器的角度,selenium_hub和hub都是1cbbf6f07804容器的名字,而且做为容器的hostname,node用这2个名字中的哪个均可以访问到1cbbf6f07804容器并与之通讯(docker经过DNS自动解析)。咱们能够来看下:
进入node容器:
docker exec -it node /bin/bash root@c4cc05d832e0:~# ping selenium_hub PING hub (172.17.0.2) 56(84) bytes of data. 64 bytes from hub (172.17.0.2): icmp_seq=1 ttl=64 time=0.184 ms 64 bytes from hub (172.17.0.2): icmp_seq=2 ttl=64 time=0.133 ms 64 bytes from hub (172.17.0.2): icmp_seq=3 ttl=64 time=0.216 ms root@c4cc05d832e0:~# ping hub PING hub (172.17.0.2) 56(84) bytes of data. 64 bytes from hub (172.17.0.2): icmp_seq=1 ttl=64 time=0.194 ms 64 bytes from hub (172.17.0.2): icmp_seq=2 ttl=64 time=0.218 ms 64 bytes from hub (172.17.0.2): icmp_seq=3 ttl=64 time=0.128 ms
可见,selenium_hub和hub都指向172.17.0.2。
按照上例的方法就能够成功的将selenium_hub和node容器连接起来,那这2个容器间是怎么通讯传送数据的呢?另外,前言中提到的接收容器能够获取源容器的一些信息,好比环境变量,又是怎么一回事呢?
源容器和接收容器之间传递数据是经过如下2种方式:
docker会在接收容器中设置名为<alias>_NAME的环境变量,该环境变量的值为:
<alias>_NAME=/接收容器名/源容器alias
咱们进入node容器,看下此环境变量:
docker exec -it node /bin/bash seluser@c4cc05d832e0:/$ env | grep -i hub_name HUB_NAME=/node/hub
可见,确实有名为HUB_NAME=/node/hub的环境变量存在。
另外,docker还会在接收容器中建立关于源容器暴露的端口号的环境变量,这些环境变量有一个统一的前缀名称:
<name>PORT<port>_<protocol>
其中:
<name>表示连接的源容器alias
<port>是源容器暴露的端口号
<protocol>是通讯协议:TCP or UDP
docker用上面定义的前缀定义3个环境变量:
<name>PORT<port>_<protocol>ADDR
<name>PORT<port><protocol>PORT
<name>PORT<port><protocol>_PROTO
注意,若源容器暴露了多个端口号,则每1个端口都有上面的一组环境变量(包含3个环境变量),即若源容器暴露了4个端口号,则会有4组12个环境变量。
查看selenium/hub的Dockerfile,可见只暴露了4444端口号:
EXPOSE 4444
咱们进入node容器,看这些此环境变量:
docker exec -it node /bin/bash seluser@c4cc05d832e0:/$ env | grep -i HUB_PORT_4444_TCP_ HUB_PORT_4444_TCP_PROTO=tcp HUB_PORT_4444_TCP_ADDR=172.17.0.2 HUB_PORT_4444_TCP_PORT=4444
可见,确实有3个以<name>PORT<port><protocol>为前缀的环境变量存在。
另外,docker还在接收容器中建立1个名为<alias>_PORT的环境变量,值为源容器的URL:源容器暴露的端口号中最小的那个端口号。
咱们进入node容器,看下此环境变量:
docker exec -it node /bin/bash seluser@c4cc05d832e0:/$ env | grep -i HUB_PORT= HUB_PORT=tcp://172.17.0.2:4444
可见,此环境变量的确存在。
docker会在接收容器中建立一些环境变量,这些环境变量是的值是关于源容器自己的环境变量的值。这些环境变量的定义格式为:
<alias>ENV<name>
查看selenium/hub的Dockerfile,可见Dockerfile中ENV标签设置的环境变量有:
# As integer, maps to "maxSession" ENV GRID_MAX_SESSION 5 # In milliseconds, maps to "newSessionWaitTimeout" ENV GRID_NEW_SESSION_WAIT_TIMEOUT -1 # As a boolean, maps to "throwOnCapabilityNotPresent" ENV GRID_THROW_ON_CAPABILITY_NOT_PRESENT true # As an integer ENV GRID_JETTY_MAX_THREADS -1 # In milliseconds, maps to "cleanUpCycle" ENV GRID_CLEAN_UP_CYCLE 5000 # In seconds, maps to "browserTimeout" ENV GRID_BROWSER_TIMEOUT 0 # In seconds, maps to "timeout" ENV GRID_TIMEOUT 30 # Debug ENV GRID_DEBUG false
咱们进入selenium_hub容器,看下这些环境变量:
root@ubuntu:~# docker exec -it selenium_hub /bin/bash seluser@1cbbf6f07804:/$ env | grep -i grid_ GRID_DEBUG=false GRID_TIMEOUT=30 GRID_CLEAN_UP_CYCLE=5000 GRID_MAX_SESSION=5 GRID_JETTY_MAX_THREADS=-1 GRID_BROWSER_TIMEOUT=0 GRID_THROW_ON_CAPABILITY_NOT_PRESENT=true GRID_NEW_SESSION_WAIT_TIMEOUT=-1
咱们再进入node容器,看下node容器中关于selenium_hub的<alias>ENV<name>环境变量:
docker exec -it node /bin/bash seluser@c4cc05d832e0:/$ env | grep -i hub_env HUB_ENV_GRID_DEBUG=false HUB_ENV_GRID_TIMEOUT=30 HUB_ENV_DEBCONF_NONINTERACTIVE_SEEN=true HUB_ENV_GRID_CLEAN_UP_CYCLE=5000 HUB_ENV_GRID_MAX_SESSION=5 HUB_ENV_TZ=UTC HUB_ENV_GRID_JETTY_MAX_THREADS=-1 HUB_ENV_DEBIAN_FRONTEND=noninteractive HUB_ENV_GRID_BROWSER_TIMEOUT=0 HUB_ENV_GRID_THROW_ON_CAPABILITY_NOT_PRESENT=true HUB_ENV_GRID_NEW_SESSION_WAIT_TIMEOUT=-1
可见,selenium_hub容器中的GRID_* 环境变量均在node容器中被建立,只不过名称变为HUB_ENV_GRID_* 而已。
环境变量的注意事项
注意,接收容器环境变量中存储的源容器的IP,不会自动更新,即,若源容器重启,则接收容器环境变量中存储的源容器的IP极可能就失效了。因此,docker官方建议使用/etc/hosts来解决上述的IP失效问题。
docker会将源容器的host更新到目标容器的/etc/hosts中:
咱们再进入node容器,查看node容器中的/etc/hosts文件的内容:
docker exec -it node /bin/bash seluser@c4cc05d832e0:/$ 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 hub 1cbbf6f07804 selenium_hub 172.17.0.3 c4cc05d832e0
其中172.17.0.3是node容器的ip,并使用node容器的容器id做为host name。另外,源容器的ip和hostname也写进来了,172.17.0.2是selenium_hub容器的ip,hub是容器在link下的alias,后面是hub容器的容器id。
若是重启了源容器,接收容器的/etc/hosts会自动更新源容器的新ip。
在--link标签下,接收容器就是经过设置环境变量和更新/etc/hosts文件来获取源容器的信息,并与之创建通讯和传递数据的。
在docker的后续版本中,会取消docker run中的--link选项,但了解其如何在2个容器之间创建通讯的原理是很是有用的,由于这有助于理解如何用官方推荐的全部容器在同一个network下来通讯的方法,以及用docker-compose来连接2个容器来通讯的方法。
9月初就用--link方法链接了seleniumhub和seleniumnode容器,可是不明白--link的做用,最近花了几天时间读官方文档,终于算搞清楚了,也把本身的理解在这里分享下。