For details see moby/libnetwork#1113 or weaveworks/weave#2388 (comment)
Broadly, Setns() only affects the current Linux thread, but the Go runtime can create a new thread while you have changed namespace, so now any operation elsewhere in the program can suddenly switch to the other namespace as Go schedules goroutines onto the new thread.
The only safe thing to do seems to be to exec a new process to do nothing except the task we want to achieve in the alternate namespace, to call runtime.LockOSThread while doing the work, and then to exit the process.