Docker的组合功能:如何用external_links选项连接组合文件外部定义的容器

原文出处 Docker Compose: Link containers outside compose file using external_links

容器连接是Docker平台上的基本概念之一。容器连接后,即使不向Docker主机提供需要的程序端口,也可以访问容器提供的服务。这个概念也体现在了Docker组合(Compose)功能中。但是,如果某个要连接的容器定义在别的组合文件(docker-compose.yml)里,那情况就略微复杂了些。

不用组合功能时,连接容器很简单,只要用 –link参数就行了:

docker run --name test1 something
docker run --name test2 --link test1:test1 something

这个例子里,先启动一个叫test1的容器,然后再启动test2容器。test1容器和test2容器连接起来,这样在test1容器中只要用test1的名字test1就能访问test2了。

用组合功能时,如果两个服务定义在同一个组合文件里,那也可以那样连接:

version: '2'
services:
  test2:
    image: something
    depends_on:
      - test1
    links:
      - test1
  test1:
    image: something

效果和docker run命令完全一样。

但如果容器定义��%A ��������{E C的组合文件里呢?如何把它们连接起来?

我就碰到这么一个情况:有好几个组合文件,每个域用一个文件,每个文件都定义了一些紧密相关的服务,比如博客、后台服务和数据库。然后我还有一个前端的网站服务器,这样就可以通过英特网来访问我的网站,并把收到的请求代理到组合文件中定义的各种服务里去处理。

Docker平台的组合功能提供了一个叫“外部链接”(“external_links”)的设置选项,能用来接连那些在不同组合文件中定义的容器:

version: '2'
services:
  test2:
    image: something
    external_links:
      - domainA_test1_1

这里,“test1”服务在组合“domainA”中定义。只要这个服务是第一个运行且是当前唯一一个运行的服务,Docker的组合功能会自动在容器名字后面加上“_1”。

然而,从这里开始就有点复杂了。原因就是Docker在默认状态下会为每个docker组合建立一个独立的网络。同一个组合中定义的容器都连接到同一个网络,网络之间不能相互访问,所以一定要想点办法。

方法1:让需要连接的容器也加入外部网络

这种方法要求在定义连接的组合文件里加两个部分:在test2服务定义里加入外部网络“domainA_default”,使这个容器成为该网络的一部分;在组合文件本身的网络定义中再加入“domainA_default”网络,并定义为外部。

version: '2'
services:
  test2:
    image: something
    external_links:
      - domainA_test1_1
    networks:
      - default
      - domainA_default
networks:
  domainA_default
    external: true

可以看到,“domainA_default”是docker自动为组合“domainA”创建的外部网络,我用了两个额外的部分把test2服务连接到这个默认网络上去。

在test2里,可以用默认的DNS名“domainA_test1_1”来访问test1容器。

我们可以用这个命令查看所有的docker网络:

docker network ls

方法2:为所有要互联的容器设定桥接连网模式(bridge networking mode)

第一个方法能让私有网络互联。但如果需要从已互联的容器内部向外部发起网络连接,就可能会遇到问题。

因此,还有另一种方法,就是为所有想要互联的容器开启桥接连网模式:

version: '2'
services:
  test2:
    image: something
    network_mode: bridge
    external_links:
      - domainA_test1_1
version: '2'
services:
  test1:
    image: something
    network_mode: bridge

哪种方法好取决于具体情况。个人来说我比较喜欢第一种方法,因为它用的是私有网络,而不会把容器桥接到主机的网络上去。