最近看了一下 k8s 的 pause 容器,让我重新梳理了一下 pid namespace。

pid namespace 用于隔离进程,意思就是可以用 pid namespace 对进程进行分组管理,那么不同的进程就可以被放入不同的 namespace 分组中去。linux 系统启动后,默认创建了第一个 namespace,此时的所有进程都位于在这个 namespace 中,所以 ps 命令才能够查看到所有的进程。

pid namespace 是有父子嵌套关系的,当我们创建一个新的子进程的时候,完全可以同时为这个子进程分配一个新的 namespace,这个时候就会出现父子进程在不同的 namespace 中,但两个 namespace 也是父子的嵌套关系。大概是如下这样的一个关系:

目前,真实的容器环境一般来说只有两层 namespace,第一层就是系统初始化默认的,第二层就是每个容器所创建的 namespace,很少有2层以上的实际场景,目前我好像还没遇到。上图展示的最深是 3 层。

pid namespace 隔离的是进程,是对进程进行的分组管理,这个分组隔离的具体内容其实是进程间的可见性,简单的说就是属于同一个 pid namespace 中的进程相互是可见的,注意这里可见的意思是『进程之间相互可以看到对方,也可以使用 syscall 操作对方,比如发送信号等』。进程除了对相同 pid namespace 中的其他进程可见以外,其实对它的祖先 pid namespace 中的进程也是可见的,这就是为什么我们在 linux 宿主机上 ps 可以看到所有的进程,包括每个 docker 容器中的进程,在宿主机上也可以使用 kill 命令杀死每个 docker 容器中的进程。

pid namespace 除了有进程分组隔离的作用外,还有一个大家都知道的特性,就是一个 pid namespace 中的第一个被创建的进程 pid 是 1,通常也称这个进程为 init 进程。这个特性不难理解,一个 pid namespace 就是一个全新的、独立的 pid 分配环境,那么 pid 的分配自然是从 1 开始了。在 linux 系统上,1 号进程是特殊的,它不会被同 pid namespace 内的其他进程杀死,即使是 kill -9 也不行,这样的设计是为了防止误操作杀掉 1 号进程;但是容器内的 1 号进程是可以被父 pid namespace 中的进程杀死的,这样一来内核将会同时杀掉整个 namespace 内的其他进程,也就说 1 号进程挂掉后,其整个 namespace 内的进程都会被内核 kill 掉。

1 号进程还有一个能力,就是能够接管孤儿进程,成为孤儿进程的父进程。这一点很重要,否则系统里就会出现非常多的僵死进程了。

不难发现,一个进程有唯一的一个 pid 这种说法是不正确的,必须加上 pid namespace 这个维度才正确。也就是说,在一个固定的 pid namespace 内,一个进程有唯一的一个 pid,在多个 pid namespace 中,同一个进程就可能有不同的 pid 了。

基于上面的总结,再谈一下 k8s pod 中的 pause 容器。设计这个 pause 容器的核心是解决 pod 中多个容器相互共享 namespace 的问题,也就是 k8s 创建 pod 的时候会先创建一个 pause 容器,然后再创建其他应用容器并将相关的 namespace 和 pause 共享。那么,k8s 为什么不设计成去掉 pause 容器,然后按某个顺序启动应用容器,把第一个应用容器作为标准,后面的应用容器和第一个应用容器共享 namespace 呢?这样也是可以达到共享 namespace,实现 pod 本地通信等功能。

我认为至少有以下几点:

1. 引入 pause 容器的设计更加优雅一点,至少遵循了一个模块、一个组件干一件事情的原则,角色上划分比较清晰明了。

2. k8s pod 采用多容器设计,也就是多进程设计,因此 namespace 中的第一个进程就必须足够稳定,不会轻易退出。上文提到,1 号进程挂掉,会导致整个 namespace 的进程被内核杀死的。所以,pause 进程的源码非常的简单。

3. 应用容器内的进程完全有可能出现孤儿进程,这些孤儿进程最终会被 1 号进程接管,也就是成为 1 号进程的子进程,那么最终 1 号进程就需要负责回收孤儿进程的退出状态。如果这个 1 号进程不是 pause,而是一个应用容器内的应用进程的话,就有可能不能正常的处理退出信号回收子进程。因为,应用进程有可能并没有处理 SIGCHLD 信号;也可能采用了特殊的逻辑去处理,而不是单纯的 wait or wait_pid,比如:nginx master。

所以,k8s pod 要设计一个独立的 pause 容器。


个人文章优先发表在『专治好奇』知识星球。

推荐阅读:

相关文章