【问题标题】:VPN-connected Docker container unable to access other containersVPN 连接的 Docker 容器无法访问其他容器
【发布时间】:2021-05-22 14:04:40
【问题描述】:

我有一个通过 VPN 容器 (vpn) 连接到互联网的应用程序容器 (app)。虽然该连接有效,但应用容器现在无法连接到数据库容器 (db)。

有没有办法让app 容器连接到本地容器(或任何 RFC1918 地址),同时也通过vpn 连接?我只需将db 添加到相同的network_mode 中,但db 需要由另一个未通过vpn 连接的容器访问(第二个应用程序将从db 读取)。

VPN 容器正在运行bubuntux/nordvpn,我的 docker-compose.yml 如下:

version: "3.9"

services:
  app:
    build: app/
    depends_on:
      - db
    network_mode: service:vpn
    depends_on:
      - vpn
  db:
    image: postgres:alpine
    restart: always
    network_mode: service:vpn
    environment:
      POSTGRES_USER: PASSWORD
      POSTGRES_PASSWORD: PASSWORD
      POSTGRES_DB: PASSWORD
  vpn:
    image: bubuntux/nordvpn
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.conf.all.rp_filter=2
    devices:
      - /dev/net/tun
    environment:
      - USER=EMAIL@EMAIL.COM
      - "PASS=PASSWORD"
      - CONNECT=United_States
      - TECHNOLOGY=NordLynx
    ulimits:
      memlock:
        soft: -1
        hard: -1

我尝试过使用link,如下:

app:
   links:
      - db

但是,我收到一个启动错误,特别是 container type network can't be used with links.

重申问题:如何通过 VPN 容器(在本例中为 bubuntux/nordvpn)将容器连接到互联网,并且非 VPN 连接的容器也可以访问该容器?

谢谢!

