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

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

那么,如果把pause进程变成进程号为1的容器主进程,是不是就可以处理孤儿进程了呢?

答案是肯定的~~~ 有如下两种方法,能够将pause容器变成主进程

  • kubelet 通过配置 --docker-disable-shared-pid=false 开启共享 pid namespace,也可以在 yml 中指定
  • 可以在yaml编排文件中指定
yaml 复制代码
cat << EOF >> 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 开启后,可以在容器中,看到如下进程列表:

bash 复制代码
[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 的作用是生成子进程、避免僵尸进程生成、转发信号量(pid1 时)到子进程并等待它退出。使用 tini 可以优雅的结束容器内的进程。

参考:github.com/krallin/tin...

背景:

  • Linux 中 pid1init 进程可以接受中断信号量,并将该信号量转发到所有子进程
  • init 需要程序实现转发信号的功能才能关闭其他程序,一般的 bashsh 不具备上述功能
  • 使用 docker stop 时,容器内 pid1 进程将接受中断信号量

打包镜像:

dockerfile 复制代码
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 <<EOF /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
RUN dnf update -y && dnf install epel-release -y   && dnf -y install s3cmd  && dnf install -y wget  && dnf -y install net-tools  && dnf install -y telnet  && dnf -y install traceroute  && dnf -y install tcpdump  && dnf install -y fio  && dnf -y install bind-utils  && dnf install -y kubectl-1.24.16-0 && dnf install -y vim && dnf install -y expect  && dnf install -y git && dnf install -y procps && dnf install psmisc -y && chmod +x /tini
ENTRYPOINT ["/tini", "--"]
CMD [ "sleep","100000" ]

#docker run --rm --name app -e MX_MEM=128m -v /tmp/apps:/data -p 18080:8080 -p 17070:7070 registry.knowdee.com/tests/app:v1.0.0


#docker build    -t registry.knowdee.com/library/tools:v-rock9.2  . -f ./tools.dockerfile --progress=plain

# dnf --showduplicates list kubectl

yaml编排文件:

yaml 复制代码
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
  name: midware
  namespace: tools
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: midware
  serviceName: midware
  template:
    metadata:
      annotations:
        # prometheus.io/port: "8000"
        # prometheus.io/scrape: "true"
      labels:
        app: midware
    spec:
      tolerations:
      - effect: NoExecute
        key: taint.knowdee.io/apps
        operator: Exists
      containers:
      - args:
        - /bin/sh
        - -c 
        - |
          git config --global user.name "knowdee"
          git config --global user.email "it@knowdee.com"
          sleep 30000s
        envFrom:
        - configMapRef:
            name: midware-config
        volumeMounts:
        - name: kubecfg
          mountPath: /root/.kube
        - mountPath: /data
          name: data
        image: registry.knowdee.com/library/tools:v-rock9.2
        imagePullPolicy: IfNotPresent
        name: midware
        # ports:
        # - containerPort: 8000
        #   name: http
        #   protocol: TCP
        resources:
          requests:
            cpu: "1"
            memory: 512Mi
      dnsPolicy: ClusterFirst
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      creationTimestamp: null
      name: data
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 200Mi
      volumeMode: Filesystem
  updateStrategy:
    type: RollingUpdate

在启动后的容器中,可以看到:

bash 复制代码
root           1       0  0 06:27 ?        00:00:00 /tini -- /bin/sh -c git config --global user.name "knowdee" git config --global user.email "it@knowdee.com" cp /data/.s3cfg /root/
root           7       1  0 06:27 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30000s
root          73       0  0 06:27 pts/0    00:00:00 /bin/bash
root         793      73  0 08:32 pts/0    00:00:00 ps -ef

tini进程为进程号为1的进程,则负责孤儿进程的处理,防止出现僵尸进程。

相关推荐
大G哥几秒前
记一次K8S 环境应用nginx stable-alpine 解析内部域名失败排查思路
运维·nginx·云原生·容器·kubernetes
妍妍的宝贝16 分钟前
k8s 中微服务之 MetailLB 搭配 ingress-nginx 实现七层负载
nginx·微服务·kubernetes
QMCY_jason41 分钟前
Ubuntu 安装RUST
linux·ubuntu·rust
慕雪华年1 小时前
【WSL】wsl中ubuntu无法通过useradd添加用户
linux·ubuntu·elasticsearch
苦逼IT运维1 小时前
YUM 源与 APT 源的详解及使用指南
linux·运维·ubuntu·centos·devops
仍有未知等待探索1 小时前
Linux 传输层UDP
linux·运维·udp
zeruns8021 小时前
如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程
linux·运维·服务器·docker·网站
卑微求AC1 小时前
(C语言贪吃蛇)16.贪吃蛇食物位置随机(完结撒花)
linux·c语言·开发语言·嵌入式·c语言贪吃蛇
福大大架构师每日一题2 小时前
23.1 k8s监控中标签relabel的应用和原理
java·容器·kubernetes
Hugo_McQueen2 小时前
pWnos1.0 靶机渗透 (Perl CGI 的反弹 shell 利用)
linux·服务器·网络安全