mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Destroy container along with processes before stdio
We need to make sure the container is destroyed before closing the stdio for the container. This becomes a big issues when running in the host's pid namespace because the other processes could have inherited the stdio of the initial process. The call to close will just block as they still have the io open. Calling destroy before closing io, especially in the host pid namespace will cause all additional processes to be killed in the container's cgroup. This will allow the io to be closed successfuly. This change makes sure the order for destroy and close is correct as well as ensuring that if any errors encoutered during start or exec will be handled by terminating the process and destroying the container. We cannot use defers here because we need to enforce the correct ordering on destroy. This also sets the subreaper setting for runc so that when running in pid host, runc can wait on the addiontal processes launched by the container, useful on destroy, but also good for reaping the additional processes that were launched. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
@@ -321,47 +321,76 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcont
|
||||
return factory.Create(id, config)
|
||||
}
|
||||
|
||||
// runProcess will create a new process in the specified container
|
||||
// by executing the process specified in the 'config'.
|
||||
func runProcess(container libcontainer.Container, config *specs.Process, listenFDs []*os.File, console string, pidFile string, detach bool) (int, error) {
|
||||
type runner struct {
|
||||
enableSubreaper bool
|
||||
shouldDestroy bool
|
||||
detach bool
|
||||
listenFDs []*os.File
|
||||
pidFile string
|
||||
console string
|
||||
container libcontainer.Container
|
||||
}
|
||||
|
||||
func (r *runner) run(config *specs.Process) (int, error) {
|
||||
process, err := newProcess(*config)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// Add extra file descriptors if needed
|
||||
if len(listenFDs) > 0 {
|
||||
process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(listenFDs)), "LISTEN_PID=1")
|
||||
process.ExtraFiles = append(process.ExtraFiles, listenFDs...)
|
||||
if len(r.listenFDs) > 0 {
|
||||
process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(r.listenFDs)), "LISTEN_PID=1")
|
||||
process.ExtraFiles = append(process.ExtraFiles, r.listenFDs...)
|
||||
}
|
||||
|
||||
rootuid, err := container.Config().HostUID()
|
||||
rootuid, err := r.container.Config().HostUID()
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
|
||||
tty, err := setupIO(process, rootuid, console, config.Terminal, detach)
|
||||
tty, err := setupIO(process, rootuid, r.console, config.Terminal, r.detach)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
defer tty.Close()
|
||||
handler := newSignalHandler(tty)
|
||||
defer handler.Close()
|
||||
if err := container.Start(process); err != nil {
|
||||
handler := newSignalHandler(tty, r.enableSubreaper)
|
||||
if err := r.container.Start(process); err != nil {
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
if err := tty.ClosePostStart(); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
if pidFile != "" {
|
||||
if err := createPidFile(pidFile, process); err != nil {
|
||||
process.Signal(syscall.SIGKILL)
|
||||
process.Wait()
|
||||
if r.pidFile != "" {
|
||||
if err := createPidFile(r.pidFile, process); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
if detach {
|
||||
if r.detach {
|
||||
tty.Close()
|
||||
return 0, nil
|
||||
}
|
||||
return handler.forward(process)
|
||||
status, err := handler.forward(process)
|
||||
if err != nil {
|
||||
r.terminate(process)
|
||||
}
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (r *runner) destroy() {
|
||||
if r.shouldDestroy {
|
||||
destroy(r.container)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) terminate(p *libcontainer.Process) {
|
||||
p.Signal(syscall.SIGKILL)
|
||||
p.Wait()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user