docker-compose:通过 vpn 路由流量,但与其他服务的连接除外
docker-compose: route traffic through vpn except for connections to other services
考虑这个 docker-compose 配置:
# docker-compose.yml
version: "3.7"
services:
app:
build: ./app
depends_on:
- db
- vpn
ports:
- "3001:3000"
db:
image: postgres
vpn:
build: ./vpn
cap_add:
- NET_ADMIN
描述
- 通过 http://localhost:3001 从 docker 主机访问
app
。
app
需要连接到 postgres db
,这是第二个容器。
- 此外,
app
需要连接到 api,这只能通过 vpn 访问。这就是第三个容器 vpn
建立所需 vpn 连接的原因。
目标
app
容器应该能够访问此 docker-compose 环境中的其他服务,即 db
,并通过 vpn
容器,这样它就可以访问 vpn 隧道后面的 api。
我试过的
我试过设置app
的network_mode
:
services:
app:
network_mode: "service:vpn"
这会通过 vpn
路由 app
容器的所有流量。有了这个,我可以从 app
容器到达 vpn 隧道后面的 api。但这与 ports: - "3001:3000"
不兼容。此外,无法再从 app
访问 db
容器:ping: bad address 'db'
.
我也尝试过从 vpn
容器 link 到 db
容器,希望这将使 db
服务可用app
.
services:
app:
network_mode: "service:vpn"
vpn:
links:
- db
但是 app
仍然找不到 db
。
如果我 link 来自 vpn
容器的 db
容器但是不 建立 vpn 连接vpn
容器,db
容器 可以 从 app
.
到达
并且我已经尝试将 127.0.0.1 db
添加到 app
容器的 /etc/hosts
中,隐约希望我可以到达 db
直接端口。但这也行不通。
有人知道如何实现吗?
我终于找到了解决方案,但需要三个步骤:
第 1 步:network_mode: service
为了通过 vpn
路由 app
容器的所有流量,在 app
容器上设置 network_mode
:
services:
app:
network_mode: "service:vpn"
第 2 步:DNS 服务器
为了解析 vpn 隧道后面的主机名以及本地 docker 服务,vpn
容器需要与两个 DNS 服务器对话:隧道后面的 DNS 服务器以及 docker-compose DNS 服务器。
据我所知,docker-compose DNS 服务器始终是 127.0.0.11
。
要找出隧道后面的远程DNS 服务器,建立隧道然后运行 cat /etc/resolv.conf
。这将在注释为“by strongSwan”的行中列出隧道后面的 DNS 服务器。
在 vpn
容器的启动脚本中,将两个 DNS 服务器添加到 vpn
容器的 resolv.conf
:
# vpn-container startup script:
echo "nameserver <remote dns server ip>" >> /etc/resolv.conf
echo "nameserver 127.0.0.11" >> /etc/resolv.conf
要对此进行测试,请登录 vpn
容器并尝试 ping
远程 ip 和 db
容器:
docker-compose run vpn /bin/bash
ping db # should work
ping <some-ip-behind-the-vpn-tunnel> # should also work
第 3 步:公开端口
在 app
容器上使用 network_mode: "service:vpn"
,据我所知,app
容器无法再向主机公开其端口。相反,app
容器和 vpn
容器现在对 docker 主机显示为同一台机器。因此,可以改为在 vpn
容器上公开所需的端口。
services:
vpn:
ports:
- "3001:3000"
然后可以通过 docker 主机上的 http://localhost:3001 访问 app
(!)。
汇集在一起:最终 docker-compose.yml
# docker-compose.yml
version: "3.7"
services:
app:
build: ./app
depends_on:
- db
- vpn
network_mode: "service:vpn"
db:
image: postgres
vpn:
build: ./vpn
cap_add:
- NET_ADMIN
ports:
- "3001:3000"
command: >
bash -c "echo 'nameserver <remote dns server ip>' >> /etc/resolv.conf
&& echo 'nameserver 127.0.0.11' >> /etc/resolv.conf
&& ..."
考虑这个 docker-compose 配置:
# docker-compose.yml
version: "3.7"
services:
app:
build: ./app
depends_on:
- db
- vpn
ports:
- "3001:3000"
db:
image: postgres
vpn:
build: ./vpn
cap_add:
- NET_ADMIN
描述
- 通过 http://localhost:3001 从 docker 主机访问
app
。 app
需要连接到 postgresdb
,这是第二个容器。- 此外,
app
需要连接到 api,这只能通过 vpn 访问。这就是第三个容器vpn
建立所需 vpn 连接的原因。
目标
app
容器应该能够访问此 docker-compose 环境中的其他服务,即 db
,并通过 vpn
容器,这样它就可以访问 vpn 隧道后面的 api。
我试过的
我试过设置
app
的network_mode
:services: app: network_mode: "service:vpn"
这会通过
vpn
路由app
容器的所有流量。有了这个,我可以从app
容器到达 vpn 隧道后面的 api。但这与ports: - "3001:3000"
不兼容。此外,无法再从app
访问db
容器:ping: bad address 'db'
.我也尝试过从
vpn
容器 link 到db
容器,希望这将使db
服务可用app
.services: app: network_mode: "service:vpn" vpn: links: - db
但是
app
仍然找不到db
。如果我 link 来自
到达vpn
容器的db
容器但是不 建立 vpn 连接vpn
容器,db
容器 可以 从app
.并且我已经尝试将
127.0.0.1 db
添加到app
容器的/etc/hosts
中,隐约希望我可以到达db
直接端口。但这也行不通。
有人知道如何实现吗?
我终于找到了解决方案,但需要三个步骤:
第 1 步:network_mode: service
为了通过 vpn
路由 app
容器的所有流量,在 app
容器上设置 network_mode
:
services:
app:
network_mode: "service:vpn"
第 2 步:DNS 服务器
为了解析 vpn 隧道后面的主机名以及本地 docker 服务,vpn
容器需要与两个 DNS 服务器对话:隧道后面的 DNS 服务器以及 docker-compose DNS 服务器。
据我所知,docker-compose DNS 服务器始终是 127.0.0.11
。
要找出隧道后面的远程DNS 服务器,建立隧道然后运行 cat /etc/resolv.conf
。这将在注释为“by strongSwan”的行中列出隧道后面的 DNS 服务器。
在 vpn
容器的启动脚本中,将两个 DNS 服务器添加到 vpn
容器的 resolv.conf
:
# vpn-container startup script:
echo "nameserver <remote dns server ip>" >> /etc/resolv.conf
echo "nameserver 127.0.0.11" >> /etc/resolv.conf
要对此进行测试,请登录 vpn
容器并尝试 ping
远程 ip 和 db
容器:
docker-compose run vpn /bin/bash
ping db # should work
ping <some-ip-behind-the-vpn-tunnel> # should also work
第 3 步:公开端口
在 app
容器上使用 network_mode: "service:vpn"
,据我所知,app
容器无法再向主机公开其端口。相反,app
容器和 vpn
容器现在对 docker 主机显示为同一台机器。因此,可以改为在 vpn
容器上公开所需的端口。
services:
vpn:
ports:
- "3001:3000"
然后可以通过 docker 主机上的 http://localhost:3001 访问 app
(!)。
汇集在一起:最终 docker-compose.yml
# docker-compose.yml
version: "3.7"
services:
app:
build: ./app
depends_on:
- db
- vpn
network_mode: "service:vpn"
db:
image: postgres
vpn:
build: ./vpn
cap_add:
- NET_ADMIN
ports:
- "3001:3000"
command: >
bash -c "echo 'nameserver <remote dns server ip>' >> /etc/resolv.conf
&& echo 'nameserver 127.0.0.11' >> /etc/resolv.conf
&& ..."