【问题标题】:How make openvpn work with docker如何使 openvpn 与 docker 一起工作
【发布时间】:2018-01-23 08:08:28
【问题描述】:

我最近安装了privacy vpn,结果发现启用了openvpn 会破坏docker。

当我尝试运行 docker-compose up 时出现以下错误

ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

禁用 vpn 可以解决问题(但我宁愿不禁用它)。有没有办法让这两者和平共处?我使用 debian jessie,我的 openvpn 有以下版本字符串

 OpenVPN 2.3.4 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Jun 26 2017

很多人通过禁用openvpn“解决”了这个问题,所以我专门询问如何让这两者同时工作。

参考文献:

  1. https://stackoverflow.com/a/45377351/7918
  2. https://stackoverflow.com/a/42499393/7918

如果这有什么不同,我的 vpn 提供商是:https://www.ovpn.com/,这里是(有些编辑的)配置文件:

client
dev tun

proto udp

remote host port
remote-random

mute-replay-warnings
replay-window 256

push "dhcp-option DNS 46.227.67.134"    
push "dhcp-option DNS 192.165.9.158"

remote-cert-tls server
cipher aes-256-cbc
pull

nobind
reneg-sec 432000
resolv-retry infinite

comp-lzo
verb 1

persist-key
persist-tun
auth-user-pass /etc/openvpn/credentials
ca ovpn-ca.crt
tls-auth ovpn-tls.key 1

