如何通过“主机名”在Docker容器之间进行通信


90

我计划将单机服务器拆分为许多小的docker容器,但还没有找到“容器间通信”的好解决方案。这是我的目标方案:

目标方案

我知道如何将容器链接在一起,以及如何公开端口,但是这些解决方案都不令我满意。

有什么解决方案可以像传统服务器网络中那样通过主机名(容器名称)在容器之间进行通信?


我最近写的文档完全符合您的需求。它基本上记录了如何安装多个容器(每个过程一个)并使其集成。“容器间通信”是游戏的一部分
xuhdev 2015年

我只是找到了Tumtum博客在Docker官方文档中偶然发现了这一段。我不知道我是否一直都错过本段,或者我是否一直在错过该段,但这正是我所需要的:)
Patrick Gotthard 2015年

docker 1.10已经发布,并且docker connect很棒(github.com/docker/docker/blob/…)。请参阅下面我编辑的答案
VonC

2
我认为您应该尝试docker-compose。效果很好。
Suhas Chikkanna

Answers:


27

编辑:在Docker 1.9之后,docker network命令(请参见下面的 https://stackoverflow.com/a/35184695/977939)是实现此目的的推荐方法。


我的解决方案是在主机上设置dnsmasq,以使DNS记录自动更新:“ A”记录具有容器的名称,并自动指向容器的IP地址(每10秒)。该自动更新脚本被粘贴在这里:

#!/bin/bash

# 10 seconds interval time by default
INTERVAL=${INTERVAL:-10}

# dnsmasq config directory
DNSMASQ_CONFIG=${DNSMASQ_CONFIG:-.}

# commands used in this script
DOCKER=${DOCKER:-docker}
SLEEP=${SLEEP:-sleep}
TAIL=${TAIL:-tail}

declare -A service_map

while true
do
    changed=false
    while read line
    do
        name=${line##* }
        ip=$(${DOCKER} inspect --format '{{.NetworkSettings.IPAddress}}' $name)
        if [ -z ${service_map[$name]} ] || [ ${service_map[$name]} != $ip ] # IP addr changed
        then
            service_map[$name]=$ip
            # write to file
            echo $name has a new IP Address $ip >&2
            echo "host-record=$name,$ip"  > "${DNSMASQ_CONFIG}/docker-$name"
            changed=true
        fi
    done < <(${DOCKER} ps | ${TAIL} -n +2)

    # a change of IP address occured, restart dnsmasq
    if [ $changed = true ]
    then
        systemctl restart dnsmasq
    fi

    ${SLEEP} $INTERVAL
done

确保您的dnsmasq服务在上可用docker0。然后,启动您的容器--dns HOST_ADDRESS以使用此小型dns服务。

参考:http : //docs.blowb.org/setup-host/dnsmasq.html


这看起来很有趣,比我的--link答案更具弹性。+1
VonC

@VonC似乎新的libnetwork可能会替代此替代方法。让我们看看。
xuhdev 2015年

@xuhdev我在docs.blowb.org/setup-host/dnsmasq.html中设置了dnsmasq 。但是我在从Docker容器中使用挖掘时遇到问题,它超时。但是对主机docker0接口ip执行ping操作。还使用来自docker主机的相同docker0 ip进行挖掘。你有什么建议吗?
Satheesh

1
@Satheesh也许是您的防火墙设置阻止了您的容器从主机查询DNS?
xuhdev

@xuhdev,谢谢,这是导致主机出现问题的原因。一旦弯下了firewalld,我的容器就会与主机上的dnsmasq通信
Satheesh

205

借助新的联网功能,您可以按容器的名称连接到容器,因此,如果创建新网络,则连接到该网络的任何容器都可以通过其名称访问其他容器。例:

1)创建新网络

$ docker network create <network-name>       

2)将容器连接到网络

$ docker run --net=<network-name> ...

要么

$ docker network connect <network-name> <container-name>

3)按名称平容器

docker exec -ti <container-name-A> ping <container-name-B> 

64 bytes from c1 (172.18.0.4): icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from c1 (172.18.0.4): icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from c1 (172.18.0.4): icmp_seq=3 ttl=64 time=0.074 ms
64 bytes from c1 (172.18.0.4): icmp_seq=4 ttl=64 time=0.074 ms

请参阅文档的部分;

注意:与旧版不同links,新网络将不会创建环境变量,也不会与其他容器共享环境变量。

此功能当前不支持别名


4
效果很好。为什么默认网络默认情况下不启用此功能?
斯特凡

不太明显的部分是,您需要重新启动在其他容器中运行的应用程序。那么,容器A如何才能使在容器B中运行的应用重新启动?显然,似乎需要某种通信总线。我的首要任务是使用Redis进行信号传输和容器间通信。.因此,所有容器都订阅了redis香奈儿,并且他们将在那里谈论... docker-compose中已发布端口的变化如何? .yml文件需要完整docker-compose down,up,restart
eigenfield '18

这正是我整天一直在寻找的东西!不知道您可以通过容器名称/ id引用网络节点。谢谢!
elliotwesoff

