k8s 中 pause 容器的理解

概述

通过

https://www.zido.site/blog/2021-06-01-container-resource/

中知道容器之间是通过 NameSpace 和 cgroups 隔离开的,但是 pod 中的网络和存储却是共享的.

kubernetes 为了解决网络共享问题,引入了 pause 容器,又叫Infra容器,在kubelet的配置中有KUBELET_POD_INFRA_CONTAINER参数,它的默认配置是:

KUBELET_POD_INFRA_CONTAINER=--pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0

而 pause 的代码可见

https://github.com/kubernetes/kubernetes/tree/master/build/pause

网络共享实现原理

只看

https://github.com/kubernetes/kubernetes/blob/master/build/pause/linux/pause.c#L64-L65

非常简单,我直接把它贴出来

#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #define STRINGIFY(x) #x #define VERSION_STRING(x) STRINGIFY(x) #ifndef VERSION #define VERSION HEAD #endif static void sigdown(int signo) { psignal(signo, "Shutting down, got signal"); exit(0); } static void sigreap(int signo) { while (waitpid(-1, NULL, WNOHANG) > 0) ; } int main(int argc, char **argv) { int i; for (i = 1; i < argc; ++i) { if (!strcasecmp(argv[i], "-v")) { printf("pause.c %s\n", 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\n"); 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\n"); return 42; }

按照主流程看:

  • -v 输出版本号 (不看)
  • if(getpid() !=1) 确保自己是 pid为 1 的进程。(warning)
  • 检查 SIGINTSIGTERM信号,收到此信号关闭应用(ctrl-c之类的)
  • 检查 SIGCHLD,当子进程停止(ctrl-z之类的行为)或终结(kill之类的行为)时,调用waitpid方法收割僵尸进程
  • 然后一直暂停(循环调用pause())。

waitpid函数的作用: 收割僵尸进程。 -1 表示所有子进程,WNOHANG表示没有子进程被退出就立即返回。 pause 函数的作用为:使调用进程(线程)进入休眠状态(就是挂起);直到接收到信号且信号函数成功返回 pause函数才会返回。

发现主要有两部分功能:

  • 承担PID 1的角色,它将通过调用wait来收割这些僵尸进程(见sigreap)。保证不会有僵尸堆积在Kubernetes pods的PID命名空间中。
  • pause 容器一直处于暂停状态

有了这个不退出的容器之后, 其它所有的容器就可以利用 Join Namespace 这个特性,加入到 pause container 的 NetWork Namespace 中。

此时,所有容器的网络试图就完全一样了,他们看到的都是 pause container 的网络视图,例如 网络设备、IP 地址、Mac 地址等等。

当然了,这也就要求其它容器必须在 pause 容器之后启动。同时,其它任何容器做重建之类操作,整个pod 也不会重启,因为 pause 容器一直存在。

 
  • 云原生

    13 引用
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口

    29 引用
  • 容器化

    1 引用