我有一组使用 docker-compose 运行的容器。网络是 docker-compose 创建的默认网络,容器使用 docker-compose 自动设置的主机名相互通信。因此,如果我在 docker-compose 中定义了一个名为“my_service”的服务,我会以主机“my_service”的身份访问这个容器。
在某些情况下,我想禁用特定容器并将所有请求重定向到实际的本地主机,而不是 docker 容器。因此,我不想将主机“my_service”路由到具有相同名称的容器,而是将其路由到实际的本地主机,在那里我运行相同的服务,例如在带有调试器或类似的东西的 IDE 中。
我不确定如何最好地实现这一点,我是否可以修改网络本身来做到这一点,或者我是否必须以某种方式代理这些请求。有没有办法做到这一点,理想情况下只需要在 docker-compose.yml 中进行一些更改,而无需更改我的容器本身?
我在 Linux (Ubuntu 20.04) 上使用 docker-compose 或在 Windows 10 上使用 WSL2。
答案 0 :(得分:0)
你需要三件事才能让它工作:
hostname
每个参与服务的条目aliases
条目允许其他服务通过预定义的主机名访问此路由器服务。注意:针对 Linux 进行了测试。不确定,它是否适用于 Windows。
172.30.0.1
,每个 docker 服务都应该能够访问主机。docker network create \
--driver=bridge \
--subnet=172.30.0.0/16 \
--gateway=172.30.0.1 \
host-net
hostname
,例如services:
service-1:
hostname: service-1.in.docker
service-2:
hostname: service-2.in.docker
因此,service-2
现在可以通过域 service-1.in.docker 访问 service-1
,反之亦然。
services:
router:
image: alpine/socat
command: TCP-LISTEN:5900,fork TCP:172.30.0.1:15900
这里基于 TCP,它在 localhost 的 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:
注意事项:
这里的router
服务包括两个重要的东西:host-net
作为网络,以及aliases
网络入口bridged
,其中还涉及其他服务.
router
服务的工作原理如下:
(请求) -> [localhost:5900] -> (重定向) -> [172.30.0.1:15900]
(请求) -> [localhost:5901] -> (重定向) -> [172.30.0.1:15901]
由于我们注释了 hostname: service-1.in.docker
行,service-2
(curl service-1.in.docker:5900) 发出的 curl 请求将转到router
服务(由于别名 service-1.in.docker)。随后,这些请求通过端口 15901 转发到主机。
如果我们注释掉 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.router
或 service-1.in.docker
。
脚注:
你可以在你的主机上运行一个测试服务器来测试这个,例如:
python3 -m http.server 15901