But the point still stands... you get a subset of the OS API. Everything has to be "canned" into that struct and you can't execute arbitrary code between fork and exec.
Especially with containers, this is a never-ending target... They apparently have user namespaces, but what about network namespaces or IPC namespaces?
[1] https://golang.org/src/syscall/exec_linux.go
Now, it might be good enough for your application, and it probably IS good enough for everything except a full-fledged production quality init system. For that case I would be worried about running into limitations.
There's no reason calls to e.g. unshare(2) and setns(2) can't be added to forkAndExecInChild in exec_linux.go like they have been added for the other syscalls needed to set up a child. I guess if anyone is reading this thread and wants that they can follow the guidelines for contributions and look at https://github.com/golang/go/issues/5968
EDIT: It's also possible to supply CloneFlags though the SysProcAttr struct, e.g., CLONE_NEWIPC, CLONE_NEWNET.
Also, the subject's been raised before, and regrettably (IMO) the proposal rejected. As a result, you'll find a nontrivial amount of C appearing in e.g. the runc project. (Which is a crying shame, because it invoking cgo means runc ceased to be trivially reproducibly buildable, last time I checked...)
Attached simple demo code of what I mean with ForkExec, Wait4.
EDIT: to clarify, the demo code is not intended to work like init, just to spawn a couple of processes and wait for them to terminate.