Docker Swarm 主机无法解析其他节点上的主机

Docker Swarm host cannot resolve hosts on other nodes

我正在学习这个非常优秀的教程:https://github.com/binblee/springcloud-swarm

当我将堆栈部署到包含单个节点(仅管理器节点)的 Docker 群时,它运行良好。

docker stack deploy -c all-in-one.yml springcloud-demo

我有四个docker容器,其中一个是Eureka服务发现,其他三个容器都注册成功。

问题是当我添加一个worker节点到swarm时,两个容器会部署到worker,另外两个容器到manager,部署到worker节点的服务找不到Eureka server。

java.net.UnknownHostException: eureka: Name does not resolve

这是我的撰写文件:

version: '3'
services:
  eureka:
    image: demo-eurekaserver
    ports:
      - "8761:8761"

  web:
    image: demo-web
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka

  zuul:
    image: demo-zuul
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka
    ports:
      - "8762:8762"

  bookservice:
    image: demo-bookservice
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka

此外,我只能在部署到的主机上访问 Eureka Service Discovery 服务器。

我认为使用 "docker stack deploy" 会自动创建一个覆盖网络,其中所有暴露的端口都将路由到相应服务所在的主机 运行:

来自 https://docs.docker.com/engine/swarm/ingress/ :

All nodes participate in an ingress routing mesh. The routing mesh enables each node in the swarm to accept connections on published ports for any service running in the swarm, even if there’s no task running on the node.

这是 docker 服务 ls:

的输出
manager:~/springcloud-swarm/compose$ docker service ls

ID                  NAME                           MODE                REPLICAS            IMAGE                                                  PORTS
rirdysi0j4vk        springcloud-demo_bookservice   replicated          1/1                 demo-bookservice:latest
936ewzxwg82l        springcloud-demo_eureka        replicated          1/1                 demo-eurekaserver:latest   *:8761->8761/tcp
lb1p8nwshnvz        springcloud-demo_web           replicated          1/1                 demo-web:latest
0s52zecjk05q        springcloud-demo_zuul          replicated          1/1                 demo-zuul:latest           *:8762->8762/tcp

and of docker stack ps springcloud-demo:

manager:$ docker stack ps springcloud-demo
ID                  NAME                             IMAGE                      NODE            DESIRED STATE       CURRENT STATE        
o8aed04qcysy        springcloud-demo_web.1           demo-web:latest            workernode      Running             Running 2 minutes ago
yzwmx3l01b94        springcloud-demo_eureka.1        demo-eurekaserver:latest   managernode     Running             Running 2 minutes ago
rwe9y6uj3c73        springcloud-demo_bookservice.1   demo-bookservice:latest    workernode      Running             Running 2 minutes ago
iy5e237ca29o        springcloud-demo_zuul.1          demo-zuul:latest           managernode     Running             Running 2 minutes ago

更新:

我成功添加了另一台主机,但现在无法添加第三台。我尝试了几次,遵循相同的 steps,(安装 docker,打开必要的端口,加入 swarm)——但是节点找不到具有容器主机名的 Eureka 服务器)。

更新 2:

在测试端口是否打开时,我检查了防火墙配置:

workernode:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
8080                       ALLOW       Anywhere
4789                       ALLOW       Anywhere
7946                       ALLOW       Anywhere
2377                       ALLOW       Anywhere
8762                       ALLOW       Anywhere
8761                       ALLOW       Anywhere
22                         ALLOW       Anywhere

但是 - 当我尝试从管理器节点访问工作节点上的端口 2377 时,我不能:

managernode:~$ telnet xx.xx.xx.xx 2377

Trying xx.xx.xx.xx...
telnet: Unable to connect to remote host: Connection refused

我在亚马逊 AWS 上遇到了同样的问题。

我的问题出在 docker 网络入口。我在我的主机和 VPC 中解决了这个开放端口。

https://docs.docker.com/network/overlay/#customize-the-docker_gwbridge-interface

You need the following ports open to traffic to and from each Docker host participating on an overlay network:

TCP port 2377 for cluster management communications

TCP and UDP port 7946 for communication among nodes

UDP port 4789 for overlay network traffic

您需要为服务创建网络,如下所示:

