Docker - network sharing
One of the lesser known options of networking in Docker is sharing of network namespaces. In a bit clearer terms - a situation where 2 (or more) containers from a user point of view use the same “virtual” network interface.
It’s not surprising that this option is not widely used - most of the times ability to bind any port in the container to a host port covers intended use case.
So when this becomes useful? Personally I’ve come across this when I’ve been working with a networks that used Tailscale or Netbird. I really needed a service to use the same network interface that Tailscale / Netbird did and at the same time I couldn’t simply do network_mode: host
as the ports I’ve needed were already taken.
Macvlan with additional options that are available through network_mode
saved the day - as they allow specifying the name of a service / container which network interface we’d like to “borrow”. Simply write it down instead of host
(which you’re probably more used to):
network_mode: service:<SERVICE_NAME>
Here’s a simple example to test it (dropping macvlan settings to make it clearer):
networks:
shared-net:
services:
nginx1:
container_name: nginx1
image: nginx:latest
environment:
- NGINX_PORT=6080
- SERVER_NAME=nginx1
networks:
- shared-net
volumes:
- ./nginx-conf.template:/etc/nginx/conf.d/nginx-conf.template
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/nginx-conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
nginx2:
container_name: nginx2
image: nginx:latest
environment:
- NGINX_PORT=7080
- SERVER_NAME=nginx2
network_mode: service:nginx1
volumes:
- ./nginx-conf.template:/etc/nginx/conf.d/nginx-conf.template
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/nginx-conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
In this case nginx2
container uses nginx1
service network interface.
To run this example an additional template file for nginx config is needed. It can look like this:
server {
listen ${NGINX_PORT};
listen [::]:${NGINX_PORT};
server_name ${SERVER_NAME};
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
After starting the containers via docker compose up -d
you can open bash in one of them by:
docker container exec -it nginx2 bash
Then use curl
to check whether you have nginx on localhost
port 6080 (from nginx1) and 7080 (from nginx2):
curl http://localhost:6080
curl http://localhost:7080
Actually inspecting the config with docker container inspect
on the host system gives even better info:
docker container inspect nginx2
“NetworkMode” and “NetworkSettings” section of the output are work checking out. In my case the first one contained:
"NetworkMode": "container:cd15bb65e8af98ab0a383269277b7e3710b3d85189869742202884cce4f46f66"
While the second one had empty / null entries - which more definitively illustrates that nginx2 does not have its own network interface.
Links
https://docs.docker.com/reference/compose-file/services/
https://docs.docker.com/reference/compose-file/services/#network_mode