my_init 解决胖容器僵尸进程清理问题

背景:

虽然不建议,但总有需求把容器当成虚拟机来用,如果产生了僵尸进程,容器就很难正常删除,甚至会导致kubelet状态不稳定。

经测试 tini、dumb-init、pid1并不能容器中清理执行脚本产生的僵尸进程,my_init比较完美解决,容器可以正常删除。


示例:

一、单进程容器僵尸进程处理

使用 tini 作为1号进程处理子进程创建的僵尸进程

ENV TINI_VERSION v0.18.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
二、胖容器僵尸进程处理

使用 my_init 作为1号进程处理所有进程创建的僵尸进程

  • 改造 alpine 镜像
FROM alpine:3.9

RUN apk --no-cache add runit curl python && \
         ln -s  /sbin/runsvdir /usr/bin/runsvdir && \
         ln -s  /sbin/sv /usr/bin/sv && \
         curl -o  /sbin/my_init https://raw.githubusercontent.com/AEGQ/tools/master/alpine/my_init  && \
         chmod +x  /sbin/my_init         

ENTRYPOINT ["/sbin/my_init","--skip-startup-files"]
  • 改造 centos 镜像
FROM centos

RUN rpm -Uvh https://packagecloud.io/imeyer/runit/packages/el/7/runit-2.1.1-7.el7.centos.x86_64.rpm/download && \
         yum install -y curl python python-pip && \
         pip install argparse && \
         curl -o  /sbin/my_init https://raw.githubusercontent.com/AEGQ/tools/master/centos/my_init  && \
         ln -s -t /usr/bin /sbin/sv && \
         ln -s -t /usr/bin /sbin/runsvdir && \
         chmod +x  /sbin/my_init

ENTRYPOINT ["/sbin/my_init","--skip-startup-files"]
  • 改造 ubuntu 镜像
FROM ubuntu:18.04

RUN apt-get update &&  \
         apt-get install -y curl  runit  python &&  \
         curl -o  /sbin/my_init https://raw.githubusercontent.com/AEGQ/tools/master/ubuntu/my_init  && \
         chmod +x  /sbin/my_init
      
ENTRYPOINT ["/sbin/my_init","--skip-startup-files "]
  • 使用官方base镜像(ubuntu)
FROM phusion/baseimage

# for test
#RUN  apt-get update && apt-get install procps wget -y
#RUN  wget https://github.com/AEGQ/tools/raw/master/zombie -O /zombie
#RUN chmod +x  /zombie

ENTRYPOINT ["/sbin/my_init","--skip-startup-files "]
三、 测试
# 生成僵尸进程代码
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    if(!fork()){ 
        if(fork()){ 
            while(1){
                sleep(5);
            }
        }
    }
    return 0;
}

# 安装 gcc
[alpine] # apk add libc-dev gcc 
[centos] # yum install gcc 
[ubuntu] # apt-get install gcc

# 编译
# gcc -o zombie main.c
# 生成僵尸进程
#  watch -n 1 ./zombie 
#  for (( i=0; i < 500; i++ )); do ./zombie; done
#  测试容器在有或没有僵尸进程的情况下,是否能正常删除。

参考: