在Docker中,容器之間的連接是一種很常見的操做:它提供了訪問其中的某個容器的網絡服務而不須要將所需的端口暴露給Docker Host主機的功能。Docker Compose中對該特性的支持一樣是很方便的。然而,若是須要連接的容器沒有定義在同一個docker-compose.yml
中的時候,這個時候就稍微麻煩複雜了點。nginx
在不使用Docker Compose的時候,將兩個容器連接起來使用—link
參數,相對來講比較簡單,以nginx
鏡像爲例子:docker
1 2 |
docker run --rm --name test1 -d nginx #開啓一個實例test1 docker run --rm --name test2 --link test1 -d nginx #開啓一個實例test2並與test1創建連接 |
這樣,test2
與test1
便創建了連接,就能夠在test2
中使用訪問test1
中的服務了。網絡
若是使用Docker Compose,那麼這個事情就更簡單了,仍是以上面的nginx
鏡像爲例子,編輯docker-compose.yml
文件爲:app
1 2 3 4 5 6 7 8 9 10 |
version: "3" services: test2: image: nginx depends_on: - test1 links: - test1 test1: image: nginx |
最終效果與使用普通的Docker命令docker run xxxx
創建的連接並沒有區別。這只是一種最爲理想的狀況。測試
docker-compose.yml
文件中,應該如何連接它們呢?docker-compose.yml
文件中的容器須要與docker run xxx
啓動的容器連接,須要如何處理?針對這兩種典型的狀況,下面給出我我的測試可行的辦法:spa
咱們仍是使用nginx鏡像來模擬這樣的一個情景:假設咱們須要將兩個使用Docker Compose管理的nignx容器(test1
和test2
)連接起來,使得test2
可以訪問test1
中提供的服務,這裏咱們以能ping通爲準。code
首先,咱們定義容器test1
的docker-compose.yml
文件內容爲:get
1 2 3 4 5 6 7 8 9 10 11 |
version: "3" services: test2: image: nginx container_name: test1 networks: - default - app_net networks: app_net: external: true |
容器test2
內容與test1
基本同樣,只是多了一個external_links
,須要特別說明的是:最近發佈的Docker版本已經不須要使用external_links來連接容器,容器的DNS服務能夠正確的做出判斷,所以若是你你須要兼容較老版本的Docker的話,那麼容器test2
的docker-compose.yml
文件內容爲:it
1 2 3 4 5 6 7 8 9 10 11 12 13 |
version: "3" services: test2: image: nginx networks: - default - app_net external_links: - test1 container_name: test2 networks: app_net: external: true |
不然的話,test2
的docker-compose.yml
和test1
的定義徹底一致,不須要額外多指定一個external_links
。相關的問題請參見stackoverflow上的相關問題:docker-compose + external containerio
正如你看到的那樣,這裏兩個容器的定義裏都使用了同一個外部網絡app_net
,所以,咱們須要在啓動這兩個容器以前經過如下命令再建立外部網絡:
1 |
docker network create app_net |
以後,經過docker-compose up -d
命令啓動這兩個容器,而後執行docker exec -it test2 ping test1
,你將會看到以下的輸出:
1 2 3 4 5 6 7 8 |
docker exec -it test2 ping test1 PING test1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.091 ms 64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.146 ms 64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.150 ms 64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.145 ms 64 bytes from 172.18.0.2: icmp_seq=4 ttl=64 time=0.126 ms 64 bytes from 172.18.0.2: icmp_seq=5 ttl=64 time=0.147 ms |
證實這兩個容器是成功連接了,反過來在test1
中pingtest2
也是可以正常ping通的。
若是咱們經過docker run --rm --name test3 -d nginx
這種方式來先啓動了一個容器(test3
)而且沒有指定它所屬的外部網絡,而須要將其與test1
或者test2
連接的話,這個時候手動連接外部網絡便可:
1 |
docker network connect app_net test3 |
這樣,三個容器均可以相互訪問了。
經過更改你想要相互連接的容器的網絡模式爲bridge
,並指定須要連接的外部容器(external_links
)便可。與同屬外部網絡的容器能夠相互訪問的連接方式一不一樣,這種方式的訪問是單向的。
仍是以nginx容器鏡像爲例子,若是容器實例nginx1
須要訪問容器實例nginx2
,那麼nginx2
的doker-compose.yml
定義爲:
1 2 3 4 5 6 |
version: "3" services: nginx2: image: nginx container_name: nginx2 network_mode: bridge |
與其對應的,nginx1
的docker-compose.yml
定義爲:
1 2 3 4 5 6 7 8 |
version: "3" services: nginx1: image: nginx external_links: - nginx2 container_name: nginx1 network_mode: bridge |
須要特別說明的是,這裏的
external_links
是不能省略的,並且nginx1
的啓動必需要在nginx2
以後,不然可能會報找不到容器nginx2
的錯誤。
接着咱們使用ping來測試下連通性:
1 2 3 4 5 6 7 8 |
$ docker exec -it nginx1 ping nginx2 # nginx1 to nginx2 PING nginx2 (172.17.0.4): 56 data bytes 64 bytes from 172.17.0.4: icmp_seq=0 ttl=64 time=0.141 ms 64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.139 ms 64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.145 ms $ docker exec -it nginx2 ping nginx1 #nginx2 to nginx1 ping: unknown host |
以上也能充分證實這種方式是屬於單向聯通的。
在實際應用中根據本身的須要靈活的選擇這兩種連接方式,若是想偷懶的話,大可選擇第二種。不過我更推薦第一種,不難看出不管是聯通性仍是靈活性,較爲更改網絡模式的第二種都更爲友好。