容器之间默认互相看不到进程,打开 shareProcessNamespace 之后会发生什么?pause 在这里多了什么职责?僵尸进程从哪来、谁来收?这篇用两个对照 Pod 把 ps、kill、僵尸和环境变量都实际跑一遍。
iso 的 side 容器里 ps:['1 S sleep 3601', '11 R ps -o pid,stat,args'] shared 的 side 容器里 ps:['1 S /pause', '7 S sleep 3600', '17 S sleep 3601', '27 R ps -o pid,stat,args'] shared 里的 PID 1 是 pause——pause 成了整个 Pod 的 init,容器进程的 PID 不再从 1 开始
对照 Pod iso(默认)和 shared(shareProcessNamespace: true),各有 app 和 side 两个容器。iso 的 side 里 ps 只有 PID 1 = sleep 3601 和 ps 自己;shared 的 side 里有 PID 1 = /pause、PID 7 = sleep 3600(app 容器的进程)、PID 17 = sleep 3601(自己)。pause 成了整个 Pod 的 init,容器进程的 PID 不再从 1 开始。
在 side 里通过 /proc/7/root 看 app 容器的根目录:bin dev etc home | sleep 3600 | lrwxrwxrwx 1 root root 0 Oct 10 17:27 /proc/7/cwd -> / 在 side 里 kill -TERM app 的 sleep 进程:app 容器 restartCount=1,lastState=['terminated'];side 的 restartCount=0(跨容器发信号可以,杀掉的容器会被 kubelet 按 restartPolicy 重启) 对照 iso 的 side 里对自己的 PID 1(sleep)kill -TERM:rc=0 / PID COMMAND / 1 sleep 3601;side 的 restartCount=0(没有被杀:容器里的 PID 1 对没有处理函数的信号默认忽略)
在 shared 的 side 里:/proc/7/root 能看到 app 容器的根目录,/proc/7/cwd 指向 /;kill -TERM 7 杀掉 app 的进程后,app 容器 restartCount=1(lastState terminated),side 仍是 0——跨容器发信号可行,被杀的容器由 kubelet 按 restartPolicy 重启。对照 iso 的 side 里对自己的 PID 1(sleep)kill -TERM:进程仍在,restartCount=0,容器里的 PID 1 对没有处理函数的信号默认忽略。
在 app 容器里启动 5 个“孤儿”短命进程(父进程立刻退出,孤儿被 PID 1 收养,结束后需要 PID 1 来 wait):
iso(PID 1 是 sleep,不会 wait):僵尸进程 5 个;PID 1 是 sleep
shared(PID 1 是 pause,会 wait):僵尸进程 0 个;PID 1 是 pause
iso 里的僵尸:['18 Z [sh]', '20 Z [sh]', '22 Z [sh]']在 app 容器里起 5 个“孤儿”短命进程(父进程立刻退出,孤儿被 PID 1 收养,结束后需要 PID 1 去 wait):iso 里 PID 1 是 sleep,不会 wait,留下 5 个僵尸(ps 里 Z 状态的 [sh]);shared 里 PID 1 是 pause,会回收,僵尸 0 个。共享 PID 命名空间的一个附带好处,是 pause 当了 init。
Pod spec.shareProcessNamespace=true 容器重启后 PID 会变:app 重启前 sleep 3600 的 PID 是 7,重启后是 ['62'] 从 side 读 app 的 /proc/62/environ:'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=shared KUBERNET'(同一用户 root,可以读;非 root 或不同 UID 的容器会被拒)
app 容器重启后 sleep 3600 的 PID 从 7 变成 62——PID 不稳定,脚本里不要写死。side 能读 app 的 /proc/62/environ,拿到 PATH、HOSTNAME=shared 等环境变量(两者都是 root);放在环境变量里的密码在共享进程命名空间下更容易被邻居容器读到。