如何从不同的主机外部访问运行在Docker容器(overlay)中的服务?

3
我有一个运行在overlay网络上的Docker容器。我的要求是从不同的主机外部访问在该容器内运行的服务。该服务绑定了容器的内部IP地址,因此在主机上进行端口绑定不是可行的解决方案。
实际情况如下: 容器内运行的服务是配置为使用yarn客户端的spark driver。Spark driver绑定到容器的内部IP(10.x.x.x)。当spark driver与在不同集群上运行的hadoop yarn通信时,应用程序主管在yarn上会尝试返回到驱动程序的容器内部IP,但由于明显的原因无法连接到内部IP上的驱动程序。
请告诉我是否有一种方法可以实现从应用程序主管(yarn)成功通信到spark driver(docker容器)。
Swarm版本:1.2.5

docker info:

Containers: 3
 Running: 2
 Paused: 0
 Stopped: 1
Images: 42
Server Version: swarm/1.2.5
Role: primary
Strategy: spread
Filters: health, port, containerslots, dependency, affinity, constraint
Nodes: 1
 ip-172-30-0-175: 172.30.0.175:2375
  └ ID: YQ4O:WGSA:TGQL:3U5F:ONL6:YTJ2:TCZJ:UJBN:T5XA:LSGL:BNGA:UGZW
  └ Status: Healthy
  └ Containers: 3 (2 Running, 0 Paused, 1 Stopped)
  └ Reserved CPUs: 0 / 16
  └ Reserved Memory: 0 B / 66.06 GiB
  └ Labels: kernelversion=3.13.0-91-generic, operatingsystem=Ubuntu 14.04.4 LTS, storagedriver=aufs
  └ UpdatedAt: 2016-09-10T05:01:32Z
  └ ServerVersion: 1.12.1
Plugins:
 Volume: 
 Network: 
Swarm: 
 NodeID: 
 Is Manager: false
 Node Address: 
Security Options:
Kernel Version: 3.13.0-91-generic
Operating System: linux
Architecture: amd64
CPUs: 16
Total Memory: 66.06 GiB
Name: 945b4af662a4
Docker Root Dir: 
Debug Mode (client): false
Debug Mode (server): false

运行容器的命令:我使用docker-compose来运行它:

zeppelin:
    container_name: "${DATARPM_ZEPPELIN_CONTAINER_NAME}"
    image: "${DOCKER_REGISTRY}/zeppelin:${DATARPM_ZEPPELIN_TAG}"
    network_mode: "${CONTAINER_NETWORK}"
    mem_limit: "${DATARPM_ZEPPELIN_MEM_LIMIT}"
    env_file: datarpm-etc.env
    links:
      - "xyz"
      - "abc"
    environment:
      - "VOL1=${VOL1}"
      - "constraint:node==${DATARPM_ZEPPELIN_HOST}"
    volumes:
      - "${VOL1}:${VOL1}:rw"
    entrypoint: ["/bin/bash", "-c", '<some command here>']


我不知道你使用的 Swarm 版本是什么,请发布你的 docker info。同时请发布你用来创建容器和服务的代码。 - Bernard
depends_on 可用于依赖项。在网络版本2配置中,links 仍然有效,但它们所做的不同于以前。 - Matt
@Matt 我应该写一下,链接现在已经过时了。除非用来定义别名(从我所见的情况来看,很少有人这么做),否则它们就没有什么作用了。depends_on可以用于依赖项,但请记住,它们非常有限。它们只检查容器是否正在运行,而不是容器内部的应用程序是否准备就绪。 - Bernard
@SantoshKumar 在深入探讨之前,为什么不使用“Swarm模式”而不是传统的Swarm呢? - Bernard
@Alkaline,我计划开始使用“Swarm模式”,但我怀疑它是否能解决我的问题。 - Santosh Kumar
显示剩余2条评论
1个回答

1

看起来yarn和spark需要直接在网络上互相通信。如果您能将它们放在同一个覆盖网络上,一切都能直接通信,否则...

覆盖网络

通过docker_gwbridge,可以将数据直接路由到Docker节点上的覆盖网络中,所有覆盖容器都连接到该网桥,但是,这只适用于运行容器的Docker节点。

因此,在2个节点上运行2个容器非Swarm模式覆盖网络10.0.9.0/24...

我可以ping demo0上的本地容器,但无法ping远程容器demo1。

docker@mhs-demo0:~$ sudo ip ro add 10.0.9.0/24 dev docker_gwbridge
docker@mhs-demo0:~$ ping -c 1 10.0.9.2
PING 10.0.9.2 (10.0.9.2): 56 data bytes
64 bytes from 10.0.9.2: seq=0 ttl=64 time=0.086 ms
docker@mhs-demo0:~$  ping -c 1 10.0.9.3
PING 10.0.9.3 (10.0.9.3): 56 data bytes
^C
--- 10.0.9.3 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss

在另一台主机上,容器被反转,但仍然可以访问本地容器。
docker@mhs-demo1:~$ sudo ip ro add 10.0.9.0/24 dev docker_gwbridge
docker@mhs-demo1:~$ ping 10.0.9.2
PING 10.0.9.2 (10.0.9.2): 56 data bytes
^C
--- 10.0.9.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
docker@mhs-demo1:~$  ping 10.0.9.3
PING 10.0.9.3 (10.0.9.3): 56 data bytes
64 bytes from 10.0.9.3: seq=0 ttl=64 time=0.094 ms
64 bytes from 10.0.9.3: seq=1 ttl=64 time=0.068 ms

所以最大的问题是网络需要知道容器运行的位置并相应地路由数据包。如果网络能够实现这样的路由,你可能根本不需要覆盖网络。另一个可能性是在每个Docker节点上使用普通的桥接网络和可路由的IP地址。因此,每个桥接都分配了一个IP范围,你的网络知道并可以从任何地方路由到它。
192.168.9.0/24        10.10.2.0/24
Yarn                  DockerC

             router

10.10.0.0/24          10.10.1.0/24     
DockerA               DockerB          

每个节点都会连接到一个网络。

DockerA:$ docker network create --subnet 10.10.0.0/24 sparknet
DockerB:$ docker network create --subnet 10.10.1.0/24 sparknet
DockerC:$ docker network create --subnet 192.168.2.0/24 sparknet

然后路由器通过DockerA等配置10.10.0.0/24的路由。

这类似于Kubernetes进行网络配置的方式

Weave Net

Weave类似于覆盖层,它创建一个虚拟网络,通过UDP传输数据。它是一个更通用的网络解决方案,可以与主机网络集成


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接