Docker default address pool customization question

Hi,

The docker version: 19.03.11-ol, build 1a3e46b
Operation System: Oracle Linux 7.9

I was looking for the right place to ask my question (among the docker GitHub repositories) but ended up with this forum. If this question should be moved somewhere - tell me:)

I’d like to clarify the docker default address pool creation and how to properly customize that.
There is information about that different sources including the official documentation, but it’s quite difficult to gain insight into it.

For example, I need to customize my default docker network settings. So the solution I found was to extend my ‘daemon.json’ configuration file with the ‘default-address-pool’ options.

Like this:

"default-address-pools": [
       {
           "base": "10.17.0.1/16",
            "size": 16
        }
]

I supposed that a setting like that will give me the address pool of 10.17.X.X with the netmask 255.255.0.0
But this actually didn’t work, my containers started to fail with:

"starting container failed: error creating external connectivity network: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network"

…at the same time the following settings work:

"default-address-pools": [
       {
           "base": "10.17.0.0/16",
            "size": 24
        }
]

These settings gave me the 255.255.255.0 netmask (according to ‘size’ option) but what /16 stands for then?

I started to look for an explanation for it and found some: https://github.com/moby/moby/pull/36396#issue-171138310

But it is also puzzling one, in particular, the document says:

As an example,
dockerd --default-address-pools base=10.10.0.0/16,size=24
would allow user to set the 256 pools 10.10.[0-255].0/24 as default for the local scope networks.

It caused questions like:

How does /16 correlates with the number of subnets [0-255] and the /24 netmask? What is the role of netmask /24 if we already have /16 definition?
What number of the pools will be if we set for example /17, /18, /19 masks?
Why should we define two masks here (/16 and /24) at all? Can we use just one of them?

Another example from the given link:

When user creates a network without specifying a --subnet, docker will pick a subnet for the network from the static set 172.[17-31].0.0/16 and 192.168.[0-240].0/20 for the local scope networks

The example says 192.168.[0-240].0/20 but if I’m not mistaken according to the standard network calculations, /20 netmask allows only 16 subnets (192.168.[0-15].0/20). So where did the number of 240 come from?

Does docker do any specific calculations? If yes it would be great to find out what exactly is going on under the hood to know how to properly customize these settings.

It would be great if someone could shed a light on the above.
Maybe my description is not clear enough or lacks some additional information - feel free to ask me.

Thank you in advance!

1 Like

While the base is the (total) ip range docker will manage, the size defines the netmask of a subnet for each single network that docker can create within the specified (total) ip range.

A 16 bit subnet will allow 65,534 usable ip’s (2 ips already subtracted for broadcast and network). A 20 bit subnet will allow 4,094 usable ip’s (again 2 ips already subtracted). Thus, sixteen 20 bit subnets are possible with a 16 bit subnet. The possible ip ranges double per bit, thus a difference of 20-16=4 allow 2^4 subnets.

1 Like

Hi @meyay

Thank you for the explanation.
Let me a bit rephrase and extend your answer to check if I correctly got the point.
For example, the setting

"default-address-pools": [
      {"base":"10.17.0.0/16","size":21}
]

will mean:

  1. The docker will be able to create up to 31 (+1 for docker0 interface = 32) networks via ‘docker create’. According to:
    /16 = 65534 hosts
    /21 = 2046 hosts
    65534/2046 = 32 or 2^(21-16) = 32

  2. The docker will assign to each of these created network the address from 10.17.[0-248].0 range. The [0-248] range because 248 is the highest bit of the ‘/21’ mask’s third octet (255.255.248.0).

  3. Each of these created networks will get a ‘/21’ (255.255.248.0) mask assigned, so every created network can have up to 8 subnetworks (according to /21 mask ).

For example, we have docker network 10.17.248.1 so this network will have addresses from the following pool: 10.17.[248-255].[0-254].
I.e the first 254 containers of that network will get 10.17.248.x addresses and the next 254 will get 10.17.249.x and so on until the subnetwork hosts are exhausted.
Similar examples for this case:
10.17.80.[0-254] - 10.17.87.[0-254]
10.17.120.[0-254] - 10.17.127.[0-254]

Following this logic we can sort out the ranges mentioned in my first reply: for /20 mask the range will be [0-240] (255.255.240.0) and we can create 16 docker networks each having 16 subnetworks and with this calculation, we will end up with 65534 maximum host number corresponding to /16 mask from the ‘base’ parameter.

Did I get it right?

1 Like

Seems about right :slight_smile:

I am not sure if docker0 is affected by this setting. It is responsible for the default bridge. If memory serves right, it shouldn’t be affected. You still might want to check if it is.

Not sure if it assignes the address sequentialy or randomly. This is still a single subnet, so who cares :slight_smile: Just to be on the safe side: for container to container communication always use the service name (thru build-in dns-based service discovery in user defined networks) and not container ips. While service names remain stable, container ips are ephemeral and will eventualy change.

Hi @meyay

Seems about right 

That’s good) thanks for your help to sort it out

I am not sure if docker0 is affected by this setting. It is responsible for the default bridge. If memory serves right, it shouldn’t be affected. You still might want to check if it is.

As far as my tests showed it was affected but I’ll re-check that once I fix my broken test installation :slight_smile:

Not sure if it assignes the address sequentialy or randomly. This is still a single subnet, so who cares

Agree :slight_smile:

Just to be on the safe side: for container to container communication always use the service name (thru build-in dns-based service discovery in user defined networks) and not container ips. While service names remain stable, container ips are ephemeral and will eventualy change.

Noted, thank you!

The definitive guide to docker's default-address-pools option in case it helps, I wrote a blog post on this subject that describes how the different netmasks interact with this option, what the default configuration is, how you would write a config to replicate it, and how to configure docker to accommodate a greater amount of much smaller networks.

1 Like