-
Notifications
You must be signed in to change notification settings - Fork 18.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Running docker containers in existing network namespace (netns) #47828
Comments
If you modify the process in option 3 a bit, I think you can get what you want. We're going to leave the bridge in the global namespace (which may even be necessary for the bridge to function properly, but don't quote me on that), but that's okay! A bridge is a layer 2 device and doesn't really care about ip addresses. We're going to create the bridge without an ip address, like this:
That gets us a new network:
And a bridge without an ip address:
If we start a container on this network, it will have a default route:
But the route won't go anywhere, because the gateway address hasn't been assigned to anything yet:
This is everything we need. Create a new namespace running openvpn, then create a
Now our container has a functioning default gateway:
Set up the routing table and netfilter rules inside the
Note that you will either need to add some additional networking to the Here's a visual of what you get:
PS: I hadn't looked at this in a number of year; I'm actually quite happy with this solution. The ability co create the bridge but not configure an address on it opens up a lot of flexibility. |
@larsks Thanks a lot, you pointed me in the right direction. Two things to add:
DebuggingPinging the ip address of the veth pair worked correctly from inside a container in my custom network, but pinging 8.8.8.8 was not working. Once everything was configured, my routing table on vpn0 looked like this:
If I run a ping to the internet on this netns, it works correctly.
Now, I would like to make a ping to the internet (8.8.8.8) from inside an new docker container using the vpn0net network.
This, however, does not work. I don't receive a response. Running tcpdump again will show:
So I needed to add a masquerading rule in my netns:
And then the ping works and tcpdump shows:
SolutionAssuming we already have a netns named
|
I'm still leaving this issue open as it would be easier, more secure and probably more efficient if docker allowed us to set the bridge directly inside our netns with a bridge network driver option. |
Right, that's expected. If it make things easier you can set a static network range using the
That would be the "Set up the routing table and netfilter rules inside the openvpn namespace as you see fit" step that I mentioned :). |
@zackherbert would you mind also sharing the integration of you solution inside docker compose? It would be very valuable to me.
|
Description
It should be possible and easy (and documented) to run docker containers in an existing network namespace (netns) on Linux.
There were some previous attempts made to solve this previously, which were rejected without providing an adequate alternative for the users.
Use case:
Simplest example:
Let's say we already have a vpn configured inside the
vpn0
netns we created.Running
curl ip.me
printsisp-ip-address
Running
sudo ip netns exec vpn0 curl ip.me
printsvpn-ip-address
To test if a container is behind the vpn, we can use this simple Dockerfile:
Building the container
docker build -t ip-fetcher-simple
,then running the container
docker run --rm ip-fetcher-simple
, will printisp-ip-address
If we try to run the container in the vpn0 netns, with
sudo ip netns exec vpn0 docker run --rm ip-fetcher-simple
, it still printsisp-ip-address
That's because it's the dockerd daemon which is responsible to create the network bridge and container network namespace and it still use the "default" one because it was started on that "default" netns.
Alternative 1 - select netns inside container
One way to solve this is to select the vpn0 netns INSIDE the container.
Our Dockerfile looks like this now:
Building
docker build -t ip-fetcher
,Running:
docker run --privileged --rm --volume /var/run/netns:/var/run/netns:ro --volume /etc/netns/vpn0/resolv.conf:/etc/resolv.conf:ro ip-fetcher
And now it prints the
vpn-ip-address
correctly.CONS:
--privileged
Alternative 2 - Setting dockerd in the vpn0 netns
It is apparently possible if you're using systemd to set the dockerd daemon in your created netns.
Stop docker:
Edit docker.service using
systemctl edit docker.service
, to ensure that updates will not overwrite your changes, with:Then reload systemd services and restart docker:
In theory, running the simple-ip-fetcher container above should return
vpn-ip-address
In my case though (On Ubuntu 22.04 with systemd 249 (249.11-0ubuntu3.12)), it was not working.
Building the container works but trying to run my container will generate the following error:
And I would find in the system logs errors like this:
The StackOverflow answer points to a possible misconfiguration between dockerd and containerd, but the
/var/run/docker/containerd/containerd.toml
does not exist on my system, so I'm stuck.CONS:
Alternative 3: create you own custom docker network bridge and try to set its link inside your netns
Creating a custom network and running the container works and gives out the
isp-ip-address
as expected:ip link will return something like this:
Now if I now try to move the vpn0bridge link inside the vpn0 netns, it does not work. I have the following error:
It seems that it might be possible, with complex iptables magic, to redirect all traffic going through a custom bridge to our vpn gateway, but it seems fickle and potentially still expose the user to the dhcp vulnerability in the use case above.
Alternative 4:
Apparently we can use plugins in github.com/docker/libnetwork.
As far as I know, no documentation exists to show on how to do this.
If this is possible, an easy step by step guide should be added to the docker networking tutorials
Alternative 5:
Once your containers are started, you can find out which netns is used by docker for each one
And then you can use
nsenter
orip netns exec
, create veth pairs and move one of them in the vpn0 netns, modifying the routing tables as needed.This alternative is not acceptable as the containers are already started before we modify the routing.
Proposition
All this is way too complicated / not working for a feature which should have been already supported by docker ages ago to allow user to better compartmentalize and secure container networks on Linux.
A possible elegant way to solve this would be to add a
com.docker.network.bridge.netns
option to the bridge driver optionsThis would allow the user to create a new docker network with
docker network create --opt com.docker.network.bridge.netns=vpn0 --opt com.docker.network.bridge.name=vpn0bridge vpn0net
or even allow to configure the default bridge with a new
netns
json key in thedaemon.json
file.The text was updated successfully, but these errors were encountered: