K8s学习笔记(十五) pause容器与init容器
1 Pod 里的容器为什么能 “共享资源”?
Pod 是 K8s 的最小部署单元,一个 Pod 里可以有多个容器(比如一个应用容器 + 一个日志收集容器)。这些容器能共享网络 IP、端口空间、进程可见性等资源,本质上是因为它们共享了同一个 “命名空间”(Linux 的 namespace 技术)。
但这里有个问题:谁来 “创建和维持” 这些共享的命名空间?
答案就是:pause 容器。
2 什么是 pause 容器?
pause 容器是 K8s 自动为每个 Pod 创建的第一个容器,也叫 “基础设施容器”(Infrastructure Container)。它的作用非常纯粹:初始化并维持 Pod 的共享命名空间,让后续加入 Pod 的业务容器能 “附着” 到这些命名空间上。
可以把它理解为:
- Pod 是一个 “房间”,pause 容器是 “房间的承重墙”,负责支撑房间的结构;
- 业务容器是 “房间里的家具”,依赖承重墙(pause 容器)共享房间的空间(命名空间)。
3 pause 容器的 3 个核心作用
3.1 维持共享的网络命名空间(Network Namespace)
- 当 Pod 被创建时,pause 容器首先启动,会创建一个独立的网络命名空间(包含一个 IP 地址、端口范围、路由表等)。
- 后续 Pod 内的所有业务容器(如应用容器、日志容器)都会 “加入” 这个网络命名空间,因此:
- 所有容器共享同一个 IP 地址(Pod 的 IP);
- 容器之间可以通过
localhost
直接通信(比如应用容器监听localhost:8080
,日志容器可以直接访问); - 端口不能冲突(因为共享端口空间,两个容器不能同时监听 80 端口)。
举例:如果 Pod 的 IP 是10.244.1.5
,那么 Pod 内所有容器的网络视角里,自己的 IP 都是10.244.1.5
,对外通信也用这个 IP。
3.2 维持共享的 PID 命名空间(PID Namespace)
- pause 容器会创建并维持 Pod 的 PID 命名空间,让 Pod 内的所有容器能 “看到彼此的进程”。
- 比如:在应用容器里执行
ps aux
,可以看到 pause 容器的进程(通常是/pause
),也能看到其他业务容器的进程。 - 这对一些需要跨容器管理进程的场景很重要(比如监控容器需要查看应用容器的进程状态)。
3.3 作为 Pod 的 “生命周期锚点”
- pause 容器是 Pod 中第一个启动的容器,也是最后一个退出的容器。
- 它的进程非常简单:就是一个 “暂停”(pause)进程(源码本质是
while(true) { sleep(inf) }
),几乎不消耗 CPU 和内存,也不会主动退出。 - 只要 pause 容器还在运行,Pod 的共享命名空间就会一直存在。即使业务容器因故障重启或退出,命名空间也不会被销毁,新启动的业务容器可以直接重新加入。
- 如果 pause 容器意外退出,整个 Pod 会被 K8s 重启(因为它是 Pod 的 “根基”)。
4 pause 容器的特点
- 镜像极小:官方 pause 镜像(如
k8s.gcr.io/pause:3.9
)通常只有几 MB(比如 3.9 版本约 2.5MB),因为它只包含一个静态编译的pause
二进制文件,没有其他冗余内容。 - 资源消耗极低:运行时几乎不占用 CPU(微秒级)和内存(KB 级),仅作为命名空间的 “占位符”。
- 自动创建:用户不需要手动定义 pause 容器,K8s 在创建 Pod 时会自动添加(通过容器运行时,如 containerd、CRI-O)。
5 如何 “看到” pause 容器?
虽然用户不直接操作 pause 容器,但可以通过工具观察它的存在:
-
通过 kubectl 查看 Pod 的容器列表
执行
kubectl describe pod <pod名称>
,在Containers
部分上方,会有一个Init Containers
(如果有的话),但 pause 容器通常不在这里显示。更直接的方式是查看容器运行时的信息: -
通过容器运行时(如 containerd)查看
在 Node 节点上执行(需要 root 权限):
# 列出所有容器(包含pause容器) ctr containers list | grep <pod的UID>
会看到一个名称包含
pause
的容器,比如:k8s://<namespace>/<pod名称>/<pod的UID>-pause
-
查看 Pod 的详细 JSON 结构
执行
kubectl get pod <pod名称> -o json
,在spec.containers
里看不到 pause 容器(因为它是 K8s 自动添加的),但可以通过容器运行时的状态间接确认。
6 为什么需要 pause 容器?
简单说:没有 pause 容器,Pod 内的容器就无法稳定共享命名空间。
如果用业务容器来初始化命名空间,会有两个问题:
- 若业务容器意外退出,命名空间会被销毁,其他容器会受影响;
- 业务容器可能有复杂逻辑,不适合作为 “稳定的根基”。
而 pause 容器的设计就是 “极简 + 稳定”,完美承担了 “维持命名空间” 的角色。
总结
pause 容器是 Pod 的 “隐形基础设施”:
- 它先启动,创建并维持 Pod 的网络、PID 等共享命名空间;
- 业务容器依赖它实现资源共享;
- 它自身极小、稳定,是 Pod 能正常工作的 “幕后支撑”。
7 init容器
init容器是在 Pod 的业务容器启动前执行 “初始化任务” 的专用容器。它就像演唱会开始前的 “场务人员”—— 先做好设备调试、场地布置,确保主唱(业务容器)能顺利登场。
8 为什么需要 init 容器?
假设有一个业务容器(比如一个 Web 应用),它启动前需要满足一些条件:
- 必须等待数据库服务先启动(否则连接会失败);
- 需要从配置中心下载最新的配置文件;
- 要先给某个目录授权(否则业务容器没有读写权限)。
如果这些工作让业务容器自己做(比如在启动脚本里加一堆判断逻辑),会让业务容器变得臃肿,而且不好维护。
这时,init 容器就派上用场了:它专门负责这些 “前置初始化工作”,完成后就退出,不干扰业务容器的运行。
9 什么是 init 容器?
init 容器是在 Pod 中业务容器(containers
字段定义的容器)启动之前运行的容器,定义在 Pod 的initContainers
字段中。
它的核心逻辑是:“做完就走”—— 只执行初始化任务,成功完成后就退出(状态码为 0),然后 K8s 才会启动后续的业务容器。
10 init 容器的 3 个核心作用
10.1 等待依赖服务就绪
这是最常见的场景。比如 Web 应用依赖数据库,init 容器可以循环检测数据库的端口是否可通,直到数据库就绪才退出,确保业务容器启动时能正常连接。
示例逻辑(伪代码):
# init容器脚本
while ! nc -z db-service 3306; do # 检测数据库服务是否可用echo "等待数据库启动..."sleep 2
done
echo "数据库已就绪!"
10.2 初始化配置或环境
比如:
- 从配置中心(如 ConfigMap、Secret)读取配置,生成业务容器需要的配置文件(如
app.conf
); - 给业务容器的工作目录授权(
chmod 777 /data
); - 下载业务容器依赖的静态资源(如 JS/CSS 文件)。
10.3 简化业务容器的逻辑
把初始化逻辑从业务容器中剥离,让业务容器只专注于核心功能(比如处理请求、计算任务),避免 “业务代码 + 初始化代码” 混在一起导致的臃肿和维护困难。
11 init 容器的关键特点(和业务容器的区别)
特性 | init 容器 | 业务容器(containers ) |
---|---|---|
启动时机 | 先于所有业务容器启动 | 在所有 init 容器成功退出后启动 |
执行顺序 | 多个 init 容器按定义顺序依次执行(前一个完成,后一个才启动) | 多个业务容器并行启动 |
运行状态 | 执行完任务后必须退出(状态码 0) | 通常长期运行(如nginx 、java 进程) |
失败处理 | 若失败,Pod 会重启(受restartPolicy 影响) | 若失败,按restartPolicy 重启自身 |
资源共享 | 和业务容器共享 Pod 的网络、存储(同 pause 容器维护的命名空间) | 同上 |
12 实战示例:用 init 容器等待数据库
假设我们有一个 Web 应用 Pod,依赖名为db-service
的数据库服务,我们用 init 容器确保数据库就绪后再启动 Web 应用。
12.1 定义 Pod 的 YAML(web-with-init.yaml
)
apiVersion: v1
kind: Pod
metadata:name: web-app
spec:# init容器:等待数据库initContainers:- name: wait-dbimage: busybox:1.35 # 轻量镜像,包含nc工具command: ['sh', '-c', 'while ! nc -z db-service 3306; do echo "等待数据库..."; sleep 2; done; echo "数据库就绪!"']# 业务容器:Web应用containers:- name: webimage: nginx:alpineports:- containerPort: 80
12.2 执行与观察
# 创建Pod
kubectl apply -f web-with-init.yaml# 查看Pod状态(此时init容器正在运行)
kubectl get pod web-app
# 输出可能为:Init:0/1(表示1个init容器,0个完成)# 查看init容器日志(确认等待过程)
kubectl logs web-app -c wait-db
# 输出:等待数据库...(直到db-service可用,显示“数据库就绪!”)# 当init容器完成后,业务容器启动,Pod状态变为Running
kubectl get pod web-app # 状态:Running
13 init 容器的注意事项
-
必须成功退出:init 容器必须以状态码 0 退出,否则 K8s 会不断重启 Pod(或 init 容器,取决于
restartPolicy
),导致业务容器永远无法启动。- 若初始化逻辑可能失败(如配置文件下载失败),需在脚本中处理错误(如重试几次后退出非 0 状态,避免无限循环)。
-
资源限制:init 容器的资源请求(
requests
)和限制(limits
)会被计入 Pod 的总资源计算,且调度器会确保 Node 有足够资源运行 init 容器(即使业务容器资源需求更低)。 -
无健康检查:init 容器不支持
livenessProbe
、readinessProbe
(因为它是一次性的,不需要健康检查)。 -
调试方法:若 init 容器卡住或失败,可通过以下命令排查:
# 查看Pod事件(可能有失败原因) kubectl describe pod <pod名称># 查看init容器日志(若容器曾启动过) kubectl logs <pod名称> -c <init容器名称>
14 和其他 “初始化方式” 的区别
- 与启动脚本(
command
/args
)的区别:业务容器的启动脚本也能做初始化,但如果初始化逻辑复杂(如多步等待、依赖检查),会让脚本冗长;而 init 容器是独立的,逻辑更清晰。 - 与 pause 容器的区别:pause 容器是 “基础设施容器”,负责维持 Pod 的命名空间(长期运行);init 容器是 “初始化工具”,负责前置任务(完成后退出)。
总结
init 容器是 Pod 的 “前置初始化助手”:
- 作用:等待依赖、初始化配置、简化业务容器逻辑;
- 特点:顺序执行、完成后退出、失败会阻塞业务容器启动;
- 核心价值:让业务容器专注于核心功能,提升 Pod 的可维护性。
当业务容器需要 “启动前准备工作” 时,优先考虑用 init 容器来实现。