Swarm 负载均衡是否应该对其节点执行健康检查?

Should swarm loadbalancing perform healthchecks on its nodes?

swarm 文档中的 Load Balancing 部分没有说明内部负载均衡器是否也进行健康检查,以及是否删除不再是 运行 服务的节点(因为它被杀死或节点被重新启动)。

在以下情况下,我在 3 个节点中的每个节点上都有一个副本 3、1 个实例 运行 的服务。

经理:

[root@centosvm ~]# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS               NAMES
a593d485050a        ddewaele/springboot.crud.sample:latest   "sh -c 'java $JAVA_OP"   7 minutes ago       Up 7 minutes                            springbootcrudsample.1.5syc6j4c8i3bnerdqq4e1yelm

节点 1:

[root@node1 ~]# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS               NAMES
d3b3fbc0f2c5        ddewaele/springboot.crud.sample:latest   "sh -c 'java $JAVA_OP"   4 minutes ago       Up 4 minutes                            springbootcrudsample.3.7y1oyjyrifgkmxlr20oai5ppl

节点 2:

[root@node2 ~]# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS               NAMES
ebca8f24ec3a        ddewaele/springboot.crud.sample:latest   "sh -c 'java $JAVA_OP"   7 minutes ago       Up 7 minutes                            springbootcrudsample.2.4tqjad7od8ep047s55485na1t

现在,在 node1 上,我们终止 docker 容器。这个节点将没有服务(swarm 将在几秒钟后在这里重新创建它以保持服务上的 replication=3)

[root@node1 ~]# docker kill d3b3fbc0f2c5
d3b3fbc0f2c5

容器不见了

[root@node1 ~]# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS               NAMES

新建容器

[root@node1 ~]# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS               NAMES
b8c9a7a5cf97        ddewaele/springboot.crud.sample:latest   "sh -c 'java $JAVA_OP"   11 seconds ago      Up 9 seconds                            springbootcrudsample.3.9v4cnhi8dvq7n8afb2kvp28sk

然而,在下面的输出中,当容器 d3b3fbc0f2c5 被终止时,入口负载均衡器没有检测到这一点,它仍在向节点发送流量(导致连接被拒绝)?

我们应该如何处理这种情况?这种情况下我们还需要外部负载均衡器吗?我们应该如何配置它?

[root@centosvm ~]# while :; do curl http://localhost:8080/env/hostname ; echo "" ; sleep 1; done
{"hostname":"d3b3fbc0f2c5"}
{"hostname":"a593d485050a"}
{"hostname":"ebca8f24ec3a"}
{"hostname":"d3b3fbc0f2c5"}
{"hostname":"a593d485050a"}
{"hostname":"ebca8f24ec3a"}
{"hostname":"d3b3fbc0f2c5"}
{"hostname":"a593d485050a"}
{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
curl: (7) Failed connect to localhost:8080; Connection refused

{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
{"hostname":"b8c9a7a5cf97"}
{"hostname":"ebca8f24ec3a"}
{"hostname":"a593d485050a"}
{"hostname":"b8c9a7a5cf97"}

François Maturel 所示,通过适当的健康检查,Docker Swarm 将考虑容器的健康状态来决定是否将请求路由到它。

对于已启用默认执行器的 Spring 引导应用程序,将其添加到 Docker 文件足以进行基本的健康检查。当 Spring 启动应用程序初始化并启用其 health actuator 时,以下 http 请求将 return 有效的 http 200 响应并且健康检查将通过。

HEALTHCHECK CMD wget -q http://localhost:8080/health -O /dev/null

这将使您的 docker 容器能够达到健康状态。当您的 docker 容器启动时,其中的服务 运行 可能仍在初始化。为了进行适当的负载平衡和检测服务健康状况,Swarm 需要知道何时能够将请求路由到特定服务实例(节点上的容器)。

所以当 Swarm 启动一个服务副本时,它会启动一个容器,它会一直等到服务的健康状态为 "healthy"。当您的容器启动时,它将从 "starting" :

过渡
CONTAINER ID        IMAGE                                                                                                     COMMAND                  CREATED             STATUS                                     PORTS               NAMES
5001e1c46953        ddewaele/springboot.crud.sample@sha256:4ce69c3f50c69640c8240f9df68c8816605c6214b74e6581be44ce153c0f3b7a   "/docker-entrypoin..."   5 seconds ago       Up Less than a second (health: starting)                       springbootcrudsample.2.yt6d38zhhq2wxt1d6qfjz5974

到'healthy'。只有这样,Swarm 负载均衡器才会将请求路由到此端点。

[root@centos-a ~]# docker ps
CONTAINER ID        IMAGE                                                                                                     COMMAND                  CREATED              STATUS                        PORTS               NAMES
5001e1c46953        ddewaele/springboot.crud.sample@sha256:4ce69c3f50c69640c8240f9df68c8816605c6214b74e6581be44ce153c0f3b7a   "/docker-entrypoin..."   About a minute ago   Up About a minute (healthy)                       springbootcrudsample.2.yt6d38zhhq2wxt1d6qfjz5974

@ddewaele 是正确的,所以这里还有一些花絮:

  • 不,LB 不直接执行端口连接检查,那是 Docker 引擎启动健康检查的工作,这可能是一个简单的 curl 或更多。
  • 健康检查对于零停机部署至关重要。特别是如果您的容器需要超过一亚秒的时间来启动或关闭。没有健康检查,docker 只知道 "Does Linux say the process is running?"
  • 您可以使用 docker events 查看它在每个容器中启动 exec 命令,并为其 Swarm 服务设置健康检查。您还可以在那里看到它如何将 task/container 标记为 healthy/unhealthy。
  • issues/bugs 入口负载均衡器在 update/shutdown 任务期间发送数据包,但据我所知,截至 17.12(刚刚发布),这些已 mostly/all 已修复。一个老问题是 LB 可能不会在容器关闭开始之前从其路由 table 中删除任务,但人们报告说最近几个版本的结果更好。 https://github.com/moby/moby/issues/30321