K8s在创建Pod时,先创建Pause容器,然后以Pause的network namespaces为基础,创建Pod内的业务容器,这样Pod内的所有容器就共享了同一个network namespaces,同一个POD内的容器可以通过的localhost访问。

    • 在Pod中,它作为共享Linux NameSpace (Network, UTS等)的基础;
    • 启用PID namespace 共享,它为每个Pod提供1号进程,并收集Pod内的僵尸进程。

    它扮演PID 1的角色,并在子进程成为“孤儿进程”的时候,通过调用wait()收割这些僵尸子进程。这样就不用担心我们的Pod的PID namespace里会堆满僵尸进程了。这也是为什么Kubernetes不随便找个容器(例如Nginx)作为父容器,让用户容器加入的原因。

    在UNIX系统中,PID为1的进程是init进程,即所有进程的父进程。init进程比较特殊,它维护一张进程表并且不断地检查其他进程的状态。init进程的其中一个作用是当某个子进程由于父进程的错误退出而变成了“孤儿进程”,便会被init进程“收养”并在该进程退出时回收资源。

    在UNIX系统中,PID为1的进程是init进程,即所有进程的父进程。init进程比较特殊,它维护一张进程表并且不断地检查其他进程的状态。init进程的其中一个作用是当某个子进程由于父进程的错误退出而变成了“孤儿进程”,便会被init进程“收养”并在该进程退出时回收资源。进程可以使用fork和exec两个系统调用启动其他进程。当启动了其他进程后,新进程的父进程就是调用fork系统调用的进程。fork用于启动正在运行的进程的另一个副本,而exec则用于启动不同的进程。每个进程在操作系统进程表中都有一个条目。这将记录有关进程的状态和退出代码。当子进程运行完成后,它的进程表条目仍然保留,直到父进程使用wait系统调用获得其退出代码后才会清理进程条目。这被称为“收割”僵尸进程,并且僵尸进程无法通过kill命令清除。

    僵尸进程是已停止运行但进程表条目仍然存在的进程,父进程尚未通过wait系统调用进行检索。从技术层面来说,终止的每个进程都算是一个僵尸进程,尽管只是在很短的时间内发生的。当用户程序写得不好并且简单地省略wait系统调用,或者当父进程在子进程之前异常退出并且新的父进程没有调用wait检索子进程时,会出现较长时间的僵尸进程。系统中存在过多僵尸进程将占用大量操作系统进程表资源。

    当进程的父进程在子进程完成前退出时,OS将子进程分配给init进程。init进程“收养”子进程并成为其父进程。这意味着当子进程退出时,新的父进程(init进程)必须调用wait获取其退出代码,否则其进程表项将一直保留,并且它也将成为一个僵尸进程。同时,init进程必须拥有“信号屏蔽”功能,不能处理某个信号逻辑,从而防止init进程被误杀。所以不是随随便便一个进程都能当init进程的。

    容器使用PID namespace对PID进行隔离,因此每个容器中均可以有独立的init进程。当在主机上发送SIGKILL或者SIGSTOP(也就是docker kill或者docker stop命令)强制终止容器的运行时,其实就是在终止容器内的init进程。一旦init进程被销毁,同一PID namespace下的进程也随之被销毁。

    在容器中,必须要有一个进程充当每个PID namespace的init进程,使用Docker的话,ENTRYPOINT进程是init进程。如果多个容器之间共享PID namespace,那么拥有PID namespace的那个进程须承担init进程的角色,其他容器则作为init进程的子进程添加到PID namespace中。