【散步思考】容器init进程是否能够被kill

饭后散步,同事(烽哥,记住这位大佬)提出这么一个问题,k8s在启动pod的时候,程序往往会作为1号进程进行启动,那么,使用kill往init进程发送信号,进程能否被重启? 我听到这个问题的第一反应回答是:这个问题出现在极客时间《容器实战高手课》中,我半年前看过一遍,但是只能说结果,推导的过程忘记了。 这就暴露出一个问题,在阅读技术文章时的思维惯性:当作者写的非常通俗易懂的时候,看过就觉得自己会了。 本篇文章作为我的一个总结性文章。先说答案:init进程能够被kill掉, 但是只能发送SIGTERM信号(kill -15), 使用SIGKIll信号无效(即发送kill -9 )。并且,go语言可以直接使用, C语言需要自己注册SIGTERM处理函数才可以。

要理解这个问题,需要搞明白几件事:

  1. 信号在内核中如何传递给进程的。
  2. 进程是如何处理信号的。

在第二个问题的基础上:又提出了一个问题,一个while(true)的死循环程序,是否能够kill掉?理由?

信号的传递

【散步思考】容器init进程是否能够被kill关注于信号的传递函数:sig_task_ignored()。

kernel/signal.c
static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
{
        void __user *handler;
        handler = sig_handler(t, sig);

        /* init程序忽略SIGKILL以及SIGSTOP信号 */
        if (unlikely(is_global_init(t) && sig_kernel_only(sig)))

                return true;

        if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
            handler == SIG_DFL && !(force && sig_kernel_only(sig)))
                return true;

        /* 只允许内核中定义的信号进行传递 */
        if (unlikely((t->flags & PF_KTHREAD) &&
                     (handler == SIG_KTHREAD_KERNEL) && !force))
                return true;

        return sig_handler_ignored(handler, sig);
}

三个if条件中: 第一个条件解释了,为什么init函数接受到kill -9 无效,同样的SIGSTOP信号也将无效。 第二个条件,里面的关键点:

  • **SIGNAL_UNKILLABLE **如果进程为init进程,条件为true;
  • 程序是否注册缺省处理函数;
  • **force **在同一个namespace中为0;

第三个条件,用来排除非内核的信号。

通过strace跟踪系统调用,可以测试到程序收到的信号。 当对init进程发送SIGKILL时,进程为收到信号。使用SIGTERM时,在K8S中,go进程完成原地重启。

关键点在于init函数有没有注册信号处理函数

程序处理信号时机

while(true)死循环程序,能否被kill掉。 答案是肯定的(否则机器早崩了)。 用户进程提供的信号处理函数是在用户态里的,而发现信号的时刻处于内核态中,所以需要从内核态跑到用户态去执行信号处理程序,执行完毕后还要返回内核态。【散步思考】容器init进程是否能够被kill对于while(true)的进程来说,还需要设计到进程的调度,当程序死循环中,也会被Linux调用拉下来,发生调用的原则:

  • 时间片轮转;
  • 系统资源不足;
  • 睡眠函数,主动挂起;
  • 优先级调度
  • 硬件中断;

所以当发送进程切换后, 当while(true)进程切换回来,会先判断是否存在信号需要处理,然后再执行之前进程流程。 到这里,我脑袋又冒出一个问题,kubernetes中,我们执行kubectl delete pod,发送的是什么信号?

kubernete delete pod

答案:先发送SIGTERM,30s宽限期后,发送SIGKILL信号,具体流程如下:【散步思考】容器init进程是否能够被kill

总结

在云原生的环境中,程序可以通过注册SIGTERM信号,来实现优雅的关闭。 并且由于kuberenets没有restart pod的机制,又在删除,重建pod后,podip出现变化,所以可以进入到容器中使用kill -15信号,完成程序的重启(一般不推荐)。如果有这种需要,更推荐使用OpenKruise 简介 | OpenKruise。 在总结完这个技术问题后,我烽哥散步又提出了一个狗血问题:如果给kubernetes的磁盘进行限制

参考文章

  1. 容器实战高手课_容器_实战_Linux_Docker_-极客时间
  2. [译] SIGKILL:Linux 容器的快速终止 (信号 9) – 海的澜色
  3. 【干货】linux内核信号的处理过程
  4. 4.5.5 Pod 的终止过程 · Kubernetes Documentation


原文始发于微信公众号(小唐云原生):【散步思考】容器init进程是否能够被kill

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/247506.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!