Libcontainer – 在容器中运行多个进程

huangapple go评论89阅读模式
英文:

Libcontainer - Running multiple processes in the container

问题

我正在尝试使用libcontainer实现类似于docker rundocker exec的功能。

我已经能够使用以下代码创建容器并在其中运行进程:

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)
}

这个代码运行得很好(我相信),但当我必须在同一个容器内运行另一个进程时,问题就出现了。例如,一个容器已经在运行(主进程以前台模式运行):我如何实现Docker中的docker exec功能?

我有以下代码:

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()

    // 重定向进程输出
    process.Stdout = writer
    process.Stderr = writer

    // 待修复:在开始之前等待主进程退出
    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)
}

这个代码也可以工作,但问题是:它在运行之前等待主进程退出。有时它会运行,但在调用该函数5-7次运行一个简单的whoami命令后,我的内存占用率达到了100%

我相当确定我做错了一些事情,只是不知道是什么。或者是我对容器的理解有问题?

我使用了这个项目作为参考:
https://github.com/opencontainers/runc

英文:

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

答案1

得分: 2

你可以参考Docker的代码,因为它在启动和在容器中执行新进程时使用相同的libcontainer.Container对象。你可以在这里找到与libcontainer交互的代码:
https://github.com/docker/docker/tree/master/daemon/execdriver/native

此外,最好发布完整的代码,这样其他人可以尝试并调试它来帮助你。

编辑:
这里有一个运行多个容器的示例代码:https://gist.github.com/anonymous/407eb530c0cb6c87ec9f

我像这样运行它:

go run procs.go path-to-busybox

你可以用ps命令看到容器中确实有多个进程。
如果有任何问题,请随时提问。

英文:

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.

huangapple
  • 本文由 发表于 2015年9月24日 01:38:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/32746026.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定