英文:
Libcontainer - Running multiple processes in the container
问题
我正在尝试使用libcontainer
实现类似于docker run
和docker 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论