【问题讨论】:

    标签: docker docker-compose vpn


    【解决方案1】:

    根据documentation,这应该可以:

    version: "3.9"
    
    services:
      app:
        build: app/
        links:
          - vpn:db     
        depends_on:
          - db
      db:
        image: postgres:alpine
        depends_on:
          - vpn
        restart: always
        network_mode: service:vpn
        environment:
          POSTGRES_USER: PASSWORD
          POSTGRES_PASSWORD: PASSWORD
          POSTGRES_DB: PASSWORD
      vpn:
        image: bubuntux/nordvpn
        network_mode: bridge 
        cap_add:
          - NET_ADMIN
          - SYS_MODULE
        sysctls:
          - net.ipv4.conf.all.rp_filter=2
        devices:
          - /dev/net/tun
        environment:
          - USER=EMAIL@EMAIL.COM
          - "PASS=PASSWORD"
          - CONNECT=United_States
          - TECHNOLOGY=NordLynx
        ulimits:
          memlock:
            soft: -1
            hard: -1
        ports:
          - 5432:5432
    

    您应该在 localhost:5432 上从您的机器访问 postgres

    更新

    我做了这个模拟,因为我无法访问付费的 nordvpn acciut,所以 vpn 服务只是一个休眠 36000 秒的 ubuntu 并且 db 服务正在使用该网络,但是这种方式我不知道真正的vpn 服务正在使用这些附加功能(NET_ADMIN、SYS_MODULE)的主机上进行,但请尝试此设置。

    使用此设置应用程序服务(即管理员,一个 db admin gui)正在我的机器 localhost:8080 上侦听,我可以登录它并使用主机名 db 连接到 postgres db(服务器名称设置打开gui),它正在侦听其默认的 5432 postgres 端口。我也可以从我的机器 localhost:54320 地址访问 postgres,因为它被转发到应用服务 5432 端口,该端口使用与使用 vpn 服务网络的 db 服务相同的网络,这可能意味着使用 nordvpn 网络。

    version: "3"
    
    services:
      app:
        image: adminer
        restart: always
        ports:
          - 8080:8080
          - 54320:5432
        links:
          - vpn:db     
        depends_on:
          - db
      db:
        image: postgres:alpine
        depends_on:
          - vpn
        restart: always
        network_mode: service:vpn
        environment:
           - POSTGRES_USER=root
           - POSTGRES_PASSWORD=root
           - POSTGRES_DB=mydb
      vpn:
        image: ubuntu
        command: ["/bin/sh","-c","echo started && sleep 36000"]
    

    【讨论】:

    • 应用程序app仍然无法连接db
    • 确切的连接错误消息是什么以及您在应用程序中使用什么连接字符串连接到数据库? “主机”使用“db”,“端口”使用“5432”。
    • 我的连接字符串是这样的:postgres://USER:PASSWORD@db/DATABASENAME 错误信息是failed to connect to host=db user=USER database=DATABASENAME: hostname resolving error (lookup db: Try again) 错误似乎与主机名查找有关。
    • 应用程序仍在通过本地连接(而不是通过 VPN)进行连接,而数据库仍然无法访问。您似乎在数据库上使用network_mode: service:vpn,这意味着数据库已连接到VPN。这是故意的吗?
    【解决方案2】:

    这里的问题是network_mode: service:$name 的工作原理:

    它创建了从您的app 服务到您的vpn 服务的隐式依赖关系,因此docker-compose 将首先使用自己的网络命名空间和连接到虚拟网络的虚拟网络接口启动vpn 容器(在这种情况下<project>_default 网络由 docker_compose 创建)。

    然后它将启动app容器vpn服务具有相同的网络命名空间,即vpn容器中的localhostlocalhost中的相同app 容器 - 到目前为止,这实际上是您想要的。

    现在,由于您也在 db 服务上设置了 network_mode: service:vpn,它也将被添加到同一个网络命名空间 - 这不是你的因为容器现在无法通过 DNS 发现为 db,因为它附加到 vpn 而不是它自己的网络命名空间。

    通过以下方式之一实现您想要的:

    • 第一个选项:从db 中删除network_mode: service:vpn,这样服务将获得可以通过DNS 解析的自己的网络命名空间/内部IP 地址 - 即您可以使用“db”作为数据库的主机名连接
    • 第二个选项:使用“localhost”作为数据库连接的主机名,因为appdb 共享相同的网络命名空间,即localhost 都指的是相同的

    对于第一个选项,docker-compose.yml 如下所示:

    version: "3.9"
    
    services:
      app:
        build: app/
        depends_on:
          - db
        network_mode: service:vpn
      db:
        image: postgres:alpine
        restart: always
        environment:
          POSTGRES_USER: PASSWORD
          POSTGRES_PASSWORD: PASSWORD
          POSTGRES_DB: PASSWORD
      vpn:
        image: bubuntux/nordvpn
        cap_add:
          - NET_ADMIN
          - SYS_MODULE
        sysctls:
          - net.ipv4.conf.all.rp_filter=2
        devices:
          - /dev/net/tun
        environment:
          - USER=EMAIL@EMAIL.COM
          - "PASS=PASSWORD"
          - CONNECT=United_States
          - TECHNOLOGY=NordLynx
        ulimits:
          memlock:
            soft: -1
            hard: -1
    

    另请注意:

    • links 已弃用,不应用于新应用程序
    • depends_on 将确保依赖服务在依赖服务之前启动 - 但 DNS 解析不是必要 工作的,因此您可以省略它
    • 如果您想为服务更改/分配特定的 DNS 名称,可以使用 aliases

    更多信息请见Networking in Compose

    【讨论】:

    • 把这些放在一起,docker-compose.yml 文件会是什么样子?我需要改变什么?
    • 对于第一个选项:只需从 db 服务中删除 network_mode,文件的其余部分保持不变。对于第二个选项:不更改您的 docker-compose.yml,仅更改您的应用程序特定配置以使用 localhost(或 127.0.0.1)作为数据库主机。
    • 对于第一个选项,VPN 变得无关紧要,因为应用程序容器不再通过它进行路由。我的目标是让所有非本地地址的应用程序路由通过 VPN 并连接到数据库。
    • 不,只有db 服务受此影响,app 服务仍将有network_mode: service:vpn 并因此通过VPN 路由。如果您还需要通过 VPN 路由数据库,则需要第二个选项。
    • 我用具体的docker-compose.yml更新了答案
    【解决方案3】:

    当您在 app 的配置中使用 network_mode: service:vpn 时,appvpn 服务似乎在同一个容器网络中运行(具体来说,它们在同一个网络命名空间中)。它们共享接口、路由规则、端口等。值得注意的是,它们还共享/etc/resolv.conf/etc/hosts。由于links 只是将相关条目添加到/etc/hosts,因此您可以通过(反直觉地)将db 链接添加到vpn 服务,从app 链接到db

    尝试以下配置:

    version: "3.9"
    
    services:
      app:
        build: app/
        depends_on:
          - db
        network_mode: service:vpn
      db:
        image: postgres:alpine
        network_mode: bridge
        restart: always
        environment:
          POSTGRES_USER: USER
          POSTGRES_PASSWORD: PASSWORD
          POSTGRES_DB: DB
      vpn:
        image: bubuntux/nordvpn
        network_mode: bridge
        cap_add:
          - NET_ADMIN
          - SYS_MODULE
        sysctls:
          - net.ipv4.conf.all.rp_filter=2
        devices:
          - /dev/net/tun
        environment:
          - USER=EMAIL@EMAIL.com
          - "PASS=PASSWORD"
          - CONNECT=foo
          - TECHNOLOGY=NordLynx
        links:
          - db # <----- This makes `db` accessible to `app`
        ulimits:
          memlock:
            soft: -1
            hard: -1
    

    【讨论】:

      猜你喜欢
      • 2021-02-08
      • 2020-06-24
      • 2021-11-21
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2017-05-19
      相关资源
      最近更新 更多