1. 程式人生 > >wwwhy76888com理解容器間link通信機制199O8836661

wwwhy76888com理解容器間link通信機制199O8836661

定義網絡 pass 包括 建立 保留 方便 基本功 fin 排除

一、什麽是docker的link機制?

同一個宿主機上的多個docker容器之間如果想進行通信,可以通過使用容器的ip地址來通信,也可以通過宿主機的ip加上容器暴露出的端口號來通信,前者會導致ip地址的硬編碼,不方便遷移,並且容器重啟後ip地址會改變,除非使用固定的ip,後者的通信方式比較單一,只能依靠監聽在暴露出的端口的進程來進行有限的通信。通過docker的link機制可以通過一個name來和另一個容器通信,link機制方便了容器去發現其它的容器並且可以安全的傳遞一些連接信息給其它的容器。其使用方式如下:

  1. 運行一個容器,通過–name指定一個便於記憶的名字,這個容器被稱為source container,也就是要連接的容器

$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=server -d mysql
上面通過傳遞環境變量MYSQL_ROOT_PASSWORD=server,來設置MySQL服務的密碼為server

  1. 運行另外一個容器,並link到上面啟動的容器,這個容器被稱為received container

$ docker run --name nginx --link mysql:aliasmysql -d nginx
上面通過–link連接名為db的容器,並為其設置了別名aliasmysql。

完成了上面的兩個步驟後,在nginx的容器中就可以使用db或者aliasmysql作為連接地址來連接MySQL服務,即使容器重啟了,地址發生了變化,不會影響兩個容器之間的連接。

Docker:理解容器間link通信機制
二、link機制的連接信息傳遞

雖然通過使用link機制nginx可以和MySQL進行通信了,但是如何知道Mysql的端口是多少呢?雖然說是固定的是3306,但是也不排除更改端口號的問題,並且對應一些非固定端口的應用來說,只要連接的容器的端口信息也是尤為重要的,link機制通過環境變量的方式提供了這些信息,除此之外像mysql的密碼這些信息也會通過環境變量提供,docker將source container中定義的環境變量全部導入到received container中,在received container中可以通過環境變量來獲取連接信息下面是mysql中提供的環境變量:

第一個部分是nginx容器自身提供的一些環境變量,如NGINX_VERSION,HOSTNAME,HOME,PATH等。
第二個部分則是ALIASMYSQL_ENV開頭的變量,這些都是從source container中導入的,變量來源於Dockerfile中使用ENV命令定義的變量,或者是docker run的時候通過-e添加的環境變量。
第三個部分是ALIASMYSQL_NAME這個變量,這變量記錄了link的兩個容器的組合,這裏就是/nginx/aliasmysql。
第四個部分就是ALIASMYSQL_PORT開頭的一系列變量,這些變量會有分組,每組變量的命名格式如下

其中<port>是在Dockerfile中使用EXPOSE導出的端口,還有docker run的時候使用-p導出的端口。<protocol>則是這些端口對應的協議。

第五個部分就是ALIASMYSQL_PORT這個變量,這個變量是EXPOSE導出端口中的第一個端口對應的連接url, 如果有EXPOSE導出的端口,還有docker run -p指定導出的端口,那麽通過-p指定的端口是第一個被導出的端口。
三、link機制和/etc/hosts

使用了link機制後,可以通過指定的名字來和目標容器通信,這其實是通過給/etc/hosts中加入名稱和IP的解析關系來實現的,下面是名為nginx的容器中的/etc/hosts信息。

通過上面的信息可以看出,link機制給received container(這裏是名為nginx的容器)添加了一條關於mysql容器的名稱解析。有了這個名稱解析後就可以不使用ip來和目標容器通信了,除此之外當目標容器重啟,docker會負責更新/etc/hosts文件,因此可以不用擔心容器重啟後IP地址發生了改變,解析無法生效的問題。但是很不幸的是,環境變量無法更新,上文中提到了link機制會通過環境變量將一些mysql容器的信息導入到nginx容器中,這種導入是一次性的,此後這個容器更新了環境變量的信息是無法在nginx容器中更新的。

四、link機制和網絡新特性

通過上文中對link機制的介紹,可以發現link機制提供了如下幾個功能:名稱解析、對link的容器可以使用別名、安全的容器間連接通信、環境變量的註入。

對於安全的容器間連接通信,這個需要結合docker daemon的 -icc=false這個選項,默認同一個宿主機上的所有容器可以互相通信,當使用 -icc=false的時候所有容器之間是無法進行互相通信的(具體原因會單獨出篇文章分析),但是使用link機制後,即使使用了 -icc=false兩個容器之間也可以進行基於端口的通信。很不幸的是當docker引入網絡新特性後,link機制變的有些多余,但是為了兼容早期版本,–link機制在默認網絡上的功能依舊沒有發生變化,docker引入網絡新特性後,內置了一個DNS Server,但是只有用戶創建了自定義網絡後,這個DNS Server才會起作用。在網絡新特性為未引入之前,有三種網絡,第一種就是docker0這種橋接網絡,用的也是最多的,第二個則是復用主機網絡,稱為HOST網絡,第三種就是none網絡,只創建了一個空的網絡命名空間,沒有網絡接口,無法和外界通信,可以讓使用者自己去構建網絡。當網絡新特性引入後,有了overlay網絡,有了用戶自定義網絡。用戶自定義網絡下,用戶可以通過docker的network子命令創建一個自定義的橋接網絡,這個自定義橋接的網絡和默認的docker0橋接網絡基本功能都是一致的,只是在這個自定義橋接網絡中擁有一些特性,可以替代link機制。這些特性包括如下幾個方面:

在用戶自定義網絡下,不使用link機制就可以實現名稱解析功能了,不再是通過link機制追加名稱解析關系到/etc/hosts文件中了。並且在默認的docker0橋接網絡和自定義網絡下使用link機制的效果是不一樣的,在自定義網絡中link機制只是負責設置別名的,不再提供環境變量註入的功能了。自定義網絡中同時也提供了 --net-alias功能和link機制提供別名功能是一樣的。保留link機制目的是為了兼容。

五、link容器配置調用變量

前面我們已經說了,link主機會導入被link主機的環境變量,以供link主機服務的使用。這些被導入的環境變量前綴就是 --link時設置的主機別名,前綴之後的部分都是相同的。所以這些是有規律可循的。既然是Shell環境變量,如果你在link主機中跑的是shell腳本,那麽就簡單了,直接應用對應的變量即可。如下:

這些變量是默認的,當然你也可以在啟動link主機時使用-e傳入這些變量,但傳入的變量要跟容器中使用的變量約定好。

那麽如果不是shell腳本,是php、python、java的配置文件呢,如何使用傳入的shell變量?我能想到的方式就是在容器構建時,先執行一個shell腳本,使用一些shell命令(如sed)來替換配置文件中需要傳入的參數。然後再啟動服務。

六、link機制的缺點

停止link連接的目標容器,hosts文件並不會更新,只有目標容器重新啟動,才會更新hosts文件。
容器需要按照link之間的依賴關系依次啟動。
移除一個link連接的容器,可能會造成整個系統的link失效,需要刪除並重新建立所有使用–link的容器。
如果是新的docker系統,盡量使用docker的User-defined networks來控制容器之間的相互通信,同時官方文檔也提到 --link可能會在以後的版本中被移除,所以以前使用 --link的系統,如果條件允許,也應該盡量遷移到networks特性上面來。

wwwhy76888com理解容器間link通信機制199O8836661