【发布时间】:2020-01-29 10:36:21
【问题描述】:
如果我有一个具有多个节点的 Docker Swarm,连接到用户定义的覆盖网络,并且服务 A 尝试与服务 B 通信,其中服务 B 有多个副本,哪个副本会收到消息?我意识到路由网格是一个入口,但在这种情况下也需要发生类似的事情,对吧?
【问题讨论】:
标签: docker routing docker-swarm docker-networking
如果我有一个具有多个节点的 Docker Swarm,连接到用户定义的覆盖网络,并且服务 A 尝试与服务 B 通信,其中服务 B 有多个副本,哪个副本会收到消息?我意识到路由网格是一个入口,但在这种情况下也需要发生类似的事情,对吧?
【问题讨论】:
标签: docker routing docker-swarm docker-networking
默认情况下,docker 使用内核中的ipvs 实现的虚拟 IP (VIP) 配置每个服务。这会针对每个不同的网络连接在服务的每个副本之间执行循环负载平衡(持久网络连接将在该 TCP 连接的生命周期内保持连接到同一个副本)。
当被转发到的 IP 地址在另一个节点上时,它使用覆盖网络(由内核中的 vxlan 实现)将这些数据包发送到其他节点。如果网络上的任何东西阻塞了覆盖网络端口,你会看到让它工作的问题。 Docker 在他们的文档中有prerequisite ports:
- 用于集群管理通信的 TCP 端口 2377
- 用于节点间通信的 TCP 和 UDP 端口 7946
- UDP 端口 4789 用于覆盖网络流量
我经常在每个节点上使用 tcpdump 调试连接问题,以查看从一个节点发送的数据包是否在目的地收到。如果需要,可以在初始化 swarm 集群时使用 docker swarm init --data-path-port 标志更改覆盖端口。
我更喜欢在大多数情况下使用默认覆盖网络,因为它消除了一类 DNS 缓存问题。如果您使用 DNS 循环,swarm 集群中的每个容器都可以缓存您的服务副本的 DNS 结果,并与该服务使用的旧 IP 地址通信,只要 DNS 缓存的结果保留在该容器的应用程序中。在您等待应用程序刷新其选定容器的 DNS 结果时,这可能会导致滚动更新期间出现大量停机。虽然我过去遇到过 ipvs 的问题,但我在最近版本的 docker 中没有遇到过那些具有较新内核的问题,而且现在许多 kubernetes 网络提供商都使用相同的内核模块,从而带来了更多的测试和稳定性。
如果您想获取服务副本的单独 IP 地址,或使用 DNS RR,您可以一次性执行此操作,而无需禁用服务 VIP。相反,如果您要查询 web 以获取 Web 服务的 VIP,则可以查询 tasks.web 以获取该服务的所有副本的 DNS RR(将 web 替换为您的服务名称)。只有当我的应用程序需要对每个副本运行命令时,我才这样做,并且我可以看到它对粘性会话有何用处。
至于这与入口网络和服务网格的关系,入口网络配置为将特定端口路由到集群中每个节点上入口网络上的该 VIP。当您在网络上运行 docker network inspect -v ... 时,您将看到服务连接到的每个覆盖网络的 VIP,包括入口网络(如果您已发布端口)。
我考虑禁用入口网络的唯一情况是,如果我有一个全局服务、一个单节点集群或一个在可预测的节点列表上运行的服务,并且我想避免服务网格添加的额外网络跃点。在这些情况下,我以“主机”模式发布端口(有关发布端口,请参阅long syntax)。这将阻止您在一个节点上运行多个副本,但在我的大多数用例中,这适用于多个副本没有意义的有状态应用程序。
【讨论】:
基本上有两种端点模式:
dnsrr => 服务 DNS 解析容器 IPdefault => 服务 DNS 解析 Swarm 入口路由器Swarm 路由器是一个纯粹的 ***** ,它有很多网络问题(超时,没有路由到主机,僵尸)。
dnsrr 将提供所有容器 IP,这很酷,但这可能会导致 DNS 缓存出现问题(logstash、Php AMQP 客户端...):
“服务 A 有 X 秒的 DNS 缓存,它可以与容器 B.1 通信。容器 B.1 崩溃,使用不同的 IP 重新生成 ==> 服务 A 仍然发送到以前的 IP” em>
如果容器有多个网络,也要小心。
【讨论】: