k8s为啥引入一个Pause容器

k8s的设计理念是希望一个容器只运行一个程序,多个关联的程序通过Pod组装到一起,譬如一个容器运行tomcat另外一个容器负责采集tomcat日志,那么这两个容器就可以组装到一个Pod里面,共享网络和挂载的存储。

k8s为啥引入一个Pause容器

那么为啥k8s里面为每个Pod都创建一个pause容器呢?为啥不直接将网卡直接挂载到第一个启动业务容器呢,非要引入一个pause容器,这不是多此一举嘛,而且还增加管理成本。那是因为k8s需要为容器创建一个稳定的网络环境,设想一下,如果将第一个容器作为启动容器,如果容器启动失败或者异常退出,将会导致网络不可用。不仅如此,后续k8s还引入initcontainer功能,第一个启动的业务容器是initcontainer,它在执行完成后就会退出。所以k8s为了给容器提供一个稳定的网络环境,就需要启动一个”一定能够启动,并且不会发生任何异常的容器“。所以这个pause容器最简单的做法就是一直执行pause指令,让容器一直”hang“在那里,不退出,所以这个容器叫做pause容器。

pause的代码就在kubernetes的build/pause路径下面,也就几行代码,如下

int main(int argc, char **argv) {
  int i;
  for (i = 1; i < argc; ++i) {
    if (!strcasecmp(argv[i], "-v")) {
      printf("pause.c %s
", VERSION_STRING(VERSION));
      return 0;
    }
  }

  if (getpid() != 1)
    /* Not an error because pause sees use outside of infra containers. */
    fprintf(stderr, "Warning: pause should be the first process
");

  if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
    return 1;
  if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
    return 2;
  if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap,
                                             .sa_flags = SA_NOCLDSTOP},
                NULL) < 0)
    return 3;

  for (;;)
    pause(); //暂停
  fprintf(stderr, "Error: infinite loop terminated
");
  return 42;
}

其中核心的就是最后面几行,通过一个for死循环里面调用pause指令。是不是非常的简单!这里细心的童鞋可能发现,上面还有接收信号优雅退出的代码,其实pause容器还有另外一个功能就是收割”僵尸进程“。当在k8s里面开启共享PID namespace的时候,Pod里面的容器就可以共享Pid了,那么这个Pause容器的进程就是1,其他业务容器的都是这个进程的子进程,那么后续就拥有了清理僵尸进程的能力。

听起来是不是很美好,但为啥k8s里面没有默认开启这个功能呢?

主要有两个原因:某些程序譬如systemd,必须要求自己的Pid是1,如果不是就无法启动;另一个原因是在优雅关闭的场景,需要信号只会发给Pid为1的进程,导致业务容器无法接收信号,执行优雅退出。

展开阅读全文

页面更新:2024-05-04

标签:容器   僵尸   指令   进程   信号   优雅   异常   原因   稳定   代码   功能   环境   业务   程序   科技   网络

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top