Docker Compose:鏈接外部容器的幾種方式
在Docker中,容器之間的鏈接是一種很常見(jiàn)的操作:它提供了訪問(wèn)其中的某個(gè)容器的網(wǎng)絡(luò)服務(wù)而不需要將所需的端口暴露給Docker Host主機(jī)的功能。Docker Compose中對(duì)該特性的支持同樣是很方便的。然而,如果需要鏈接的容器沒(méi)有定義在同一個(gè) docker-compose.yml 中的時(shí)候,這個(gè)時(shí)候就稍微麻煩復(fù)雜了點(diǎn)。
在不使用Docker Compose的時(shí)候,將兩個(gè)容器鏈接起來(lái)使用 —link 參數(shù),相對(duì)來(lái)說(shuō)比較簡(jiǎn)單,以 nginx 鏡像為例子:
- docker run --rm --name test1 -d nginx #開(kāi)啟一個(gè)實(shí)例test1
- docker run --rm --name test2 --link test1 -d nginx #開(kāi)啟一個(gè)實(shí)例test2并與test1建立鏈接
這樣, test2 與 test1 便建立了鏈接,就可以在 test2 中使用訪問(wèn) test1 中的服務(wù)了。
如果使用Docker Compose,那么這個(gè)事情就更簡(jiǎn)單了,還是以上面的 nginx 鏡像為例子,編輯 docker-compose.yml 文件為:
- version: "3"
- services:
- test2:
- image: nginx
- depends_on:
- - test1
- links:
- - test1
- test1:
- image: nginx
最終效果與使用普通的Docker命令 docker run xxxx 建立的鏈接并無(wú)區(qū)別。這只是一種最為理想的情況。
- 如果容器沒(méi)有定義在同一個(gè) docker-compose.yml 文件中,應(yīng)該如何鏈接它們呢?
- 又如果定義在 docker-compose.yml 文件中的容器需要與 docker run xxx 啟動(dòng)的容器鏈接,需要如何處理?
針對(duì)這兩種典型的情況,下面給出我個(gè)人測(cè)試可行的辦法:
- 方式一:讓需要鏈接的容器同屬一個(gè)外部網(wǎng)絡(luò)
我們還是使用nginx鏡像來(lái)模擬這樣的一個(gè)情景:假設(shè)我們需要將兩個(gè)使用Docker Compose管理的nignx容器( test1 和 test2 )鏈接起來(lái),使得 test2 能夠訪問(wèn) test1 中提供的服務(wù),這里我們以能ping通為準(zhǔn)。
首先,我們定義容器 test1 的 docker-compose.yml 文件內(nèi)容為:
- version: "3"
- services:
- test2:
- image: nginx
- container_name: test1
- networks:
- - default
- - app_net
- networks:
- app_net:
- external: true
容器 test2 內(nèi)容與 test1 基本一樣,只是多了一個(gè) external_links ,需要特別說(shuō)明的是: 最近發(fā)布的Docker版本已經(jīng)不需要使用external_links來(lái)鏈接容器,容器的DNS服務(wù)可以正確的作出判斷 ,因此如果你你需要兼容較老版本的Docker的話,那么容器 test2 的 docker-compose.yml文件內(nèi)容為:
- 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 的定義完全一致,不需要額外多指定一個(gè) external_links 。相關(guān)的問(wèn)題請(qǐng)參見(jiàn)stackoverflow上的相關(guān)問(wèn)題: docker-compose + external container
正如你看到的那樣,這里兩個(gè)容器的定義里都使用了同一個(gè)外部網(wǎng)絡(luò) app_net ,因此,我們需要在啟動(dòng)這兩個(gè)容器之前通過(guò)以下命令再創(chuàng)建外部網(wǎng)絡(luò):
- docker network create app_net
之后,通過(guò) docker-compose up -d 命令啟動(dòng)這兩個(gè)容器,然后執(zhí)行 docker exec -it test2 ping test1 ,你將會(huì)看到如下的輸出:
- 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
證明這兩個(gè)容器是成功鏈接了,反過(guò)來(lái)在 test1 中ping test2 也是能夠正常ping通的。
如果我們通過(guò) docker run --rm --name test3 -d nginx 這種方式來(lái)先啟動(dòng)了一個(gè)容器( test3 )并且沒(méi)有指定它所屬的外部網(wǎng)絡(luò),而需要將其與 test1 或者 test2 鏈接的話,這個(gè)時(shí)候手動(dòng)鏈接外部網(wǎng)絡(luò)即可:
- docker network connect app_net test3
這樣,三個(gè)容器都可以相互訪問(wèn)了。
方式二:更改需要鏈接的容器的網(wǎng)絡(luò)模式
通過(guò)更改你想要相互鏈接的容器的網(wǎng)絡(luò)模式為 bridge ,并指定需要鏈接的外部容器( external_links )即可。與同屬外部網(wǎng)絡(luò)的容器可以相互訪問(wèn)的鏈接方式一不同,這種方式的訪問(wèn)是單向的。
還是以nginx容器鏡像為例子,如果容器實(shí)例 nginx1 需要訪問(wèn)容器實(shí)例 nginx2 ,那么 nginx2 的 doker-compose.yml 定義為:
- version: "3"
- services:
- nginx2:
- image: nginx
- container_name: nginx2
- network_mode: bridge
與其對(duì)應(yīng)的, nginx1 的 docker-compose.yml 定義為:
- version: "3"
- services:
- nginx1:
- image: nginx
- external_links:
- - nginx2
- container_name: nginx1
- network_mode: bridge
需要特別說(shuō)明的是,這里的 external_links 是不能省略的,而且 nginx1 的啟動(dòng)必須要在 nginx2 之后,否則可能會(huì)報(bào)找不到容器 nginx2 的錯(cuò)誤。
接著我們使用ping來(lái)測(cè)試下連通性:
- $ 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
以上也能充分證明這種方式是屬于單向聯(lián)通的。
在實(shí)際應(yīng)用中根據(jù)自己的需要靈活的選擇這兩種鏈接方式,如果想偷懶的話,大可選擇第二種。不過(guò)我更推薦***種,不難看出無(wú)論是聯(lián)通性還是靈活性,較為更改網(wǎng)絡(luò)模式的第二種都更為友好。


























