I am trying to implement something to the effect of docker run
and docker exec
using libcontainer
.
I have been able to create a container and run a process inside it with the following code:
func Run(id string, s *specs.LinuxSpec, f *Factory) (int, error) {
...
container, err := f.CreateContainer(id, config)
if err != nil {
return -1, err
}
process := newProcess(s.Process)
tty, err := newTty(s.Process.Terminal, process, rootuid)
defer tty.Close()
if err != nil {
return -1, err
}
defer func() {
if derr := Destroy(container); derr != nil {
err = derr
}
}()
handler := NewSignalHandler(tty)
defer handler.Close()
if err := container.Start(process); err != nil {
return -1, err
}
return handler.forward(process)
}
This works great (I believe), but the problem comes when I have to run another process(es) inside the same container. For example, a container is already running (the main process is running in foreground mode): How can I achieve what Docker allows you to do with docker exec
?
I have the following code:
func Exec(container libcontainer.Container, process *libcontainer.Process, onData func(data []byte), onErr func(err error)) (int, error) {
reader, writer := io.Pipe()
process.Stdin = os.Stdin
rootuid, err := container.Config().HostUID()
if err != nil {
return -1, err
}
tty, err := newTty(true, process, rootuid)
defer tty.Close()
if err != nil {
return -1, err
}
handler := NewSignalHandler(tty)
defer handler.Close()
// Redirect process output
process.Stdout = writer
process.Stderr = writer
// Todo: Fix this, it waits for the main process to exit before it starts
if err := container.Start(process); err != nil {
return -1, err
}
go func(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
onData(scanner.Bytes())
}
if err := scanner.Err(); err != nil {
onErr(err)
}
}(reader)
return handler.forward(process)
}
This also works, but the problem is: It waits for the main process to exit before it runs. Sometimes it runs, but my memory goes to 100%
after calling that function 5 - 7 times running a simple whoami
command.
I'm pretty sure I am doing something(s) wrong, I just don't know what. Or is my understanding of containers failing me?
I used this project as a reference: https://github.com/opencontainers/runc
It's probably better to use docker as reference for your case, because it uses same libcontainer.Container
objects for starting and exec new process in container. You can find code interacting with libcontainer here: https://github.com/docker/docker/tree/master/daemon/execdriver/native
Also it's better to post whole code, so people could try and debug it to help you.
EDIT: Here is example code for running multiple containers: https://gist.github.com/anonymous/407eb530c0cb6c87ec9f
I runned it like
go run procs.go path-to-busybox
You can see with ps
that there are indeed multiple processes in container. Feel free to ask if you have any questions.