1
@Stéphane bridge由于向后兼容,它在默认网络中被禁用,但是是的,我同意,默认情况下应该启用它!
helmesjo

15

这应该是什么--link是对的,至少主机名部分。
使用docker 1.10和PR 19242,将是:

docker network create --net-alias=[]: Add network-scoped alias for the container

(请参阅下面的最后一节)

那就是更新/etc/hosts文件详细信息

除了环境变量,Docker还为/etc/hosts文件添加了源容器的主机条目。

例如,启动LDAP服务器:

docker run -t  --name openldap -d -p 389:389 larrycai/openldap

并定义一个图像以测试该LDAP服务器:

FROM ubuntu
RUN apt-get -y install ldap-utils
RUN touch /root/.bash_aliases
RUN echo "alias lds='ldapsearch -H ldap://internalopenldap -LL -b
ou=Users,dc=openstack,dc=org -D cn=admin,dc=openstack,dc=org -w
password'" > /root/.bash_aliases
ENTRYPOINT bash

您可以使用--link在测试映像中将' openldap'容器显示为' internalopenldap':

 docker run -it --rm --name ldp --link openldap:internalopenldap ldaptest

然后,如果键入“ lds”,则该别名将起作用:

ldapsearch -H ldap://internalopenldap ...

那将使人们返回。internalopenldapldaptest图像正确达到了含义。


当然,docker 1.7将添加libnetwork,它提供了用于连接容器的本地Go实现。请参阅博客文章
它通过容器网络模型(CNM)引入了更完整的体系结构

https://blog.docker.com/media/2015/04/cnm-model.jpg

这将使用新的“ network”命令更新Docker CLI,并记录如何使用“ -net”标志将容器分配给网络。


码头工人1.10有一个新的部分网络范围的别名,现在正式记录在network connect

链接提供了位于容器内的私有名称解析,而网络范围的别名为特定网络范围内的任何其他容器提供了一种由备用名称发现容器的方式。
与服务的使用者定义的链接别名不同,网络范围的别名是由向网络提供服务的容器定义的。

继续上面的示例,isolated_nw使用网络别名在其中创建另一个容器。

$ docker run --net=isolated_nw -itd --name=container6 -alias app busybox
8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17

--alias=[]         

为容器添加网络范围的别名

您可以使用--linkoption链接另一个具有首选别名的容器

您可以暂停,重新启动和停止连接到网络的容器。暂停的容器保持连接状态,可以通过网络检查来发现。停止容器后,直到重新启动它,它才会出现在网络上。

如果指定,重新启动已停止的容器时,将重新应用该容器的IP地址。如果IP地址不再可用,则容器无法启动。

保证IP地址可用的一种方法是--ip-range在创建网络时指定一个,并从该范围之外选择静态IP地址。这样可以确保当该容器不在网络上时,不会将IP地址提供给另一个容器。

$ docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 multi-host-network

$ docker network connect --ip 172.20.128.2 multi-host-network container2
$ docker network connect --link container1:c1 multi-host-network container2

3
--link的问题是,如果不重新启动链接的容器,也无法重新启动容器。当您查看我的图形时,重新启动MySQL容器将导致其他容器重新启动。
Patrick Gotthard

3

编辑:不再是前沿:http//blog.docker.com/2016/02/docker-1-10/

原始答案
我整夜都在与之抗争。如果您不担心前沿技术,则最新版本的Docker引擎Docker都将实现libnetwork。

使用正确的配置文件(需要在版本2中放置),您将创建可以全部看到的服务。而且,好处是,您也可以使用docker-compose扩展它们(您可以扩展任何您想要的不绑定主机端口的服务)

这是一个示例文件

version: "2"
services:
  router:
    build: services/router/
    ports:
      - "8080:8080"
  auth:
    build: services/auth/
  todo:
    build: services/todo/
  data:
    build: services/data/

以及此新版本的撰写文件的参考:https : //github.com/docker/compose/blob/1.6.0-rc1/docs/networking.md


1

据我所知,仅使用Docker是不可能的。您需要一些DNS才能将容器ip:s映射到主机名。

如果您想开箱即用的解决方案。一种解决方案是使用例如Kontena。它附带了Weave的网络覆盖技术,该技术用于为每个服务创建虚拟专用局域网,并且每个服务都可以通过service_name.kontena.local-address

这是Wordpress应用程序的YAML文件的简单示例,其中Wordpress服务使用wordpress-mysql.kontena.local地址连接到MySQL服务器:

wordpress:                                                                         
  image: wordpress:4.1                                                             
  stateful: true                                                                   
  ports:                                                                           
    - 80:80                                                                      
  links:                                                                           
    - mysql:wordpress-mysql                                                        
  environment:                                                                     
    - WORDPRESS_DB_HOST=wordpress-mysql.kontena.local                              
    - WORDPRESS_DB_PASSWORD=secret                                                 
mysql:                                                                             
  image: mariadb:5.5                                                               
  stateful: true                                                                   
  environment:                                                                     
    - MYSQL_ROOT_PASSWORD=secret
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.