compose: The order in which networks are assigned to interfaces does not match the order they are listed in compose file

The following report was produced using Docker version 17.03.0-ce and compose version docker-compose version 1.11.2, build dfed245.

Given a docker-compose.yml that looks like this:

version: "2"

services:
  server:
    image: alpine
    command: sleep 999
    networks:
      - nw0
      - nw1
      - nw2
      - nw3

networks:
  nw0:
  nw1:
  nw2:
  nw3:

I would expect the networks to be assigned to interface in order, such that eth0 is attached to nw0, eth1 is attached to nw1, etc. This is exactly the behavior I see if I start a container using docker run and then attach additional networks with docker network connect.

However, when using docker-compose and the above compose file, the ordering of networks and interfaces appears to be inconsistent. Assuming that the above compose file is in a directory named nwtest, this script will demonstrate the problem:


#!/bin/sh

docker-compose up -d

for nw in 0 1 2 3; do
	nw_cidr=$(docker network inspect -f '{{ (index .IPAM.Config 0).Subnet }}' \
		nwtest_nw${nw})
	if_cidr=$(docker exec -it nwtest_server_1 ip addr show eth${nw} |
		awk '$1 == "inet" {print $2}')

	nw_net=$(ipcalc -n $nw_cidr | cut -f2 -d=)
	if_net=$(ipcalc -n $if_cidr | cut -f2 -d=)

	echo "nw${nw} $nw_net eth${nw} ${if_net}"

	if [ "$if_net" != "$nw_net" ]; then
		echo "MISMATCH: nw${nw} = $nw_net, eth${nw} = $if_net" >&2
	fi
done

docker-compose stop

On my system, that produces as output:

Starting nwtest_server_1
nw0 192.168.32.0 eth0 192.168.32.0
nw1 192.168.48.0 eth1 192.168.48.0
nw2 192.168.64.0 eth2 192.168.80.0
MISMATCH: nw2 = 192.168.64.0, eth2 = 192.168.80.0
nw3 192.168.80.0 eth3 192.168.64.0
MISMATCH: nw3 = 192.168.80.0, eth3 = 192.168.64.0
Stopping nwtest_server_1 ... done

For comparison, here is a script that performs the same test using docker run and manual attachment:

#!/bin/sh

docker rm -f nwtest_server_1
docker run -d --name nwtest_server_1 --network nwtest_nw0 \
	alpine sleep 999

for nw in 1 2 3; do
	docker network connect nwtest_nw${nw} nwtest_server_1
done

for nw in 0 1 2 3; do
	nw_cidr=$(docker network inspect -f '{{ (index .IPAM.Config 0).Subnet }}' \
		nwtest_nw${nw})
	if_cidr=$(docker exec -it nwtest_server_1 ip addr show eth${nw} |
		awk '$1 == "inet" {print $2}')

	nw_net=$(ipcalc -n $nw_cidr | cut -f2 -d=)
	if_net=$(ipcalc -n $if_cidr | cut -f2 -d=)

	echo "nw${nw} $nw_net eth${nw} ${if_net}"

	if [ "$if_net" != "$nw_net" ]; then
		echo "MISMATCH: nw${nw} = $nw_net, eth${nw} = $if_net" >&2
	fi
done

docker rm -f nwtest_server_1

This always runs without error.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 8
  • Comments: 15

Most upvoted comments

+1 form me as well. Editing my response to add some details. I thought about what @johnharris85 mentioned, so I numbered my network names in the order I want them to be connected and I can get around the issue for now.

For example part of my compose looks like this: networks: – 1firstnw – 2nw – 3nw

Hope this helps someone.

@gentunian after looking at the code, I don’t see any difference in handling network priorities between v2 and v3. See https://github.com/docker/compose/blob/master/compose/network.py#L325, and PR docker/compose#5566 clearly show that v3 is ok since at least jan 2018…

however, a rapid test shows that priorities are currently ignored by docker, would you choose v2 or v3… lexical order of network names seems to be overriding the priorities you set. see https://gist.github.com/jfellus/cfee9efc1e8e1baf9d15314f16a46eca

(the answer to this may also answer https://github.com/docker/cli/issues/1372)