Hi list,
Recently I've bumped into a problem when using the Linux network
namespaces in Go.
In my program I have the following function:
func do() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
netns.Set(containerNs)
defer netns.Set(hostNs)
doSomeStuff()
}
where netns.Set [1] changes the network namespace (does the setns(2)
syscall via syscall.Syscall). The problem with this function is that
during the execution of doSomeStuff() or defer netns.Set(hostNs) the
Go runtime might create a new OS thread (e.g. due to blocking) which
will reside in the same namespace as parent (CLONE_NEWNET is not set
when doing clone(2)). The newly created thread might be used for
scheduling other go-routines which will end up running in the "wrong"
namespace. As a consequence, the go-routines might not be able to
access some netdevs available within the host network namespace or
previously created sockets.
One workaround to this problem is to shell out a process (e.g. via
exec.Command) which would set the namespace and do doSomeStuff().
However, this approach is sort of ugly, because a) we create
unnecessary process; b) doSomeStuff() cannot be implemented in Go
without special hacks [2].
Considering a vast adoption of Go within containers software, it's a
bit odd that the runtime does not provide any means to address the
problem. Maybe I'm missing something?
[1]:
https://github.com/vishvananda/netns
[2]:
https://github.com/opencontainers/runc/tree/master/libcontainer/nsenter
Best,
Martynas