Ver Fonte

add zombie check for container when killing it, alernative fix for #40735.

Signed-off-by: 屈骏 <qujun@tiduyun.com>
屈骏 há 5 anos atrás
pai
commit
f3c1eec99e
2 ficheiros alterados com 35 adições e 0 exclusões
  1. 15 0
      daemon/container_operations_unix.go
  2. 20 0
      pkg/system/process_unix.go

+ 15 - 0
daemon/container_operations_unix.go

@@ -17,6 +17,7 @@ import (
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/libnetwork"
 	"github.com/opencontainers/selinux/go-selinux/label"
@@ -353,6 +354,20 @@ func killProcessDirectly(cntr *container.Container) error {
 				logrus.Debug(e)
 				return e
 			}
+
+			// In case there were some exceptions(e.g., state of zombie and D)
+			if system.IsProcessAlive(pid) {
+
+				// Since we can not kill a zombie pid, add zombie check here
+				isZombie, err := system.IsProcessZombie(pid)
+				if err != nil {
+					logrus.Warnf("Container %s state is invalid", stringid.TruncateID(cntr.ID))
+					return err
+				}
+				if isZombie {
+					return errdefs.System(errors.Errorf("container %s PID %d is zombie and can not be killed. Use the --init option when creating containers to run an init inside the container that forwards signals and reaps processes", stringid.TruncateID(cntr.ID), pid))
+				}
+			}
 		}
 	}
 	return nil

+ 20 - 0
pkg/system/process_unix.go

@@ -3,6 +3,9 @@
 package system // import "github.com/docker/docker/pkg/system"
 
 import (
+	"fmt"
+	"io/ioutil"
+	"strings"
 	"syscall"
 
 	"golang.org/x/sys/unix"
@@ -22,3 +25,20 @@ func IsProcessAlive(pid int) bool {
 func KillProcess(pid int) {
 	unix.Kill(pid, unix.SIGKILL)
 }
+
+// IsProcessZombie return true if process has a state with "Z"
+// http://man7.org/linux/man-pages/man5/proc.5.html
+func IsProcessZombie(pid int) (bool, error) {
+	statPath := fmt.Sprintf("/proc/%d/stat", pid)
+	dataBytes, err := ioutil.ReadFile(statPath)
+	if err != nil {
+		return false, err
+	}
+	data := string(dataBytes)
+	sdata := strings.SplitN(data, " ", 4)
+	if len(sdata) >= 3 && sdata[2] == "Z" {
+		return true, nil
+	}
+
+	return false, nil
+}