【问题讨论】:

    标签: docker debian openvpn docker-networking


    【解决方案1】:

    解决方案 (TL;DR;)

    使用以下内容创建/etc/openvpn/fix-routes.sh 脚本:

    #!/bin/sh
    
    echo "Adding default route to $route_vpn_gateway with /0 mask..."
    ip route add default via $route_vpn_gateway
    
    echo "Removing /1 routes..."
    ip route del 0.0.0.0/1 via $route_vpn_gateway
    ip route del 128.0.0.0/1 via $route_vpn_gateway
    

    将可执行位添加到文件中:chmod o+x /etc/openvpn/fix-routes.sh。将此文件的所有者更改为 root:chown root:root /etc/openvpn/fix-routes.sh

    将以下两行添加到您的配置中:

     script-security 2
     route-up  /etc/openvpn/fix-routes.sh
    

    说明

    Openvpn 为以下网络添加路由:0.0.0.0/1128.0.0.0/1(这些路由覆盖整个 IP 范围),并且 docker 无法找到 IP 地址范围来创建它自己的专用网络。

    您需要添加一个默认路由(通过 openvpn 路由所有内容)并禁用这两个特定路由。 fix-routes 脚本就是这样做的。

    openvpn 添加自己的路由后调用此脚本。要执行脚本,您需要将 script-security 设置为 2,这允许从 openvpn 上下文执行 bash 脚本。

    谢谢

    我要感谢author of this comment on github,还要感谢ovpn support

    【讨论】:

    • 小心此建议 - 如果您希望 所有 流量通过 VPN,此脚本将通过您之前的(未受保护的)默认路由发送您的流量。 OpenVPN 添加了一个/1 路由,它比默认路由更具体。要真正完成这项工作,您需要删除route-up 脚本中的默认路由,然后将其重新添加到down 脚本中。 OpenVPN 通过$route_net_gateway,所以类似于ip route delete default via $route_net_gateway 用于route-upip route add default via $route_net_gateway 用于down
    • 实际上看起来我有通过 VPN 的 VPN(所有流量都路由到那里)。看起来我的系统有不止一个默认路由,而 OpenVPN 只是第一个(因此只使用了一个)。一些流量通过其他路线(本地流量),但在我的设置中,本地流量是我最不关心的。但是,您的建议会使路由表更好。不过,我确实需要阅读更多关于 linux 网络的信息。
    • 我不想通过我的 VPN 路由所有内容,所以我使用了: ip route add 10.8.0.0/24 via "$route_vpn_gateway" 。这个答案是让我找到解决方案的原因。谢谢!
    • @grisha 你能解释一下你的新手吗?据我从您的评论中了解到,此脚本将阻止我的流量通过我的 VPN 但是当我使用 traceroute 时,我仍然看到这种情况发生。我错过了什么吗?如果我使用这个脚本,什么样的流量不会通过 VPN?谢谢
    • 我应该在哪里添加提到的这两行?哪个配置文件?
    【解决方案2】:

    如果您在 docker compose 文件中定义子网 CIDR,您也可以让 docker-compose 工作:

    networks:
      your-network:
       ipam:
          config:
          - subnet: 172.16.238.0/24
            gateway: 172.16.238.1
    

    另一种选择:首先使用子网 CIDR 创建网络,然后在 docker compose 文件中指定要使用此网络:

    docker network create your-network --subnet 172.24.24.0/24
    

    在你的 docker compose 文件中:

    networks:
      your-network:
        external: true
    

    【讨论】:

    • 这行得通,是一个更好的答案。谢谢!
    • 网关:目前不适用于 docker-compose V3.0 这是一个已知的限制,唯一的解决方法是坚持使用 V2 或使用同样建议的 network create 命令。
    • 在 docker compose 版本 1.25.5 中工作。谢谢
    【解决方案3】:

    基于answer from Anas El Barkani,这是一个使用 PostgreSQL 的完整分步示例。

    在 VPN 未连接时,创建一个永久的docker network

    docker network create my-network --subnet 172.24.24.0/24
    

    在 docker-compose 文件中,将网络指定为外部:

    version: "2"
    services: postgres: container_name: postgres image: postgres volumes: - ./volumes/postgres/data:/var/lib/postgresql/data environment: - POSTGRES_DB=dummy - POSTGRES_USER=user - POSTGRES_PASSWORD=123456 - POSTGRES_HOST=localhost networks: - default ports: - "127.0.0.1:5432:5432"
    networks: default: external: name: my-network

    就是这样。现在您可以启用您的 VPN,并照常启动/停止容器:

    docker-compose up -d
    docker-compose down
    

    无需每次都打开/关闭 VPN,或以 root 身份添加奇怪的脚本。

    【讨论】:

    • “不需要关闭vpn”但是创建网络只有在没有连接vpn时才会运行...
    • @sakiroka 您在创建网络时禁用了 VPN 一次。网络是持久的。您可以在许多撰写文件中重复使用该网络。
    • 你是对的,但是例如我们使用一个工具来创建所有容器,通过项目自动将所有内容联网。再次用于其他项目。我们不希望这些手动步骤减慢我们的开发人员的速度。他们每周更换项目。通过配置文件设置的 openvpn ip range 对我们的案例来说是更可接受的解决方案。
    【解决方案4】:

    免责声明:

    这个解决方案最初是为下一个配置设计的:

    • Ubuntu 18.04
    • OpenVPN 2.4.4
    • Docker-CE 19.03.5
    • Docker-Compose 1.24.0
    • 桥接 IPV4 网络
    • Docker-Swarm 未使用

    并且可能因其他配置而有所不同。


    问题

    开始您的 VPN 连接。


    案例 1

    当您尝试重新启动 docker daemon 时,您会看到日志:

    failed to start daemon: Error initializing network controller: list bridge addresses failed: PredefinedLocalScopeDefaultNetworks
    


    案例 2

    当您尝试创建桥接网络(隐式 dockerdocker-compose 尝试创建这种网络)时:

    • docker create network 未定义子网参数
    • docker-compose up 未定义子网参数

    你会得到:

    ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
    

    解决方案 (TL;BPR)

    1. private address space 中选择 docker 网络的地址范围,该地址范围不打算用于 VPN 内的资源。想象它是172.26.0.0/16

    2. 将更改添加到 Docker 的守护程序配置文件 daemon.json 文件。 :

      {
          "bip": "172.26.0.1/17",
          "fixed-cidr": "172.26.0.0/17", 
          "default-address-pools" : [
              {
                  "base" : "172.26.128.0/17",
                  "size" : 24
              }
          ]
      }
      

      地点:

      • bip - 又名 «bridge ip»:docker0 桥接网络的特定桥接 IP 地址,如果未指定其他则默认使用。
      • fixed-cidr - docker0 接口和本地容器的 CIDR 范围。仅当您要限制bip 定义的 IP 范围时才需要。
      • default-address-pools - docker_gwbridgedocker-swarm 需要)接口和桥接网络的 CIDR 范围。 size 参数设置此范围内新建网络的默认子掩码。


      在本例中,我们将初始 172.26.0.0/16 范围除以 172.26.0.0 - 172.26.127.255172.26.128.0 - 172.26.255.255 池。

      注意daemon.json的格式化,否则重启docker的守护进程时会出现这样的错误

      unable to configure the Docker daemon with file /etc/docker/daemon.json
      
    3. 运行您的 VPN 连接
    4. 通过运行命令查找您的设备名称。通常它类似于tun0
      ip addr show type tun
      
    5. 显示创建的路线
      ip route show dev tun0
      
    6. 找到与我们选择的地址重叠的池,让它成为:
      172.16.0.0/12 via 10.8.0.1
      
    7. 使用我们选择的 Docker 池 172.26.0.0/16 在块上的子网上拆分该池。您可以使用this amazing calculator by David C。我们有:

      172.16.0.1/13
      172.24.0.1/15
      172.26.0.0/16
      172.27.0.1/16
      172.28.0.1/14
      
    8. 为OpenVPN创建/etc/openvpn/mynetwork-route-up.sh脚本,用于从路由中排除我们的子网,内容如下(注意我们排除了我们的网络):

      #!/usr/bin/env bash
      
      echo "Remove the route that conflicts with the Docker's subnet"
      ip route del 172.16.0.0/12 via $route_vpn_gateway
      
      echo "Bring back routes that don't intersect"
      ip route add 172.16.0.0/13 via $route_vpn_gateway dev $dev
      ip route add 172.24.0.0/15 via $route_vpn_gateway dev $dev
      ip route add 172.27.0.0/16 via $route_vpn_gateway dev $dev
      ip route add 172.28.0.0/14 via $route_vpn_gateway dev $dev
      
    9. 使用以下内容创建/etc/openvpn/mynetwork-route-pre-down.sh 脚本(注意我们排除了我们的网络):

      #!/usr/bin/env bash
      
      echo "Remove manually created routes"
      ip route del 172.16.0.0/13 dev $dev
      ip route del 172.24.0.0/15 dev $dev
      ip route del 172.27.0.0/16 dev $dev
      ip route del 172.28.0.0/14 dev $dev
      
      echo "Creating original route because OpenVPN will try to del that"
      ip route add 172.16.0.0/12 via $route_vpn_gateway dev $dev
      
    10. 使脚本可执行

      sudo chmod u+x /etc/openvpn/mynetwork-route-up.sh
      sudo chmod u+x /etc/openvpn/mynetwork-route-pre-down.sh
      
    11. 将此行添加到 .ovpn 配置的末尾

      script-security 2
      route-up /etc/openvpn/mynetwork-route-up.sh
      route-pre-down /etc/openvpn/mynetwork-route-pre-down.sh
      
    12. 重启您的 OpenVPN

    13. 运行(用于删除在守护程序重新启动时可能发生冲突的网络)

    docker network prune
    
    1. 重启 Docker 守护进程
      sudo service docker restart
      

    原因

    OpenVPN 经常用于通过隧道或至少通过代理专用池路由所有流量。那么为什么 docker 在启动时失败了呢?

    案例 1

    当你启动 Docker 守护进程时,它会检查守护进程的配置网桥网络是否与路由重叠(向上->向下堆栈跟踪):

    正如您可以see here 一样,您也可以禁用在守护程序配置中创建默认桥接网络以修复此错误。


    案例 2

    当 Docker 的组件libnetwork 尝试创建它的网络时,它会检查所有可用地址是否与路由重叠。如果没有找到,则返回错误(向上->向下堆栈跟踪):


    当然,也存在其他导致此错误的情况。必须抓住他们!


    解决方法(不推荐)

    使用子网参数创建网络

    Docker 允许您显式传递子网地址范围,并且在这种情况下似乎不执行重叠检查。

    https://github.com/docker/libnetwork/blob/922cd533eac14b6e0754756c5cacf9f44af5d699/network.go#L1657


    在 OpenVPN 停止时创建一个网络,然后启动它

    我没有深入探讨,但我认为,OpenVPN 不会检查重叠。


    附言

    谢谢(https://stackoverflow.com/users/7918/jb)[jb] his great answer,写这个答案给了我很多启发。

    想要深入了解Docker的网络,可以看这篇文章:

    另外,don't forget this!

    【讨论】:

    • 很好的答案,有详尽的解释和参考。
    【解决方案5】:

    导致问题的默认路由由 OpenVPN 服务器推送到 OpenVPN 客户端。

    然后创建一个脚本来删除路由,您可以简单地从一开始就阻止有问题的路由被创建。

    有两种方法可以做到这一点:

    1. 如果您可以更改 OpenVPN 服务器上的设置,请编辑配置并删除 redirect-gateway 选项。在我的 EdgeRouter 上,相关行如下所示:

      openvpn-option "--push redirect-gateway def1"

      一台 Linux 服务器,我相信它看起来像这样:

      push "redirect-gateway def1"

    2. 如果您无法更改 OpenVPN 服务器上的设置,您可以告诉您的 OpenVPN 客户端忽略来自服务器的推送路由。在我的 Linux 客户端上,相关行如下所示:

      pull-filter ignore redirect-gateway

    完成这些更改并重新启动 OpenVPN 服务后,您应该能够启动 Docker 容器而不会出现可怕的 could not find an available, non-overlapping IPv4 address 错误。

    【讨论】:

      【解决方案6】:

      也许一种方法是添加除 172.16.0.0/12 之外的所有路由以通过 VPN 进行路由,这样我们就可以确保一切都得到妥善处理:

      sudo ip route add 192.0.0.0/2 via $route_vpn_gateway
      sudo ip route add 128.0.0.0/3 via $route_vpn_gateway
      sudo ip route add 176.0.0.0/4 via $route_vpn_gateway
      sudo ip route add 160.0.0.0/5 via $route_vpn_gateway
      sudo ip route add 168.0.0.0/6 via $route_vpn_gateway
      sudo ip route add 174.0.0.0/7 via $route_vpn_gateway
      sudo ip route add 173.0.0.0/8 via $route_vpn_gateway
      sudo ip route add 172.128.0.0/9 via $route_vpn_gateway
      sudo ip route add 172.64.0.0/10 via $route_vpn_gateway
      sudo ip route add 172.32.0.0/11 via $route_vpn_gateway
      sudo ip route add 172.0.0.0/12 via $route_vpn_gateway
      
      # And finally delete the default route which handle 172.16.0.0/12
      sudo ip route del 128.0.0.0/1 via $route_vpn_gateway
      

      【讨论】:

        【解决方案7】:

        这里有一些额外的上下文:0.0.0.0 和 128.0.0.0 路由仅在 OpenVPN 服务器(又名访问服务器)配置为推送路由以通过 VPN 发送所有端点的 Internet 流量时创建。通过添加这些广泛的路由,可以路由用户的 Internet 流量,同时不会干扰本地 LAN 上的路由,并确保端点仍然能够将 OpenVPN 流量本身路由到本地路由器。

        如果不需要通过 OpenVPN 服务器发送所有互联网流量,您最好让您的 VPN 管理员创建一个配置文件,该配置文件仅通过 VPN 将流量路由到所需目的地(例如私有 IP 地址范围)一切。这应该避免弄乱端点上的路由。

        【讨论】:

          【解决方案8】:

          什么对我有用: 看过之后

          Creating network "airflow_default" with the default driver
          ERROR: could not find an available, non-overlapping IPv4 address pool 
          among the defaults to assign to the network
          

          只需手动创建该网络:

          docker network create airflow_default --subnet 172.24.24.0/24
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-11-03
            • 1970-01-01
            • 2017-05-30
            • 1970-01-01
            • 1970-01-01
            • 2023-02-02
            • 2021-12-19
            相关资源
            最近更新 更多