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

描述

目标

app 容器应该能够访问此 docker-compose 环境中的其他服务,即 db,并通过 vpn 容器,这样它就可以访问 vpn 隧道后面的 api。

我试过的

有人知道如何实现吗?

我终于找到了解决方案,但需要三个步骤:

第 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
      && ..."