Docker networking with dedicated network containers
The current version of Docker has a very limited set of networking options:
bridge
– connect a container to the Docker bridgehost
– run the container in the global network namespacecontainer:xxx
– connect a container to the network namespace of another containernone
– do not configure any networking
If you need something more than that, you can use a tool like
pipework to provision additional network interfaces inside the
container, but this leads to a synchronization problem: pipework
can
only be used after your container is running. This means that when
starting your container, you must have logic that will wait until the
necessary networking is available before starting your service.
The kubernetes project uses a clever solution to this problem:
Begin by starting a no-op container – that is, a container that does
not run any services – with --net=none
. It needs to run
something; otherwise it will exit. The kubernetes/pause
image
implements an extremely minimal “do nothing but wait” solution.
Once you have this no-op container running, you can set up the
corresponding network namespace to meet your requirements. For
example, you can create a veth
device pair and place one end in the
interface and attach another to a bridge on your system. Pipework
can help with this, but you can also perform all the changes by
hand
Once your networking is configured, start your actual service
container with --net=container:<id-of-noop-container>
. Your service
container will start with your configured network environment.
You could, I suppose, decide to link every service container with it’s own network container, but that would get messy. Kubernetes groups containers together into “pods”, in which all containers in a pod share the same network namespace, which reduces the number of “networking containers” necessary for services that have the same networking requirements.
This solution – linking your service container with a no-op container used to implement networking – solves the problems identified at the beginning of this post: because you can perform all your network configuration prior to starting your service, your service container does not need any special logic to deal with interfaces that will be created after the container starts. The networking will already be in place when the service starts.
Docker issue 7455 proposes a docker-native solution that would
accomplish largely the same thing without requiring the separate
networking container (by permitting you to pre-configure a network
namespace and then pass that to docker using something like
--net=netns:<name-of-network-namespace>
).