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 容器的特点

  1. 镜像极小 :官方 pause 镜像(如k8s.gcr.io/pause:3.9)通常只有几 MB(比如 3.9 版本约 2.5MB),因为它只包含一个静态编译的pause二进制文件,没有其他冗余内容。
  2. 资源消耗极低:运行时几乎不占用 CPU(微秒级)和内存(KB 级),仅作为命名空间的 "占位符"。
  3. 自动创建:用户不需要手动定义 pause 容器,K8s 在创建 Pod 时会自动添加(通过容器运行时,如 containerd、CRI-O)。

5 如何 "看到" pause 容器?

虽然用户不直接操作 pause 容器,但可以通过工具观察它的存在:

  1. 通过 kubectl 查看 Pod 的容器列表

    执行 kubectl describe pod <pod名称>,在Containers部分上方,会有一个Init Containers(如果有的话),但 pause 容器通常不在这里显示。更直接的方式是查看容器运行时的信息:

  2. 通过容器运行时(如 containerd)查看

    在 Node 节点上执行(需要 root 权限):

    bash 复制代码
    # 列出所有容器(包含pause容器)
    ctr containers list | grep <pod的UID>

    会看到一个名称包含pause的容器,比如:

    k8s://<namespace>/<pod名称>/<pod的UID>-pause

  3. 查看 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 容器可以循环检测数据库的端口是否可通,直到数据库就绪才退出,确保业务容器启动时能正常连接。

示例逻辑(伪代码):

bash 复制代码
# 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) 通常长期运行 (如nginxjava进程)
失败处理 若失败,Pod 会重启(受restartPolicy影响) 若失败,按restartPolicy重启自身
资源共享 和业务容器共享 Pod 的网络、存储(同 pause 容器维护的命名空间) 同上

12 实战示例:用 init 容器等待数据库

假设我们有一个 Web 应用 Pod,依赖名为db-service的数据库服务,我们用 init 容器确保数据库就绪后再启动 Web 应用。

12.1 定义 Pod 的 YAML(web-with-init.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  # init容器:等待数据库
  initContainers:
  - name: wait-db
    image: busybox:1.35  # 轻量镜像,包含nc工具
    command: ['sh', '-c', 'while ! nc -z db-service 3306; do echo "等待数据库..."; sleep 2; done; echo "数据库就绪!"']
  
  # 业务容器:Web应用
  containers:
  - name: web
    image: nginx:alpine
    ports:
    - containerPort: 80
12.2 执行与观察
bash 复制代码
# 创建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 容器的注意事项

  1. 必须成功退出 :init 容器必须以状态码 0 退出,否则 K8s 会不断重启 Pod(或 init 容器,取决于restartPolicy),导致业务容器永远无法启动。

    • 若初始化逻辑可能失败(如配置文件下载失败),需在脚本中处理错误(如重试几次后退出非 0 状态,避免无限循环)。
  2. 资源限制 :init 容器的资源请求(requests)和限制(limits)会被计入 Pod 的总资源计算,且调度器会确保 Node 有足够资源运行 init 容器(即使业务容器资源需求更低)。

  3. 无健康检查 :init 容器不支持livenessProbereadinessProbe(因为它是一次性的,不需要健康检查)。

  4. 调试方法:若 init 容器卡住或失败,可通过以下命令排查:

    bash 复制代码
    # 查看Pod事件(可能有失败原因)
    kubectl describe pod <pod名称>
    
    # 查看init容器日志(若容器曾启动过)
    kubectl logs <pod名称> -c <init容器名称>

14 和其他 "初始化方式" 的区别

  • 与启动脚本(command/args)的区别:业务容器的启动脚本也能做初始化,但如果初始化逻辑复杂(如多步等待、依赖检查),会让脚本冗长;而 init 容器是独立的,逻辑更清晰。
  • 与 pause 容器的区别:pause 容器是 "基础设施容器",负责维持 Pod 的命名空间(长期运行);init 容器是 "初始化工具",负责前置任务(完成后退出)。

总结

init 容器是 Pod 的 "前置初始化助手":

  • 作用:等待依赖、初始化配置、简化业务容器逻辑;
  • 特点:顺序执行、完成后退出、失败会阻塞业务容器启动;
  • 核心价值:让业务容器专注于核心功能,提升 Pod 的可维护性。

当业务容器需要 "启动前准备工作" 时,优先考虑用 init 容器来实现。

相关推荐
稚辉君.MCA_P8_Java2 小时前
kafka解决了什么问题?mmap 和sendfile
java·spring boot·分布式·kafka·kubernetes
无言以对,沉默不语,随你随你。3 小时前
【解决办法】GitBash不能在任意文件夹打开
经验分享·笔记·git
ᖰ・◡・ᖳ3 小时前
JavaScript:神奇的ES6之旅
前端·javascript·学习·es6
小马学嵌入式~3 小时前
堆排序原理与实现详解
开发语言·数据结构·学习·算法
递归不收敛3 小时前
吴恩达机器学习课程(PyTorch适配)学习笔记:1.4 模型评估与问题解决
pytorch·学习·机器学习
一叶飘零_sweeeet3 小时前
从 0 到 1 掌控云原生部署:Java 项目的 Docker 容器化与 K8s 集群实战指南
docker·云原生·kubernetes·项目部署
又是忙碌的一天3 小时前
前端学习 JavaScript
前端·javascript·学习
牛马大师兄4 小时前
STM32独立看门狗IWDG与窗口看门狗WWDG知识梳理笔记
笔记·stm32·单片机·嵌入式硬件·嵌入式·看门狗
ooo-p4 小时前
FPGA学习篇——Verilog学习之计数器的实现
学习·fpga开发