Disclaimer:
This solution originally designed for next configuration:
- Ubuntu 18.04
- OpenVPN 2.4.4
- Docker-CE 19.03.5
- Docker-Compose 1.24.0
- Bridge IPV4 networks
- Docker-Swarm not used
and may differ for other configurations.
Problem
Start your VPN connection.
Case 1
When you try to restart docker daemon you'll get in the logs:
failed to start daemon: Error initializing network controller: list bridge addresses failed: PredefinedLocalScopeDefaultNetworks
Case 2
When you try to create bridge network (implicitly docker
and docker-compose
try to create this kind of network) within next cases:
docker create network
without defining subnet parameter
docker-compose up
without defining subnet parameter
you'll get:
ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
Solution (TL;BPR)
Select address range for docker network from the private address space that not planned be to use for resources inside your VPN. Imagine that it is 172.26.0.0/16
.
Add changes to the Docker's daemon config file daemon.json
file. :
{
"bip": "172.26.0.1/17",
"fixed-cidr": "172.26.0.0/17",
"default-address-pools" : [
{
"base" : "172.26.128.0/17",
"size" : 24
}
]
}
Where:
bip
- aka «bridge ip»: specific bridge IP address for the docker0
bridge network, which used by default if other was not specified.
fixed-cidr
- CIDR range for docker0
interface and local containers. Only needed if you want to restrict the IP range defined by bip
.
default-address-pools
- CIDR range for docker_gwbridge
(needed for docker-swarm
) interface and bridge networks. size
parameter set the default submask for newly created networks inside this range.
We divide our initial 172.26.0.0/16
range by equal 172.26.0.0 - 172.26.127.255
and 172.26.128.0 - 172.26.255.255
pools in this example.
Be careful with daemon.json
formating, otherwise you'd get the error like this when restart docker's daemon
unable to configure the Docker daemon with file /etc/docker/daemon.json
- Run your VPN connection
- Find your device name by running the comand. Usually it something like
tun0
ip addr show type tun
- Show created routes
ip route show dev tun0
- Find the pool that overlaps with our selected address, let it be:
172.16.0.0/12 via 10.8.0.1
Split that pool on subnets on chunks with our selected Docker pool 172.26.0.0/16
. You can use this amazing calculator by David C. We've got:
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
Create /etc/openvpn/mynetwork-route-up.sh
script, for OpenVPN for excluding our subnet from routes, with following contents (note that we excluded our network):
#!/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
Create /etc/openvpn/mynetwork-route-pre-down.sh
script with following contents (note that we excluded our network):
#!/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
Make that scripts executable
sudo chmod u+x /etc/openvpn/mynetwork-route-up.sh
sudo chmod u+x /etc/openvpn/mynetwork-route-pre-down.sh
Add this lines to the end of your .ovpn
config
script-security 2
route-up /etc/openvpn/mynetwork-route-up.sh
route-pre-down /etc/openvpn/mynetwork-route-pre-down.sh
Restart your OpenVPN
Run (for removing networks that may conflict when daemon will restart)
docker network prune
- Restart Docker daemon
sudo service docker restart
Cause
OpenVPN used frequently to route all traffic through tunnel, or at least, proxy private pools. So why docker fails, when it started?
Case 1
When you starting the Docker daemon, it checks daemon's config bridge network for overlaping with routes (up->down stacktrace):
As you can see here, you can also disable creating the default bridge network in the daemon config for fixing this error.
Case 2
When the Docker's component libnetwork
try to create it's network, it check all available addresses for overlaping with routes. If nothing found, it returns an error (up->down stacktrace):
Of course, other scenarios to get this errors exists too. Gotta Catch 'Em All!
Workarounds (not recommended)
Create network with the subnet parameter
Docker allow you to pass subnet address range explicitly and it seems that doesn't perform an overlap check in this case.
https://github.com/docker/libnetwork/blob/922cd533eac14b6e0754756c5cacf9f44af5d699/network.go#L1657
Create a network when OpenVPN stopped, then start it
I don't dive deep in that, but I think, OpenVPN doesn't check overlapping.
P.S.
Thanks (https://stackoverflow.com/users/7918/jb)[jb] for his great answer, it inspire me a lot for wrtiting this answer.
For in-depth network understanding of Docker, you can read this articles:
Also, don't forget this!
/1
route which is more specific than default. To really make this work you need to remove the default route in theroute-up
script and then add it back in in adown
script. OpenVPN passes$route_net_gateway
, so something likeip route delete default via $route_net_gateway
forroute-up
andip route add default via $route_net_gateway
fordown
. – Fite