Docker Compose 容器鏈接

在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創建連接

這樣,test2test1便創建了連接,就能夠在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創建的連接並沒有區別。這只是一種最爲理想的狀況。測試


  1. 若是容器沒有定義在同一個docker-compose.yml文件中,應該如何連接它們呢?
  2. 又若是定義在docker-compose.yml文件中的容器須要與docker run xxx啓動的容器連接,須要如何處理?

針對這兩種典型的狀況,下面給出我我的測試可行的辦法:spa


方式一:讓須要連接的容器同屬一個外部網絡

咱們仍是使用nginx鏡像來模擬這樣的一個情景:假設咱們須要將兩個使用Docker Compose管理的nignx容器(test1test2)連接起來,使得test2可以訪問test1中提供的服務,這裏咱們以能ping通爲準。code

首先,咱們定義容器test1docker-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的話,那麼容器test2docker-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

不然的話,test2docker-compose.ymltest1的定義徹底一致,不須要額外多指定一個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,那麼nginx2doker-compose.yml定義爲:

1
2
3
4
5
6
version: "3"
services:
  nginx2:
    image: nginx
    container_name: nginx2
    network_mode: bridge

與其對應的,nginx1docker-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

以上也能充分證實這種方式是屬於單向聯通的。

在實際應用中根據本身的須要靈活的選擇這兩種連接方式,若是想偷懶的話,大可選擇第二種。不過我更推薦第一種,不難看出不管是聯通性仍是靈活性,較爲更改網絡模式的第二種都更爲友好。

相關文章
相關標籤/搜索