version: '3'
services:
  eureka:
    image: demo-eurekaserver
    networks:
      - main
    ports:
      - "8761:8761"

  web:
    image: demo-web
    networks:
      - main
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka

  zuul:
    image: demo-zuul
    networks:
      - main
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka
    ports:
      - "8762:8762"

  bookservice:
    image: demo-bookservice
    networks:
      - main
    environment:
      - EUREKA_SERVER_ADDRESS=http://eureka:8761/eureka

networks:
  main:
    driver: overlay
    attachable: true

attachable: true 是为了让您可以从另一个撰写文件连接到此网络(如果不是这种情况,您可以将其删除)

我终于找到了答案。 问题是我在添加防火墙例外后没有重新启动主机。

我将撰写文件的版本更新为“3.3”,因为根据文档,"endpoint_mode: dnsrr" 仅适用于 3.3 版。

有了这个改变,我就可以让它工作了。

感谢大家花时间查看我的问题并尝试解决它。​​

让我们把解决方案分解成几个部分。每个部分都试图让您了解解决方案并且相互关联。

Docker容器网络

每当我们在不指定网络的情况下创建容器时,docker 都会将其附加到默认桥接网络。 According to this,. Service discovery is unavailable in the default network. Hene in order to maker service discovery work properly we are supposed to create a user-defined network as it provides isolation, DNS resolution and many more features. 当我们使用 docker run 命令时,所有这些都适用。

当docker-compose用于运行一个容器并且没有指定网络时,它creates its own bridge network.具有用户定义网络的所有属性。

默认情况下这些桥接网络不可附加,但它们允许本地计算机中的 docker 个容器连接到它们。

Docker群网络

Docker swarm and swarm mode routing mesh 中,每当我们在不指定外部网络的情况下向其部署服务时,它都会连接到入口网络。

当您指定外部覆盖网络时,您会注意到创建的覆盖网络将仅对管理器可用,而不在工作节点中可用,除非创建服务并将其复制到它。默认情况下,这些也是不可附加的,并且不允许 swarm 服务之外的其他容器连接到它们。因此,在将容器连接到 swarm 之外的网络之前,您不需要将网络声明为可附加的。

Docker群

由于没有pre defined/official limit on no of worker/manager nodes,您应该可以从第三个节点连接。一种可能性是该节点可能作为工作节点连接,但如果覆盖网络不可附加,您可能会尝试在该节点中部署一个容器,该容器受工作节点限制。

此外,您不能直接在工作节点中部署服务。所有服务都部署在管理器节点中,它负责根据提供的配置和模式复制和扩展服务。

防火墙

Getting started with swarm mode

所述
  • TCP port 2377 for cluster management communications
  • TCP and UDP port 7946 for communication among nodes
  • UDP port 4789 for overlay network traffic
  • ip protocol 50 (ESP) for encrypted overlay network

这些端口应列入节点间通信的白名单。进行更改后,大多数防火墙都需要重新加载。这可以通过将重新加载选项传递给防火墙来完成,它在 Linux 发行版之间有所不同。 ufw不需要重新加载但是needs commit if rules are added in file.

在防火墙中需要遵循的额外步骤

除了将上述端口列入白名单。您可能需要将 docker0,docker_gw_bridge,br-123456 网络掩码为 16 的 IP 地址列入白名单。否则服务发现将无法在同一台主机上运行。即,如果您尝试连接到 192.168.0.12 中的 eureka,其中 eureka 服务位于同一 192.168.0.12 它不会解析,因为防火墙会阻止流量。 Refer this (NO ROUTE TO HOST network request from container to host-ip:port published from other container)

Java

有时 Java 工作起来很奇怪,以至于它会抛出 java.net.MalformedURLException 和类似的异常。我也有我的 of such case with 。这里 ping 正确解析,但 Java rmi 抛出错误。因此,您可以在连接到用户定义的网络时定义自己的自定义别名。

Docker 服务发现

默认情况下,您可以使用容器名称解析服务。除此之外,您还可以将服务解析为 <container_name>.<network_name>。当然,您也可以定义别名。甚至您也可以将其解析为 <alias_name>.<network_name>.

解决方案

所以你应该在加入集群后创建一个用户定义的覆盖网络,然后部署服务。在服务中,您应该 mention the external network as defined here 同时在防火墙中进行更改。

如果您想允许外部容器连接到网络,您应该使网络可附加。

因为您没有提供足够的关于第三台服务器的详细信息。我假设您正在尝试在那里部署一个容器,该容器被 docker 覆盖网络拒绝,因为该网络不可连接。