0 序
- 带着问题看此文:Kubernetes中的Pause容器到底是干嘛的?
本文作于 2025.05,发布于 2026.04.20
- 安装 Kubernetes Node 时会出现报错:
Failed to create pod sandbox: rpc error: code = Unknown desc = failed to get sandbox image "k8s.gcr.io/pause:3.5": failed to pull image "k8s.gcr.io/pause:3.5": failed to pull and unpack image "k8s.gcr.io/pause:3.5": failed to resolve reference "k8s.gcr.io/pause:3.5": failed to do request: Head "https://k8s.gcr.io/v2/pause/manifests/3.5": x509: certificate signed by unknown authority
k8s.gcr.io这个地址需要连外网才可以拉取到,导致pause镜像拉不下来,Pod无法启动。
以前都没关注过 pause 这个容器,它是啥,做什么用的,怎么在 Pod 里没注意过它,本文将带你了解 pause 容器。
1 概述:Kubernetes Pod中的Pause容器
Pause 容器 := Infra 容器
- Pause容器是个啥?
在Kubernetes中,
Pod是最小的调度单元,但它的内部结构却充满了许多复杂的机制,其中之一就是Pause容器。
尽管Pause容器看似不起眼,但它在整个Kubernetes集群中发挥了至关重要的作用。
我们在 kubernetes 的node节点,执行docker ps,可以发现每个node上都运行了一个pause进程的容器。具体如下:
[root@localhost ~]# docker ps | grep traefik
66032431a20e 2ae1addee1b2 "/entrypoint.sh --gl…" 30 hours ago Up 30 hours k8s_traefik_traefik-68b9ccfc77-x8sqg_traefik_aa5b97bf-3db8-4b92-89a7-1fe551645e6a_0
10d393461904 registry.aliyuncs.com/google_containers/pause:3.5 "/pause" 30 hours ago Up 30 hours k8s_POD_traefik-68b9ccfc77-x8sqg_traefik_aa5b97bf-3db8-4b92-89a7-1fe551645e6a_0
会发现有很多
pause容器运行于服务器上面,容器命名也很规范,然后每次启动1个Pod,都会伴随一个pause这样的容器启动。
//查看 Pod
[root@k8s-master-1 ~]# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-flannel kube-flannel-ds-lgrbd 1/1 Running 2 (28h ago) 3d2h
kube-flannel kube-flannel-ds-wv2j6 0/1 Init:0/2 0 25h
kube-system coredns-c676cc86f-nzj2x 1/1 Running 1 (28h ago) 3d3h
kube-system coredns-c676cc86f-s88tw 1/1 Running 1 (28h ago) 3d3h
kube-system etcd-k8s-master-1 1/1 Running 1 (28h ago) 3d3h
kube-system kube-apiserver-k8s-master-1 1/1 Running 1 (28h ago) 3d3h
kube-system kube-controller-manager-k8s-master-1 1/1 Running 1 (28h ago) 3d3h
kube-system kube-proxy-c7vf9 0/1 ContainerCreating 0 25h
kube-system kube-proxy-l9g4h 1/1 Running 1 (28h ago) 3d3h
kube-system kube-scheduler-k8s-master-1 1/1 Running 1 (28h ago) 3d3h
kubeedge cloud-iptables-manager-wrdjk 1/1 Running 0 28h
kubeedge cloudcore-ffd866959-zblcp 1/1 Running 0 32h//查看 容器(Container) : 1 个 Pod 内含有 1-N 个 Container
[root@k8s-master-1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a71b11b88111 kubeedge/iptables-manager "iptables-manager" 28 hours ago Up 28 hours k8s_iptables-manager_cloud-iptables-manager-wrdjk_kubeedge_07ae49e2-c0dc-48d0-aedf-89cda7b17d2f_0
532900da751e kubeedge/cloudcore "cloudcore" 28 hours ago Up 28 hours k8s_cloudcore_cloudcore-ffd866959-zblcp_kubeedge_0be58d1c-f257-495b-9699-ac533ff6336d_0
fdbceb5b647e registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_cloud-iptables-manager-wrdjk_kubeedge_07ae49e2-c0dc-48d0-aedf-89cda7b17d2f_0
44ff738f7188 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_cloudcore-ffd866959-zblcp_kubeedge_0be58d1c-f257-495b-9699-ac533ff6336d_0
ae9c452f479e 965b9dd4aa4c "/opt/bin/flanneld -…" 28 hours ago Up 28 hours k8s_kube-flannel_kube-flannel-ds-lgrbd_kube-flannel_76f47ce3-8713-4e10-b8cf-95dd960a5ccb_2
62dd1ef63552 4d2edfd10d3e "kube-apiserver --ad…" 28 hours ago Up 28 hours k8s_kube-apiserver_kube-apiserver-k8s-master-1_kube-system_7a62499f0bbe9a59a268e876557e5b19_1
e7f8604f7d2a registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_kube-apiserver-k8s-master-1_kube-system_7a62499f0bbe9a59a268e876557e5b19_1
fba842a947dd 5185b96f0bec "/coredns -conf /etc…" 28 hours ago Up 28 hours k8s_coredns_coredns-c676cc86f-s88tw_kube-system_f60ee28a-6b39-4297-b2a7-6cac0839fcca_1
9b18b50db0f9 5185b96f0bec "/coredns -conf /etc…" 28 hours ago Up 28 hours k8s_coredns_coredns-c676cc86f-nzj2x_kube-system_27881b1b-be21-4d87-9873-9d7f5a448ee5_1
f0d56184c884 1a54c86c03a6 "kube-controller-man…" 28 hours ago Up 28 hours k8s_kube-controller-manager_kube-controller-manager-k8s-master-1_kube-system_9d1ac5eb0d463a9781c0e3bc69b6bcb2_1
75e857136ba2 a8a176a5d5d6 "etcd --advertise-cl…" 28 hours ago Up 28 hours k8s_etcd_etcd-k8s-master-1_kube-system_13291f751814aec327e1f1cc90f5daab_1
adcfc8bd741a bef2cf311509 "kube-scheduler --au…" 28 hours ago Up 28 hours k8s_kube-scheduler_kube-scheduler-k8s-master-1_kube-system_a8afe93c77232b5ad4b24c58345e1d40_1
8281b58eab86 58a9a0c6d96f "/usr/local/bin/kube…" 28 hours ago Up 28 hours k8s_kube-proxy_kube-proxy-l9g4h_kube-system_468c7e25-c093-45c5-9fb5-ecc19c7aa1ab_1
d09864685d44 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_etcd-k8s-master-1_kube-system_13291f751814aec327e1f1cc90f5daab_1
4ad14afc6f4f registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_kube-flannel-ds-lgrbd_kube-flannel_76f47ce3-8713-4e10-b8cf-95dd960a5ccb_1
338a75c94741 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_coredns-c676cc86f-s88tw_kube-system_f60ee28a-6b39-4297-b2a7-6cac0839fcca_1
4f15104a5bd0 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_kube-controller-manager-k8s-master-1_kube-system_9d1ac5eb0d463a9781c0e3bc69b6bcb2_1
0711b7650cf0 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_kube-scheduler-k8s-master-1_kube-system_a8afe93c77232b5ad4b24c58345e1d40_1
69b797f24db0 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_coredns-c676cc86f-nzj2x_kube-system_27881b1b-be21-4d87-9873-9d7f5a448ee5_1
c0518a104a69 registry.aliyuncs.com/google_containers/pause:3.8 "/pause" 28 hours ago Up 28 hours k8s_POD_kube-proxy-l9g4h_kube-system_468c7e25-c093-45c5-9fb5-ecc19c7aa1ab_1
- 那它究竟是干啥的?它就是
Pause容器,又叫Infra容器。
我们在部署完 kubernetes 集群后,查看
kubelet进程,可以看到配置中有这样一个参数:
[root@localhost ~]# ps -ef | grep kubelet
root 8675 1 10 Sep18 ? 03:15:07 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.5
pause容器使用的镜像为registry.aliyuncs.com/google_containers/pause:3.5该镜像非常小,只有 683kB,由于它总是处于Pause(暂时)状态。所以,取名叫pause
[root@localhost ~]# docker images|grep pause
registry.aliyuncs.com/google_containers/pause 3.5 ed210e3e4a5b 2 years ago 683kB
想了解该 pause 容器的构成(代码是用 C 语言写的)的可以去官方仓库上一看究竟:https://github.com/kubernetes/kubernetes/tree/master/build/pause
Pause容器的作用
- 网络命名空间隔离
Pod是Kubernetes中最小的调度单元,可以包含一个或多个容器。
为了实现容器之间的网络隔离,每个Pod都有自己独立的网络命名空间。
Pause容器负责创建并维护这个网络命名空间,其他容器共享这个网络命名空间,使它们能够相互通信,而不会与其他Pod中的容器发生冲突。
- 进程隔离
Pause容器保持一个轻量级的进程运行,即使Pod中的其他容器都停止了。
这个进程实际上不执行任何有用的工作,但它的存在确保了Pod不会在没有容器运行的情况下被删除。
当其他容器停止时,Pause容器仍在运行,以维持Pod的生命周期。
- 资源隔离
尽管Pause容器通常不分配大量的CPU和内存资源,但它可以配置以使用一些资源。
这有助于确保即使Pod中没有其他容器运行时,Kubernetes仍然可以监控和管理Pod的资源使用情况。
这也有助于防止Pod被其他具有相同资源要求的Pod占用。
- IP地址维护
Pause容器负责维护Pod的IP地址。
Pod的IP地址通常是动态分配的,但由于Pause容器一直在运行,它可以维护Pod的IP地址,以便其他容器可以通过该地址进行通信。
这有助于确保Pod的IP地址在整个Pod的生命周期内保持一致。
- 业务Pod的生命周期管理
Pause容器的生命周期与Pod的生命周期相同。
当Pod创建时,Pause容器被创建;当Pod删除时,Pause容器也会被删除。
这确保了Pod的整个生命周期都由Kubernetes进行管理,包括创建、扩展、缩放和删除。
Pause容器工作原理
- 一个 Pod 可以由一组容器组成的,这些容器之间共享存储和网络资源。那么,网络资源是如何共享的呢?
下面是个例子
https://developer.qcloudimg.com/http-save/yehe-1107783/0f338dee2baf60d325436ff284900d19.png
比如说现在有一个 Pod,其中包含了一个容器 A 和一个容器 B,它们两个就要共享 Network Namespace。
在 Kubernetes 里的解法是这样的:它会在每个 Pod 里,额外起一个Infra container小容器来共享整个 Pod 的 Network Namespace。
Infra container是一个非常小的镜像,大概 683kB,是一个C语言写的、永远处于“暂停”状态的容器。
由于有了这样一个Infra container之后,其他所有容器都会通过Join Namespace的方式加入到Infra container的Network Namespace中。
所以说,一个
Pod里的【所有容器】,它们看到的【网络视图】可以说是完全一样的。
即:它们看到的网络设备、IP地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个Infra container。
这就是Pod解决网络共享的一个解法。
- 在 Pod 里面,一定有一个 IP 地址,是这个 Pod 的
Network Namespace对应的地址,也是这个Infra container的 IP 地址。
所以,大家看到的都是一份,而其他所有网络资源,都是一个 Pod 一份,并且被 Pod 中的所有容器共享。
这就是 Pod 的网络实现方式。
由于需要有一个相当于中间的容器存在,所以整个 Pod 里面,必然是Infra container第一个启动。
并且整个Pod的生命周期是等同于Infra container的生命周期的,与容器 A 和 B 是无关的。
这是非常重要的一个设计。
kubernetes的pause容器,主要为每个业务容器提供2个核心功能:
- 第一,它提供整个pod的Linux命名空间的基础。
- 第二,启用
PID命名空间,它在每个pod中都作为PID为1的进程,并回收僵尸进程。
手工模拟Pod
- 我们已经知道,1个 Pod 从表面上来看至少由1个容器组成,而实际上1个 Pod 至少要有包含2个容器:一个是应用容器,一个是
pause容器。
运行一个pause容器:
[root@localhost ~]# docker run -d --name pause -p 8080:80 registry.aliyuncs.com/google_containers/pause:3.5
fd315974f5d1a5f52ca47c5dc31aea3774cebf90c88ce065cc9e9ea2f52c103c
--name:指定 pause 容器的名字,pause
-p 8080:80:将宿主机的 8080 端口映射到容器的 80 端口
- 【案例】 运行一个nginx容器,代理 127.0.0.1:8888 springboot应用程序
# 准备nginx配置文件
[root@k8s001 ~]# cat <<EOF >> nginx.conf
error_log stderr;
events { worker_connections 1024; }
http {server {listen 80 default_server;server_name www.kubesre.com;location / {proxy_pass http://127.0.0.1:8888;}}
}
EOF# 创建nginx容器
[root@localhost ~]# docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause --ipc=shareable nginx
fa9f858adae826ad536178747e00fffc829c7baf98c3bc29e945230abbf2a5cb
--net=container:pause:用于与另一个容器共享网络命名空间。在这种情况下,容器 "nginx" 会与名为 "pause" 的容器共享网络命名空间,它们可以使用相同的网络配置和接口。
--ipc=container:pause:用于与另一个容器共享 IPC 命名空间。IPC 命名空间允许容器之间进行进程间通信(Inter-Process Communication),在这里,容器 "nginx" 与名为 "pause" 的容器共享 IPC 命名空间。
--pid=container:pause:用于与另一个容器共享 PID 命名空间。PID 命名空间允许容器查看和管理其他容器的进程。
--ipc=shareable:指示 IPC 命名空间是可共享的,以便其他容器也可以加入到这个共享命名空间中。
- 创建一个应用容器 springboot
[root@localhost ~]# docker run -d --name springboot --net=container:pause --ipc=container:pause --pid=container:pause --ipc=shareable registry.cn-shanghai.aliyuncs.com/kubesre02/springboot
e33cfa3cebd5aafa714ca6ef0f6a16be52a282c64b8d24b2d98890ccf02c436a
到这里,我们已纯手工模拟出了一个符合 K8S Pod 模型的 “Pod” ,只是它并不由 K8S 进行管理。
验证,查看运行的容器
[root@localhost ]~# docker ps | grep -E "pause|nginx|springboot"
4f877cdcba5d registry.cn-shanghai.aliyuncs.com/kubesre02/springboot "java -jar /app.jar" 3 seconds ago Up 2 seconds springboot
e541dc010fb3 nginx "/docker-entrypoint.…" 19 hours ago Up 19 hours nginx
09f94a052d50 registry.aliyuncs.com/google_containers/pause:3.5 "/pause" 19 hours ago Up 19 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp pause
通过浏览器访问 http://ip:8080 端口
[root@localhost ~]# curl http://localhost:8080
Hello Docker World
从上面的步骤可见:
- pause容器将内部80端口映射到宿主机8080端口。
- pause容器在宿主机上设置好网络namespace后,nginx容器加入到该网络的namespace中。
- nginx容器启动的时候指定了-net=container:pause。
- springboot 容器启动时,同样方式加入到该网络的namespace中。
这样三个容器共享了网络,互相之间就可以使用localhost直接通信。
--ipc=container:pause,--pid=container:pause就是三个容器的ipc和pid处于同一个namespace中,init进程为pause。
这里,我们进入 springboot 容器内部查看:
[root@localhost ~]# /tmp/test# docker exec -it springboot sh
/ # ps aux
PID USER TIME COMMAND1 65535 0:00 /pause205 root 0:22 java -jar /app.jar240 root 0:00 nginx: master process nginx -g daemon off;261 101 0:00 nginx: worker process263 root 0:00 sh269 root 0:00 ps aux
在springboot 容器中可以看到pause和nginx容器的进程,并且pause容器的PID为1,而在kubernetes中容器的PID=1的进程则为容器本身的业务进程。
如果没有 K8S 的 Pod ,启动一个 业务容器,你需要手动创建三个容器,当你想销毁这个服务时,同样需要删除三个容器。而有了 K8S 的 Pod,这三个容器在逻辑上就是一个整体,创建 Pod 就会自动创建三个容器,删除 Pod 就会删除三个容器,从管理上来讲,方便了不少。
这正是 Pod 存在的一个根本意义所在。
如何回收僵尸进程
- 在Linux中,PID命名空间中的进程是一个树型结构,每个进程有一个父进程。
在树的根上只有一个进程没有真正的父进程。这是
init进程,其PID为1。
- 僵尸进程是指已经停止运行、但它们的进程表条目仍然存在的进程。
在UNIX系统中,一个子进程结束了,但是它的父进程没有等待(调用
wait/waitpid)它,那么它将变成一个僵尸进程。
- 僵尸进程是怎么产生的?
出现僵尸进程的一种情况是:父进程编写得很糟糕,省略了wait调用,或者父进程意外崩溃在子进程之前死亡,而新的父进程没有调用wait。
当一个进程的父进程在子进程之前死亡时,操作系统将该子进程分配给init进程或PID 1的进程。即init进程接纳子进程并成为其父进程。
这意味着,现在当子进程退出时,新的父进程(init)必须调用wait来获取它的退出码,否则它的进程表条目将永远保留下来,成为僵死进程。
- 在Kubernetes pod中,容器的运行方式与上述基本相同,但是为每个pod创建了一个特殊的pause容器。
这个pause容器运行了一个非常简单的进程,它不执行任何函数,本质上永远休眠,其源码实现:
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>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;
}
从上述代码种我们可以发现,pause容器不仅仅调用
pause()使进程休眠,还拥有另外一个重要的功能:
它假定自己为PID 1的角色,当僵尸进程被其父进程孤立时,会被pause容器进行收养,通过调用wait来获取僵尸进程。这样一来就不会在Kubernetes pod的PID命名空间中堆积僵尸进程了。
那为啥使用
kubectl create或kubectl apply等命令创建Pod时,通常不会显式地看到Pause容器。
这是因为Pause容器是由Kubernetes自动创建和管理的,通常不需要用户手动操作或关注。
它是Pod的一个隐式组成部分,用于维护Pod的基础设施和容器之间的网络隔离。
不难想到,这其中的过程是非常复杂的。而且我们还没有深入探讨如何去监控和管理这些容器的生命周期。
但是不用担心,我们不需要这么复杂的去管理我们的容器,因为kubernetes已经都为我们做好了。
Y 推荐文献
X 参考文献
- Kubernetes中的Pause容器到底是干嘛的 - 腾讯云
