Docker Swarm:绕过负载均衡器并直接向特定容器发出请求

Docker Swarm: bypass load balancer and make direct request to specific containers

我有两个容器 运行 成群。每个都公开了一个我试图抓取的 /stats 端点。

但是,使用 swarm 端口显然会导致查询负载平衡,因此统计信息会混合在一起:

+--------------------------------------------------+
|                       Server                     |
|    +-------------+             +-------------+   |
|    |             |             |             |   |
|    | Container A |             | Container B |   |
|    |             |             |             |   |
|    +-------------+             +-------------+   |
|                 \              /                 |
|                  \            /                  |
|                 +--------------+                 |
|                 |              |                 |
|                 | Swarm Router |                 |
|                 |              |                 |
|                 +--------------+                 |
|                         v                        |
+-------------------------|------------------------+
                          |                         
                       A Stats                      
                       B Stats                      
                       A Stats                      
                       B Stats                      
                          |                         
                          v                          

我想为应用程序请求保留负载均衡器,但还需要一种直接向每个容器发出请求以抓取统计信息的方法。

+--------------------------------------------------+
|                       Server                     |
|    +-------------+             +-------------+   |
|    |             |             |             |   |
|    | Container A |             | Container B |   |
|    |             |             |             |   |
|    +-------------+             +-------------+   |
|        |        \              /         |       |
|        |         \            /          |       |
|        |        +--------------+         |       |
|        |        |              |         |       |
|        |        | Swarm Router |         |       |
|        v        |              |         v       |
|        |        +--------------+         |       |
|        |                |                |       |
+--------|----------------|----------------|-------+
         |                |                |
      A Stats             |             B Stats
      A Stats       Normal Traffic      B Stats
      A Stats             |             B Stats
         |                |                |
         |                |                |
         v                |                v

动态解决方案是理想的,但由于我不打算进行任何动态缩放,例如为每个容器硬编码端口这样的东西会很好:

::8080  Both containers via load balancer
::8081  Direct access to container A
::8082  Direct access to container B

这可以用 swarm 完成吗?

从覆盖网络内部,您可以使用 tasks.<service_name> DNS 查询获取所有副本的 IP 地址:

; <<>> DiG 9.11.5-P4-5.1+deb10u5-Debian <<>> -tA tasks.foo_test
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19860
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;tasks.foo_test.            IN  A

;; ANSWER SECTION:
tasks.foo_test.     600 IN  A   10.0.1.3
tasks.foo_test.     600 IN  A   10.0.1.5
tasks.foo_test.     600 IN  A   10.0.1.6

documentation.

中提到了这个

此外,如果您使用 Prometheus 来抓取这些端点以获取指标,您可以将上述内容与 dns_sd_configs 结合起来以设置要抓取的目标(here 是一篇关于如何抓取的文章) .这很容易获得 运行 但在功能上有些限制(尤其是在大型环境中)。

实现相同目的的更高级方法是使用 dockerswarm_sd_config (docs, example configuration)。这样,将通过查询 Docker 守护程序以及一些有用的标签(即节点名称、服务名称、自定义标签)来收集端点列表。

您可以尝试在主机上发布特定的容器端口 ,添加到您的服务:

    ports:
      - target: 8081
        published: 8081
        protocol: tcp
        mode: host

虽然不太理想,但您可以引入一个微服务作为其他容器的中介,这些容器公开 /stats。此微服务必须使用单独的端点进行配置,并在与所述端点相同的网络中运行。

这并没有绕过负载均衡器,而是让它变得无关紧要。

中间人可以汇总信息,或者您可以通过传递不透明标识符列表使其更复杂,然后调用者可以使用这些标识符来单独查询中间人。

从某种意义上说,它有点“反模式”,因为您有一个必须配置为能够访问每个端点的高度耦合的“统计”代理。

也就是说,从某种意义上说,这很好,您不必在代理外部公开单个容器。从安全角度来看,这可能更好,因为您不会从您的群中泄露额外的信息。