将Docker Compose网络中的主机重定向到Docker外部的本地主机

4
我有一组使用docker-compose运行的容器。网络是docker-compose创建的默认网络,容器之间使用docker-compose自动设置的主机名进行通信。 因此,如果我在docker-compose中定义了一个名为“my_service”的服务,我可以通过主机名“my_service”访问该容器。
在某些情况下,我想禁用特定的容器,并将所有请求重定向到实际的本地主机而不是docker容器。所以,我想将主机“my_service”路由到实际的localhost上,这里我正在使用带有调试器附加或类似工具的IDE运行相同的服务。
我不确定如何最好地实现这一点,无论是修改网络本身还是以某种方式代理这些请求。是否有一种方法可以实现这一点,最好只需要对docker-compose.yml进行一些更改,而不需要更改我的容器本身?
我在Linux(Ubuntu 20.04)或Windows 10上使用WSL2的docker-compose。

1
如果我理解你想做的事情,你可以使用host.docker.internal来连接主机中的应用程序。https://djangocas.dev/blog/docker-container-to-connect-localhost-of-host/ - camba1
这可能是可行的 https://dev.to/natterstefan/docker-tip-how-to-get-host-s-ip-address-inside-a-docker-container-5anh与@camba1的建议非常相似 - ofirule
你能分享一下你的 docker-compose.yml 文件吗? - Pierre B.
可以在主机上运行代理(例如Squid),并将容器环境设置为通过主机代理连接,或者(理想情况下)如果您可以将在IDE中运行的容器附加到Docker网络,则最容易。 - masseyb
1个回答

2

简而言之

你需要三个东西才能使它工作:

  1. 预定义的外部网络,以通过固定IP访问主机
  2. 每个参与服务的hostname条目
  3. 另一个Docker服务作为路由器,以便将请求重定向到主机。 我们还将使用aliases条目,以允许其他服务通过预定义的主机名访问此路由器服务。

如何操作

注意:已测试Linux。不确定是否适用于Windows。

  1. 创建具有网关的外部网络。 例如,通过下面定义的自定义IP 172.30.0.1,每个Docker服务应该能够访问主机。
docker network create \
    --driver=bridge \
    --subnet=172.30.0.0/16 \
    --gateway=172.30.0.1 \
    host-net
  1. 在你的docker-compose.yml文件中为每个参与服务添加自定义的hostname,例如:
services:
    service-1:
        hostname: service-1.in.docker

    service-2:
        hostname: service-2.in.docker

因此,service-2现在可以通过域名service-1.in.docker访问service-1,反之亦然。

  1. 创建一个额外的服务,利用多功能转发工具socat来充当路由器,例如:
services:
    router:
        image: alpine/socat
        command: TCP-LISTEN:5900,fork TCP:172.30.0.1:15900

这里基于TCP协议,在本地监听5900端口,并将传入的请求重定向到目标地址 172.30.0.1(网关 -> 主机)的15900端口。

示例

version: "3.9"

services:
  router:
    image: alpine/socat
    entrypoint: >
      sh -c "
        socat TCP-LISTEN:5900,fork TCP:172.30.0.1:15900 &
        socat TCP-LISTEN:5901,fork TCP:172.30.0.1:15901 &
        wait
      "
    networks:
      host-net:
      bridged:
        aliases:
          - service-1.in.docker

  service-1:
#   hostname: service-1.in.docker
    image: hashicorp/http-echo
    command: -listen=:5900 -text="hello world"
    networks:
      bridged:

  service-2:
    hostname: service-2.in.docker
    image: curlimages/curl:7.75.0 
    command: ["sh", "-c", "while true; do curl service-1.in.docker:5900 && sleep 5; done"]
    networks:
      bridged:

networks:
  host-net:
    external: true
  bridged:

注意:

  1. 这里的router服务包括两个重要部分:host-net作为网络,以及针对网络bridgedaliases条目,其中还涉及其他服务。

  2. router服务的工作方式如下:

(请求) -> [localhost:5900] -> (重定向) -> [172.30.0.1:15900]

(请求) -> [localhost:5901] -> (重定向) -> [172.30.0.1:15901]

  1. 由于我们注释了hostname:service-1.in.docker这一行,因此由service-2curl service-1.in.docker:5900)发出的curl请求将转到router服务(由于别名service-1.in.docker)。随后,这些请求被转发到主机上的端口15901。

  2. 如果我们注释掉hostname:service-1.in.docker这一行,则service-1将用"hello world"回应service2

如果您有可能动态更改各个服务使用的主机名,例如环境变量或属性文件等,则可以利用它们,这样您就不必每次都注释掉它们:

services:
  router:
    image: alpine/socat
    networks:
      bridged:
        aliases:
          - service-1.in.router

  service-2:
    hostname: service-2.in.docker
    command: ["sh", '-c', 'while true; do curl ${DEST_SERVICE_HOST_ADDR_SET_BY_ENV_VAR} && sleep 5; done']

DEST_SERVICE_HOST_ADDR_SET_BY_ENV_VAR 可以根据需要提供 service-1.in.routerservice-1.in.docker

注释:

您可以在主机上运行测试服务器来测试这个,例如:

python3 -m http.server 15901

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接