前言
在實踐中,自己會遇到2個容器之間互相訪問通信的問題,這個時候就用到了docker run --link選項。自己也花了一段時間泡官網(wǎng)研究了--link的用法,把自己對--link的理解分享下狰贯。注意!docker官方已不推薦使用docker run --link來鏈接2個容器互相通信赏廓,隨后的版本中會刪除--link涵紊,但了解其原理,對如何使2個容器之間互相通信還是有幫助的幔摸。
1. docker run --link的作用
docker run --link可以用來鏈接2個容器摸柄,使得源容器(被鏈接的容器)和接收容器(主動去鏈接的容器)之間可以互相通信,并且接收容器可以獲取源容器的一些數(shù)據(jù)抚太,如源容器的環(huán)境變量塘幅。
--link的格式:
--link <name or id>:alias
其中,name和id是源容器的name和id尿贫,alias是源容器在link下的別名电媳。
eg:
源容器
docker run -d --name selenium_hub selenium/hub
創(chuàng)建并啟動名為selenium_hub的容器。
接收容器
docker run -d --name node --link selenium_hub:hub selenium/node-chrome-debug
創(chuàng)建并啟動名為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。
2. --link下容器間的通信
按照上例的方法就可以成功的將selenium_hub和node容器鏈接起來废酷,那這2個容器間是怎么通信傳送數(shù)據(jù)的呢瘟檩?另外,前言中提到的接收容器可以獲取源容器的一些信息澈蟆,比如環(huán)境變量墨辛,又是怎么一回事呢?
源容器和接收容器之間傳遞數(shù)據(jù)是通過以下2種方式:
- 設(shè)置環(huán)境變量
- 更新/etc/hosts文件
2.1 設(shè)置環(huán)境變量
- 當使用--link時趴俘,docker會自動在接收容器內(nèi)創(chuàng)建基于--link參數(shù)的環(huán)境變量:
docker會在接收容器中設(shè)置名為<alias>_NAME的環(huán)境變量睹簇,該環(huán)境變量的值為:
<alias>_NAME=/接收容器名/源容器alias
我們進入node容器奏赘,看下此環(huán)境變量:
docker exec -it node /bin/bash
seluser@c4cc05d832e0:/$ env | grep -i hub_name
HUB_NAME=/node/hub
可見,確實有名為HUB_NAME=/node/hub的環(huán)境變量存在带膀。
另外志珍,docker還會在接收容器中創(chuàng)建關(guān)于源容器暴露的端口號的環(huán)境變量,這些環(huán)境變量有一個統(tǒng)一的前綴名稱:
<name>PORT<port>_<protocol>
其中:
<name>表示鏈接的源容器alias
<port>是源容器暴露的端口號
<protocol>是通信協(xié)議:TCP or UDP
docker用上面定義的前綴定義3個環(huán)境變量:
<name>PORT<port>_<protocol>ADDR
<name>PORT<port><protocol>PORT
<name>PORT<port><protocol>_PROTO
注意垛叨,若源容器暴露了多個端口號,則每1個端口都有上面的一組環(huán)境變量(包含3個環(huán)境變量)柜某,即若源容器暴露了4個端口號嗽元,則會有4組12個環(huán)境變量。
查看selenium/hub的Dockerfile喂击,可見只暴露了4444端口號:
EXPOSE 4444
我們進入node容器剂癌,看這些此環(huán)境變量:
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>為前綴的環(huán)境變量存在翰绊。
另外佩谷,docker還在接收容器中創(chuàng)建1個名為<alias>_PORT的環(huán)境變量,值為源容器的URL:源容器暴露的端口號中最小的那個端口號监嗜。
我們進入node容器谐檀,看下此環(huán)境變量:
docker exec -it node /bin/bash
seluser@c4cc05d832e0:/$ env | grep -i HUB_PORT=
HUB_PORT=tcp://172.17.0.2:4444
可見,此環(huán)境變量的確存在裁奇。
- 接收容器還會獲取源容器暴露的環(huán)境變量桐猬,這些變量包括:
- 源容器Dockerfile中ENV標簽設(shè)置的環(huán)境變量
- 源容器用docker run命令創(chuàng)建,命令中包含的 -e或--env或--env-file設(shè)置的環(huán)境變量
docker會在接收容器中創(chuàng)建一些環(huán)境變量刽肠,這些環(huán)境變量是的值是關(guān)于源容器本身的環(huán)境變量的值溃肪。這些環(huán)境變量的定義格式為:
<alias>ENV<name>
查看selenium/hub的Dockerfile,可見Dockerfile中ENV標簽設(shè)置的環(huán)境變量有:
# 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容器音五,看下這些環(huán)境變量:
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容器中關(guān)于selenium_hub的<alias>ENV<name>環(huán)境變量:
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_* 環(huán)境變量均在node容器中被創(chuàng)建躺涝,只不過名稱變?yōu)镠UB_ENV_GRID_* 而已厨钻。
環(huán)境變量的注意事項
注意,接收容器環(huán)境變量中存儲的源容器的IP诞挨,不會自動更新莉撇,即,若源容器重啟惶傻,則接收容器環(huán)境變量中存儲的源容器的IP很可能就失效了棍郎。所以,docker官方建議使用/etc/hosts來解決上述的IP失效問題银室。
2.2 更新/etc/hosts文件
docker會將源容器的host更新到目標容器的/etc/hosts中:
我們再進入node容器涂佃,查看node容器中的/etc/hosts文件的內(nèi)容:
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午笛。
總結(jié)
在--link標簽下惭蟋,接收容器就是通過設(shè)置環(huán)境變量和更新/etc/hosts文件來獲取源容器的信息,并與之建立通信和傳遞數(shù)據(jù)的药磺。
在docker的后續(xù)版本中告组,會取消docker run中的--link選項,但了解其如何在2個容器之間建立通信的原理是非常有用的癌佩,因為這有助于理解如何用官方推薦的所有容器在同一個network下來通信的方法木缝,以及用docker-compose來鏈接2個容器來通信的方法。
9月初就用--link方法連接了seleniumhub和seleniumnode容器围辙,但是不明白--link的作用我碟,最近花了幾天時間讀官方文檔,終于算搞清楚了酌畜,也把自己的理解在這里分享下怎囚。