在實踐中,本身會遇到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的做用,最近花了幾天時間讀官方文檔,終於算搞清楚了,也把本身的理解在這裏分享下。