之前有文章讨论了僵尸进程,以及脚本中出现僵尸进程时候,主进程调用wait可以一定程度上避免出现僵尸进程。但是我发现,并不是在调用完wait后,僵尸进程就一定不会存在了。
参考:github.com/milvus-io/m…
那么如何在k8s环境中,避免僵尸进程的出现呢?
本文提出两种方案来避免僵尸进程的出现。
僵尸进程产生的原理
参考:juejin.cn/post/728895…
一:操作系统中
实际上,任何一个进程都会存在僵尸进程阶段,只不过,如下两种情况就可以避免僵尸进程出现:
- 情况1:
如果父进程还存在,但是父进程没有正确调用wait/waitpid,则僵尸进程就不会消失。 - 情况2:
如果父进程早于子进程结束,那么子进程结束后,会由init进程(进程号为1)接管,init调用wait,同样不会出现僵尸进程。
二:容器环境中
容器环境中,进程号为1的进程是容器主进程,该进程不具备回收僵尸进程的能力,因此,当容器内产生孤儿进程托管给主进程(进程号为1)的进程后,就变成了没有人处理的僵尸进程
解决方法
方法一:
-
k8s 中
pause 容器
是所有容器的父容器(parent container)
,它有2个作用- 它是pod中
Linux命名空间
共享的基础 - 启用
PID 命名空间
共享,pod 中PID 1
的init 进程
有它维护,并接收收割僵尸进程
- 它是pod中
那么,如果把pause进程变成进程号为1的容器主进程,是不是就可以处理孤儿进程了呢?
答案是肯定的~~~
有如下两种方法,能够将pause容器变成主进程
kubelet
通过配置--docker-disable-shared-pid=false
开启共享pid namespace
,也可以在 yml 中指定- 可以在yaml编排文件中指定
cat test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
selector:
matchLabels:
app: pod1
replicas: 1
template:
metadata:
labels:
app: pod1
spec:
shareProcessNamespace: true
containers:
- name: sshd
image: circleci/sshd:0.1
env:
- name: PUBKEY
value: "abc"
- name: pod1
image: busybox
securityContext:
capabilities:
add:
- SYS_PTRACE
stdin: true
tty: true
ports:
- name: p80
containerPort: 80
- name: p22
containerPort: 22
EOF
在编排文件的spec中,加入 shareProcessNamespace: true
开启后,可以在容器中,看到如下进程列表:
[root@sc-master-1 ~]# kubectl -n milvus-1 exec -it elasticsearch-etcd-2 -- ps -ef
UID PID PPID C STIME TTY TIME CMD
65535 1 0 0 03:09 ? 00:00:00 /pause
1001 7 0 1 03:09 ? 00:03:55 etcd
1001 53340 0 0 07:46 pts/0 00:00:00 ps -ef
如上,可以看到pause容器变成了进程号为1的主进程,将会负责处理孤儿进程。
参考:www.xiexianbin.cn/kubernetes/…
方法二:
参考一: www.xiexianbin.cn/docker/dock…
参考二:cloud-atlas.readthedocs.io/zh_CN/lates…
参考三:cloud-atlas.readthedocs.io/zh_CN/lates…
tini
是一个针对容器开发的、精简的 init
服务。tini
的作用是生成子进程、避免僵尸进程生成、转发信号量(pid
为 1
时)到子进程并等待它退出。使用 tini
可以优雅的结束容器内的进程。
参考:github.com/krallin/tin…
背景:
- Linux 中
pid
为1
的init
进程可以接受中断信号量,并将该信号量转发到所有子进程 - 非
init
需要程序实现转发信号的功能才能关闭其他程序,一般的bash
、sh
不具备上述功能 - 使用
docker stop
时,容器内pid
为1
进程将接受中断信号量
打包镜像:
FROM rockylinux:9.2.20230513
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
# Run your program under Tini
# or docker run your-image /your/program ...
COPY