如何使openvpn与docker一起工作

时间:2017-08-15 11:50:29

标签: docker debian openvpn docker-networking

我最近安装了隐私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

很多人"解决了#34;这个问题通过禁用openvpn,所以我特别询问如何使这两个工作同时工作。

参考文献:

  1. https://stackoverflow.com/a/45377351/7918
  2. https://stackoverflow.com/a/42499393/7918
  3. 如果这有什么不同,我的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
    

7 个答案:

答案 0 :(得分:33)

解决方案(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

答案 1 :(得分:14)

如果在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

答案 2 :(得分:7)

免责声明:

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

  • 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 -又名“网桥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不会检查重叠部分。


P.S。

({https://stackoverflow.com/users/7918/jb)[jb]代表his great answer,这使我很想念这个答案。

要对Docker进行深入的网络了解,可以阅读以下文章:

还有don't forget this

答案 3 :(得分:2)

基于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。

答案 4 :(得分:2)

导致问题的默认路由由 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 错误。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

也许这样做的一种方法是将除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