k8s容器内如何避免僵尸进程

2023年 10月 12日 41.6k 0

之前有文章讨论了僵尸进程,以及脚本中出现僵尸进程时候,主进程调用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 进程有它维护,并接收收割僵尸进程

那么,如果把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 需要程序实现转发信号的功能才能关闭其他程序,一般的 bashsh 不具备上述功能
  • 使用 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

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论