您的位置 首页 > 数码极客

【amd64】Kubernetes pod里一个特殊的容器:pause-amd64

大家在使用Docker容器或Kubernetes时见过这个容器吗?gcr . io/Google _ containers/pause-amd64

Docker PS命令返回的结果:

[root @ k8s-minion 1 kubernetes]# docker PS | grep pause

c 3026 adee 957 gcr . io/Google _ containers/pause-amd 6433603 . 0 '/pause ' 22 minutes ago up 22 minutes k 8

202 df 18d 636 e gcr . io/Google _ containers/pause-amd 6433603 . 0 '/pause ' 24 hours ago up 24 hours k 8

072d 3414d 33 agcr . io/Google _ containers/pause-amd 6433603 . 0 '/pause ' 24 hours ago up 24 hours k 8

[root@k8s-minion1 kubernetes]#

Kubernet的官网解释说:

t ' s part of the infra structure . this container is started first in all pods to setup the network for the pod。

换句话说,pause-amd64是Kubernetes基础架构的一部分,在Kubernetes管理的所有pod上,pause-amd64容器首次启动,用于Kubernetes群集中pod之间的网络通信。

对这个特殊容器感兴趣的朋友,可以阅读其源代码:

我们查看这个pause-amd64镜像的dockerfile,发现实现很简单,基于一个空白镜像开始:

FROM scratch

ARG ARCH

ADD bin/pause-${ARCH} /pause

ENTRYPOINT ["/pause"]

ARG指令用于指定在执行docker build命令时传递进去的参数。

这个pause container是用c语言写的:

在运行的Kubernetes node上运行docker ps,能发现这些pause container:

pause container作为pod里其他所有container的parent container,主要有两个职责:

1. 是pod里其他容器共享Linux namespace的基础

2. 扮演PID 1的角色,负责处理僵尸进程

这两点我会逐一细说。在Linux里,当父进程fork一个新进程时,子进程会从父进程继承namespace。目前Linux实现了六种类型的namespace,每一个namespace是包装了一些全局系统资源的抽象集合,这一抽象集合使得在进程的命名空间中可以看到全局系统资源。命名空间的一个总体目标是支持轻量级虚拟化工具container的实现,container机制本身对外提供一组进程,这组进程自己会认为它们就是系统唯一存在的进程。

在Linux里,父进程fork的子进程会继承父进程的命名空间。与这种行为相反的一个系统命令就是unshare:

再来聊聊pause容器如何处理僵尸进程的。

Pause容器内其实就运行了一个非常简单的进程,其逻辑可以从前面提到的Pause github仓库上找到:

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() {

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;

}

这个c语言实现的进程,核心代码就28行:

其中第24行里一个无限循环for(;;), 至此大家能看出来pause容器名称的由来了吧?

这个无限循环里执行的是一个系统调用pause,

因此pause容器大部分时间都在沉睡,等待有信号将其唤醒。

接收什么信号呢?

一旦收到SIGCHLD信号,pause进程就执行注册的sigreap函数。

看下SIGCHLD信号的帮助:

SIGCHLD,在一个进程正常终止或者停止时,将SIGCHLD信号发送给其父进程,按系统默认将忽略此信号,如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。

pause进程注册的信号处理函数sigreap里,调用另一个系统调用waitpid来获得子进程终止的原因。

希望这篇文章对大家理解Kubernetes里的pause容器有所帮助。感谢阅读。

关于作者: admin

无忧经验小编鲁达,内容侵删请Email至wohenlihai#qq.com(#改为@)

热门推荐