为什么杀死pod的pause进程业务容器也会退出,杀死业务进程 pause 进程却不退出?它们都是shim的子进程,区别在哪?

一个pod进程关系如图

root 163187 0.0 0.1 712460 12828 pts/2 Sl 21:40 0:00 \_ /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id e7927073fe3617c5cfd587c17bd5b9a98131a
root 163209 0.0 0.0 1028 4 ? Ss 21:40 0:00 | \_ /pause
root 163242 0.0 0.0 1332 4 ? Ss 21:40 0:00 | \_ top  

进入容器内 进程关系如图

[root@localhost pod]# nerdctl -n k8s.io  exec -it e76 sh
/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    7 root      0:00 top
   38 root      0:00 sh
   44 root      0:00 ps -ef

  1号进程的父id是0 也就是shim

/ # cat /proc/1/status |grep -i ppid
PPid:   0

  7号业务进程的父亲进程是0 也就是shim (说明它不是1号进程的后代)

/ # cat /proc/7/status |grep -i ppid
PPid:   0

  cat /run/containerd/io.containerd.runtime.v2.task/k8s.io/8efdde181c87bf3cbecfd0282218372106a4c6258284bc7c9ca8ddbf2f4f4e5b/config.json|jq 查看runc配置文件

业务的
    "namespaces": [
      {
        "type": "pid",
        "path": "/proc/187682/ns/pid"
      },
      {
        "type": "ipc",
        "path": "/proc/187682/ns/ipc"
      },
      {
        "type": "uts",
        "path": "/proc/187682/ns/uts"
      },
      {
        "type": "mount"
      },
      {
        "type": "network",
        "path": "/proc/187682/ns/net"
      }
    ]

pause的
        "namespaces": [
      {
        "type": "pid"
      },
      {
        "type": "ipc"
      },
      {
        "type": "uts"
      },
      {
        "type": "mount"
      },
      {
        "type": "network",
        "path": "/var/run/netns/cni-8a9bc5d1-491d-a07f-7465-3d17b37bee51"
      }
    ]

对比发现pause的没有 "pid" 没有path路径

shim代码如下

// ShouldKillAllOnExit reads the bundle's OCI spec and returns true if
// there is an error reading the spec or if the container has a private PID namespace
func ShouldKillAllOnExit(ctx context.Context, bundlePath string) bool {
    var bundleSpec specs.Spec
    bundleConfigContents, err := os.ReadFile(filepath.Join(bundlePath, "config.json"))
    if err != nil {
        log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to read config.json")
        return true
    }
    if err := json.Unmarshal(bundleConfigContents, &bundleSpec); err != nil {
        log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to unmarshal bundle json")
        return true
    }
    if bundleSpec.Linux != nil {
        for _, ns := range bundleSpec.Linux.Namespaces {
            if ns.Type == specs.PIDNamespace && ns.Path == "" {
                return false
            }
        }
    }
    return true
}

所以是pause容器的时候返回false(共享pid命名空间,不带路径),业务容器返回true(私有pid命名空间,带了路径)

            if ip, ok := p.(*process.Init); ok {// Ensure all children are killed
                if runc.ShouldKillAllOnExit(s.context, container.Bundle) {
           if err := ip.KillAll(s.context); err != nil { logrus.WithError(err).WithField("id", ip.ID()). Error("failed to kill init's children") } }

所以上边代码会kill掉业务容器,忽略掉pause容器

root      186449  0.0  0.1 712460 10140 pts/4    Sl   01:24   0:00  \_ /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 7bc44216dfa430195653661661e06d42c7a15
root      186470  0.0  0.0   1028     4 ?        Ss   01:24   0:00      \_ /pause
kill 杀死业务容器, pause容器仍然存活
posted @ 2022-11-11 11:34  rincloud  阅读(155)  评论(0)    收藏  举报