Docker Swarm模式下如何让多个服务监听同一个端口?

23
假设您的拓扑结构上有两个服务:
  1. API
  2. Web界面
两者都应运行在端口80上。
在Docker Swarm中,如果要从集群外部访问创建的服务,则需要将服务的端口暴露并映射到节点(外部端口)。但是,如果您将端口80映射到API服务,则不能为Web界面服务映射相同的端口,因为该端口已经被占用。
如何解决这个问题?
就我所知,目前没有支持这种情况的方法。即使您想要在大型Swarm集群中放置所有服务和应用程序,也不可能实现,因为这种行为。
我是否遗漏了什么?有没有可以解决此问题的模式?

对于这个问题感到困惑。无法将两个东西映射到同一个端口与 Docker 无关。它们将在容器内的端口80上运行,但您可以将它们映射到不同的外部端口。 - johnharris85
@JHarris 是的,我编辑了主要问题以指定外部端口。但这是一个问题,当您将API服务80端口映射到外部端口80后,它无法再次映射到Web界面服务。 - bitgandtter
正确,如果没有使用Docker,你如何解决这个问题? - johnharris85
3
没有使用Docker,我们可能会有一组在80端口运行API服务的云实例,这些实例可以在负载均衡器后面运行,也可以是像AWS ELB这样的云负载均衡器,还可以有另外一个云实例运行着Nginx。同时,对于一组Web界面服务也采用相同的设置,全部在80端口上运行。问题是如何使用Docker Swarm模式来实现这一目标? - bitgandtter
3个回答

7
你可以使用Docker Flow:Proxy作为易于配置的反向代理。
但是,我认为,正如其他评论者所指出的那样,Docker 1.12 swarm模式存在一个基本问题,即多个服务公开相同的端口(如80或8080)。
它归结为网格路由魔术 - 这是一个第4级的东西,基本上是TCP / IP - 换句话说,IP地址+端口。因此,当多个服务在(例如)端口8080上进行列举时,事情会变得混乱。网格路由器将很高兴地将流量传递到公开相同端口的任何服务。
您可以在swarm模式下使用覆盖网络将它们分离,但是当您必须将服务连接到代理(覆盖网络)时,问题就出现了 - 在这一点上,事情看起来会混淆(这就是我现在遇到困难的地方)。
我目前的解决方案是让需要向网络公开的服务使用与代理面向(覆盖)网络不同的唯一端口(它们不必发布到swarm!),然后实际上使用类似Docker Flow Proxy的东西来处理所需端口上的传入流量。

以下是一个快速示例,帮助您入门(基于this,仅供参考):

    docker network create --driver overlay proxy
    docker network create --driver overlay my-app
    # App1 exposed port 8081
    docker service create --network proxy --network my-app --name app1 myApp1DockerImage
    docker service create --name proxy \
    -p 80:80 \
    -p 443:443 \
    -p 8080:8080 \
    --network proxy \
    -e MODE=swarm \
    vfarcic/docker-flow-proxy
    #App2 exposes port 8080
    docker service create --network proxy --network my-app --name app2 myApp2DockerImage

然后,您需要按照它的文档配置reverseProxy。

注意:我现在看到有新的AUTO配置可用-我还没有尝试过。

如果一切正常,最终结果如下:

  • 代理侦听端口80、443(并且8080用于其配置调用,因此请勿将其开放给公共网络!)
  • 代理根据服务域服务路径将请求转发到适当的服务(我遇到了服务路径的问题)
  • 服务可以在隔离的覆盖网络上内部通信。
  • 服务不会不必要地向群集发布端口。

[编辑2016/10/20]

忽略关于代理附加到相同覆盖网络的相同暴露端口的问题的所有内容。

我撤销了整个设置,重新开始——现在一切都按预期工作:我可以通过Docker Flow Proxy使用不同的域名访问多个(不同的)端口80服务。
同时使用提到的自动配置——一切都像魔法般地运作。

来自 Docker Flow Proxy 仓库:“该项目需要被接手。我(@vfarcic)转向了 Kubernetes,不能再花时间在这个项目上了。同样,其他贡献者的参与度也下降了。” 有什么替代方案吗? - Yuki
喜欢它还是讨厌它 - k8s 赢了。目前我不知道任何替代方案(除了转移到 k8s)。 - demaniak

5
如果您需要向公众公开同时提供API和Web界面,则有两个选项。一是为服务使用不同的端口,另一个是通过HTTP服务器将它们暴露在同一端口下。
http://my-site.com       # Web interface
http://my-site.com:8080  # API

或者使用一个代理,监听80端口,并根据路径将请求转发到正确的服务:

http://my-site.com      # Web interface
http://my-site.com/api  # API

1

[ 四年后回顾此问题,因为它仍然在得到投票,而且自提问以来发生了很多变化 ]

在Swarm模式或Linux中,您不能有多个服务同时监听同一端口。但是,您可以在该端口上运行某种第7层代理,根据应用程序级数据将路由定向到正确的容器。最常见的例子是各种http反向代理。

特别是对于Swarm Mode,traefik似乎是最受欢迎的反向代理。但是,还有其他基于HAProxy和Nginx的解决方案。

使用反向代理时,在Swarm模式下,您的任何一个容器都不会发布端口。相反,您将配置反向代理,其端口发布在类似80和443的端口上。然后,它将通过共享的Docker网络将请求通信到您的容器。为使此功能正常工作,每个容器都需要能够根据请求中的某些内容(例如主机名、路径、cookie等)分离要传输给它的流量。


如果需要公开暴露,则使用不同的端口:

docker service create -p 80:80 --name web nginx

然后执行

docker service create -p 8080:80 --name api myapi

在第二个示例中,公共端口8080映射到容器端口80。当然,如果它们不需要公共端口暴露,则可以通过使用容器名称和容器端口,在同一网络上的容器之间查看服务。

curl http://api:80

会找到名为api的容器,并使用DNS发现在同一网络上连接到端口80。


嘿@BMitch,但是用例没有完成,因为API在端口8080上向互联网公开,而应该在端口80上。这就是我试图完成的用例。无论如何,如果您想要一个大的Swarm集群,并在其中运行多个不同的服务,并且其中几个服务需要向互联网公开端口80 - bitgandtter
我提供了Docker解决方案的描述。他们目前的实现没有提供任何其他选项,可以通过他们的服务发现机制公开暴露相同的端口给两个不同的服务。我能想到的解决方法是使用另一个工具,通过IP公开服务而不是端口,或者使用代理来解释请求并根据内容发送到API或Web服务器。 - BMitch
@bitgandtter,通过同一端口导出两个服务是没有意义的。负载均衡器只能通过检查HTTP头来将流量发送到正确的服务。这种方法可行,但肯定不是高效和简单的。在您的用例中,通常使用端口80/443进行Web部分,并使用其他端口(范围>= 30000)进行API。 - Bernard
1
我更多地考虑建立一个大型Swarm集群来运行多个应用程序。但我认为Swarm的目标更像是为单个应用程序提供集群支持。即使在单个应用程序中,您也可以有多个服务,这些服务可以并且应该使用相同的端口,例如公共API端口80和公共Web界面端口80。 - bitgandtter
你要寻找的模型,必须在特定端口上公开,这更像是 Kubernetes,其中服务通过 IP 而不是端口公开。如果必须使用相同的端口,则可以使用类似 nginx 的代理服务进行创建。如果您可以配置客户端使用不同的端口,则将每个服务公开到不同的 Swarm 端口(即使容器端口都是 80)是 Docker 设计的解决方案。 - BMitch

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