Jelajahi Sumber

Get process list after PID 1 dead

Fix #11087

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Alexander Morozov 10 tahun lalu
induk
melakukan
ac8bd12b39
2 mengubah file dengan 54 tambahan dan 15 penghapusan
  1. 29 15
      daemon/execdriver/native/driver.go
  2. 25 0
      integration-cli/docker_cli_run_test.go

+ 29 - 15
daemon/execdriver/native/driver.go

@@ -188,6 +188,34 @@ func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
 	return oom
 }
 
+func killCgroupProcs(c libcontainer.Container) {
+	var procs []*os.Process
+	if err := c.Pause(); err != nil {
+		logrus.Warn(err)
+	}
+	pids, err := c.Processes()
+	if err != nil {
+		// don't care about childs if we can't get them, this is mostly because cgroup already deleted
+		logrus.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
+	}
+	for _, pid := range pids {
+		if p, err := os.FindProcess(pid); err == nil {
+			procs = append(procs, p)
+			if err := p.Kill(); err != nil {
+				logrus.Warn(err)
+			}
+		}
+	}
+	if err := c.Resume(); err != nil {
+		logrus.Warn(err)
+	}
+	for _, p := range procs {
+		if _, err := p.Wait(); err != nil {
+			logrus.Warn(err)
+		}
+	}
+}
+
 func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
 	return func() (*os.ProcessState, error) {
 		pid, err := p.Pid()
@@ -195,8 +223,6 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
 			return nil, err
 		}
 
-		processes, err := c.Processes()
-
 		process, err := os.FindProcess(pid)
 		s, err := process.Wait()
 		if err != nil {
@@ -206,19 +232,7 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
 			}
 			s = execErr.ProcessState
 		}
-		if err != nil {
-			return s, err
-		}
-
-		for _, pid := range processes {
-			process, err := os.FindProcess(pid)
-			if err != nil {
-				logrus.Errorf("Failed to kill process: %d", pid)
-				continue
-			}
-			process.Kill()
-		}
-
+		killCgroupProcs(c)
 		p.Wait()
 		return s, err
 	}

+ 25 - 0
integration-cli/docker_cli_run_test.go

@@ -3468,3 +3468,28 @@ func TestRunContainerWithRmFlagCannotStartContainer(t *testing.T) {
 
 	logDone("run - container is removed if run with --rm and cannot start")
 }
+
+func TestRunPidHostWithChildIsKillable(t *testing.T) {
+	defer deleteAllContainers()
+	name := "ibuildthecloud"
+	if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil {
+		t.Fatal(err, out)
+	}
+	time.Sleep(1 * time.Second)
+	errchan := make(chan error)
+	go func() {
+		if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil {
+			errchan <- fmt.Errorf("%v:\n%s", err, out)
+		}
+		close(errchan)
+	}()
+	select {
+	case err := <-errchan:
+		if err != nil {
+			t.Fatal(err)
+		}
+	case <-time.After(5 * time.Second):
+		t.Fatal("Kill container timed out")
+	}
+	logDone("run - can kill container with pid-host and some childs of pid 1")
+}