1. 程式人生 > >我的docker隨筆8:docker容器相互訪問

我的docker隨筆8:docker容器相互訪問

很多時候,同一臺機器上,需要執行多個docker容器,前文提到的docker-compose就是方便同時管理多個容器的工具,那麼,容器與容器之間如何訪問、通訊呢?本文對此問題進行探討。

方式一:內部網路

在安裝docker時,會自動建立一個預設的bridge網路docker0。如下:

$ ifconfig 
docker0   Link encap:乙太網  硬體地址 02:42:7b:b6:74:3b  
          inet 地址:172.17.0.1  廣播:0.0.0.0  掩碼:255.255.0.0
          inet6 地址: fe80::42:7bff:feb6:
743b/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 躍點數:1 接收資料包:575938 錯誤:0 丟棄:0 過載:0 幀數:0 傳送資料包:700716 錯誤:0 丟棄:0 過載:0 載波:0 碰撞:0 傳送佇列長度:0 接收位元組:47416735 (47.4 MB) 傳送位元組:1246042404 (1.2 GB)

每個容器啟動時,都會建立對應的網絡卡,地址為172.17.0.X,因此,容器之間都可以通過對應的IP地址進行訪問。
然後,執行ubuntu映象:

docker run -it –rm ubuntu bash

在同一臺電腦啟動另一個終端,啟動ubuntu映象,使用同樣的命令啟動ubuntu映象:

docker run -it --rm ubuntu bash

兩個容器的IP如下(因為都是相同的映象,所以直接列出IP地址):

root@4e097f487019:/# ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          UP
BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:25 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3653 (3.6 KB) TX bytes:0 (0.0 B) root@c02729d604f6:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03 inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:23 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3380 (3.3 KB) TX bytes:0 (0.0 B)

Ping測試結果如下:

[email protected]:/# ping -c 3 172.17.0.2 
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.178 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.119 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.118/0.138/0.178/0.028 ms

這個方式只能通過IP形式,前提是要知道每個容器的IP地址。這種方式實用性不強。

在方式一基礎上,使用–link選項,則可以將網路別名(或容器別名)的方法進行ping。
先啟動ubuntu映象:

docker run -it --rm --name ubuntu1 ubuntu bash

這裡將其命名為ubnntu1。
接著在另一個終端啟動再啟動ubuntu映象:

docker run -it --rm --name ubuntu2 --link ubuntu1:ubuntu1  ubuntu bash

這個容器命名為ubuntu2,而且將其連線到ubuntu1中。注意–link ubuntu1:ubuntu1第一個ubuntu1表示容器,第二個ubuntu1表示網路/容器別名。為了統一性,建議兩者相同(這種情況下,只需要寫–link ubuntu1即可,文中只是為了示例其選項用法)。
在這個容器中檢視hosts檔案,內容如下:

[email protected]:/# 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      ubuntu1 e288b5d2f0a4
172.17.0.3      f8199115a731

倒數第二行看到,已經將IP地址172.17.0.2和ubuntu1(容器ID為e288b5d2f0a4)對應起來了。
下面ping測試

[email protected]:/# ping -c 3 172.17.0.2  
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.123 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.109 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.109/0.114/0.123/0.000 ms
[email protected]:/#

使用ping -c 3 ubuntu1也可以ping通。

[email protected]:/# ping -c 3 ubuntu1    
PING ubuntu1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.134 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.121 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.121 ms
--- ubuntu1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.121/0.125/0.134/0.000 ms

對於容器A和容器B之間使用–link連線,必須先啟動其中一個容器,比如容器A,然後在啟動容器B時,將其連線到容器A。這樣,就可以在容器B中使用網路別名連線容器A了。以gitlab為jenkins為例,實際應用中,需要先啟動gitlab,然後啟動jenkins並連線到gitlab容器。

方式三:自定義bridge網路

首先在主機上建立一個網路,命令如下:

docker network create mynet

在主機用ifconfig檢視網路情況,對應的網絡卡地址如下:

br-49d34a6504d1 Link encap:乙太網  硬體地址 02:42:bc:ba:62:17  
          inet 地址:172.18.0.1  廣播:0.0.0.0  掩碼:255.255.0.0
          inet6 地址: fe80::42:bcff:feba:6217/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  躍點數:1
          接收資料包:1400 錯誤:0 丟棄:0 過載:0 幀數:0
          傳送資料包:1558 錯誤:0 丟棄:0 過載:0 載波:0
          碰撞:0 傳送佇列長度:0 
          接收位元組:79757 (79.7 KB)  傳送位元組:3650465 (3.6 MB)

注:可以建立多個網路,每個網路IP範圍均不相同。
然後,執行ubuntu映象:

docker run -it --rm --network mynet --network-alias ubuntu1  ubuntu bash

其中,--network mynet表示使用mynet網路,--network-alias ubuntu1表示該容器執行時,使用的網路別名為ubuntu1。(網路別名的作用類似hostname,不管容器IP如何變化,都可以使用同一個別名。)
接著,在同一臺電腦啟動另一個終端,啟動ubuntu映象:

docker run -it --rm --network mynet --network-alias ubuntu2 ubuntu bash

命令形式同上。只是將網路別名改為ubuntu2。
在ubuntu容器中使用ifconfig檢視該容器的IP地址,如下:

root@74f4089ce79c:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:12:00:02  
          inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1575 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1405 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:3652734 (3.6 MB)  TX bytes:99679 (99.6 KB)

再ping另一個容器ubuntu2,結果可以ping通。

[email protected]74f4089ce79c:/# ping ubuntu2
PING jenkins (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: icmp_seq=0 ttl=64 time=0.142 ms
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.131 ms

同樣地,在ubuntu2容器中ping另一個容器ubuntu,也可以ping通。

[email protected]927fe3bab506:/# ping ubuntu 
PING ubuntu (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.122 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.113 ms

推薦使用這個方式。
預設網路中的link是靜態的,不允許連結容器重啟,而自定義網路下的link是動態的,支援連結容器重啟(以及IP變化)
因此,使用–link時連結的容器,在預設網路中必須提前建立好,而自定義網路下不必預先建好。使用網路別名後,不管容器ip地址如何變化,都可以根據別名進行連線。

docker網路相關命令

在主機上建立一個網路,命令如下:

docker network create mynet

檢視自定義bridge網路命令如下:

docker network inspect mynet

移除網路要求網路中所有的容器關閉或斷開與此網路的連線時,才能夠使用移除命令:

docker network disconnet mynet 容器ID

再移除網路

docker network rm mynet