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
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