当前位置: 首页 > backend >正文

Kubernetes控制平面组件:Kubelet详解(六):pod sandbox(pause)容器

云原生学习路线导航页(持续更新中)

  • kubernetes学习系列快捷链接
    • Kubernetes架构原则和对象设计(一)
    • Kubernetes架构原则和对象设计(二)
    • Kubernetes架构原则和对象设计(三)
    • Kubernetes控制平面组件:etcd(一)
    • Kubernetes控制平面组件:etcd(二)
    • Kubernetes控制平面组件:API Server详解(一)
    • Kubernetes控制平面组件:API Server详解(二)
    • Kubernetes控制平面组件:调度器Scheduler(一)
    • Kubernetes控制平面组件:调度器Scheduler(二)
    • Kubernetes控制平面组件:Controller Manager 之 内置Controller详解
    • Kubernetes控制平面组件:Controller Manager 之 NamespaceController 全方位讲解
    • Kubernetes控制平面组件:Kubelet详解(一):架构 及 API接口层介绍
    • Kubernetes控制平面组件:Kubelet详解(二):核心功能层
    • Kubernetes控制平面组件:Kubelet详解(三):CRI 容器运行时接口层
    • Kubernetes控制平面组件:Kubelet详解(四):gRPC 与 CRI gRPC实现
    • Kubernetes控制平面组件:Kubelet详解(五):切换docker运行时为containerd
    • Kubernetes控制平面组件:Kubelet 之 Static 静态 Pod

本文是 kubernetes 的控制面组件 kubelet 系列文章第六篇,主要讲解了 pod 的 沙箱sandbox容器,也称为pause容器,介绍了pause容器的核心作用、技术细节、工作原理、常用运维命令等,最后还对pause容器的源码进行了分析

  • 希望大家多多 点赞 关注 评论 收藏,作者会更有动力继续编写技术文章

1.pod 的容器组成:sandbox+业务containers

  • 在kubernetes中,pod容器由 sandbox + 业务containers 组成,除了业务自己的功能容器,每一个pod还包含一个sandbox容器,镜像一般为 pause,所以也称为 pause 容器
  • 在 Kubernetes控制平面组件:Kubelet详解(三):CRI 容器运行时接口层 中我们介绍了crictl的基本使用。使用crictl可以查看pod的sandbox容器
    • crictl ps:查看pod 的业务容器
    • crictl pods:查看pod 的sandbox pause容器
    • 下面例子可以看出,虽然都是nginx-sts-0这一个pod,但是找到两个不同的容器
    # 查看pod的sandbox容器
    [root@VM-226-235-tencentos ~]# crictl pods | grep nginx-sts-0
    da081a3c7ba60       10 hours ago        Ready               nginx-sts-0                                    default             0                   (default)
    # 查看pod的业务容器
    [root@VM-226-235-tencentos ~]# crictl ps | grep nginx-sts-0
    d99ea5d921d87       a830707172e80       10 hours ago        Running             nginx                     0                   da081a3c7ba60       nginx-sts-0
    

2.pod 的 sandbox 容器

2.1.pause 容器的核心作用

  • 在 Kubernetes 中,Pod 的沙箱容器(Sandbox Container),通常被称为 pause 容器,是 Pod 实现多容器共享命名空间的核心组件。它的存在对 Pod 的正常运作至关重要,但往往被开发者忽视。
  • pause 容器是 Kubernetes 为每个 Pod 创建的第一个容器,它的核心作用是为 Pod 提供共享的 Linux 命名空间(如网络、IPC、PID 等),并作为 Pod 生命周期的锚点
功能说明
维持命名空间确保 Pod 内的所有容器共享相同的网络、IPC 等命名空间。
防止 Pod 崩溃若所有应用容器退出,pause 容器仍存活,避免 Pod 被误判为终止。
处理僵尸进程作为 PID 1 进程,负责回收孤儿进程(僵尸进程),避免资源泄漏。
Pod 生命周期管理Kubelet 通过监控 pause 容器的状态来判断 Pod 是否存活。

2.2.pause 容器的技术细节

2.2.1.镜像来源
  • 默认镜像:registry.k8s.io/pause:<version>(例如 registry.k8s.io/pause:3.9
  • 镜像体积极小(约 700KB),仅包含一个极简的静态编译的 pause 进程。
2.2.2.进程行为
  • pause 进程启动后会无限休眠(通过调用 pause() 系统调用),不执行任何业务逻辑。
  • 代码开源地址:https://github.com/kubernetes/kubernetes/tree/master/build/pause
2.2.3.资源占用
  • CPU 和内存消耗极低,通常可忽略不计。
  • 示例 crictl pods 输出:
    [root@VM-226-235-tencentos ~]# crictl pods | grep nginx-sts-0da081a3c7ba60       10 hours ago        Ready               nginx-sts-0                                    default             0                   (default)
    

2.3.pause 容器的工作原理

2.3.1.步骤 1:Pod 创建
  1. Kubelet 收到创建 Pod 的指令。
  2. 先创建 pause 容器,该容器初始化 Pod 的共享命名空间(如网络命名空间)。
  3. 其他应用容器(如 Nginx、Redis)加入 pause 容器的命名空间
2.3.2.步骤 2:命名空间共享
  • 网络命名空间:所有容器共享同一个 IP 和端口空间,因此可以通过 localhost 互相通信。
  • IPC 命名空间:允许容器通过 System V IPC 或 POSIX 消息队列通信。
  • PID 命名空间:容器可以看到彼此的进程(通过 ps -ef)。
2.3.3.步骤 3:Pod 终止
  • 当 Pod 被删除时,Kubelet 先终止 pause 容器,触发共享命名空间的释放。
  • 所有关联的应用容器会被自动终止。

2.4.查看 pause 容器

  • 命令

    # 列出所有 Pod 沙箱容器(包括 pause 容器)
    crictl pods# 查看 pause 容器的详细信息,会包含:pause在主机上的进程号、pause镜像等
    crictl inspectp <pause_container_id>
    
  • 我们知道每一个容器,在主机上都是一个进程,pause容器也不例外。从进程输出看,我的主机上跑了很多个pause进程,每个pod都会有一个

    [root@VM-226-235-tencentos ~]# ps  -ef | grep /pause
    root      4754     1  3 00:13 ?        00:23:43 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.1 --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock
    65535     5598  5497  0 00:13 ?        00:00:00 /pause
    65535     5600  5520  0 00:13 ?        00:00:00 /pause
    65535     5614  5546  0 00:13 ?        00:00:00 /pause
    65535     5625  5537  0 00:13 ?        00:00:00 /pause
    65535     7203  7146  0 00:14 ?        00:00:00 /pause
    65535     7220  7182  0 00:14 ?        00:00:00 /pause
    65535     7339  7286  0 00:14 ?        00:00:00 /pause
    65535     7346  7298  0 00:14 ?        00:00:00 /pause
    65535     8796  8723  0 00:14 ?        00:00:00 /pause
    65535     8921  8784  0 00:14 ?        00:00:00 /pause
    65535     9013  8866  0 00:14 ?        00:00:00 /pause
    65535     9028  8945  0 00:14 ?        00:00:00 /pause
    65535     9057  8999  0 00:14 ?        00:00:00 /pause
    65535     9063  8980  0 00:14 ?        00:00:00 /pause
    root      9160  9137  0 00:14 ?        00:00:00 /pause
    65535    14471 14451  0 00:16 ?        00:00:00 /pause
    

2.5.常见问题与解答

2.5.1.能否不用 pause 容器?
  • 不能。Kubernetes 依赖 pause 容器实现命名空间共享和生命周期管理。若直接删除 pause 容器,Pod 内的其他容器将无法正常工作。
2.5.2.为什么 pause 容器一直处于运行状态?
  • 这是设计行为。pause 容器需要持续运行以维持命名空间,直到 Pod 被显式删除。
2.5.3.如何自定义 pause 镜像?
  • 修改 Kubelet 的启动参数:
    --pod-infra-container-image=my-registry/pause:custom
    
    注意:自定义镜像需兼容 Kubernetes 的 CRI 接口。
2.5.4.pause 容器占用资源异常?
  • 正常情况下,pause 容器几乎不消耗资源。若发现异常:
    1. 检查是否被攻击者利用(例如恶意进程注入)。
    2. 使用 crictl inspectp 查看容器状态。
    3. 排查节点上的安全漏洞。

2.6.深入理解:pause 容器与僵尸进程

  • 问题:在 Linux 中,孤儿进程会被 PID 1 进程接管。若 PID 1 进程未正确处理 SIGCHLD 信号,僵尸进程会累积。
  • pause 容器的解决方案
    • pause 进程会主动回收子进程,因此即使应用容器内的进程产生僵尸进程,也会被 pause 容器清理。

3.为什么kubernetes要引入pause容器?

  • 首先,pause容器镜像极小,几乎不占用资源,且处于长期sleep状态,不处理业务,极度稳定,基本不会主动退出
  • 此时就可以把一些 net namespace、pid namespace 等挂载给它,使得pod的网络非常稳定。只要pause容器存活,不论业务容器重启多少次,网络namespace都会存在,即使pod是crash的,也可以ping通,只是业务端口可能断掉了
  • 另外,sandbox容器的启动在所有业务容器之前,可以为业务容器提供一个就绪的网络环境等 容器前置依赖

4.pause 容器源码分析

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

  • 我们以linux为例:https://github.com/kubernetes/kubernetes/tree/master/build/pause/linux
    在这里插入图片描述

4.1.pause.c

/*
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.0Unless 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 <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// 信号处理函数:当收到 SIGINT/SIGTERM 时优雅终止容器
static void sigdown(int signo) {psignal(signo, "Shutting down, got signal");exit(0);
}// 信号处理函数:回收僵尸进程(SIGCHLD 信号触发)
static void sigreap(int signo) {// 循环调用 waitpid 回收所有已终止的子进程while (waitpid(-1, NULL, WNOHANG) > 0);
}int main(int argc, char **argv) {int i;// 处理命令行参数 "-v":打印版本信息for (i = 1; i < argc; ++i) {if (!strcasecmp(argv[i], "-v")) {printf("pause.c %s\n", VERSION_STRING(VERSION));return 0;}}// 警告:如果 pause 不是 PID 1(即不是容器第一个进程)if (getpid() != 1)fprintf(stderr, "Warning: pause should be the first process\n");// 注册信号处理器if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)return 1;  // 处理 Ctrl+C/SIGINTif (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)return 2;  // 处理 Kubernetes 发送的终止信号(如 Pod 删除)if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap,.sa_flags = SA_NOCLDSTOP},NULL) < 0)return 3;  // 处理子进程退出(SA_NOCLDSTOP 表示不处理停止事件)// 主循环:通过 pause() 挂起进程,保持容器运行for (;;)pause();  // pause() 会阻塞直到收到信号// 此处代码理论上不会执行fprintf(stderr, "Error: infinite loop terminated\n");return 42;
}

4.2.orphan.c

/*
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.0Unless 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.
*//* 测试工具:生成一个孤儿进程,验证 pause 容器的僵尸进程回收能力 */#include <stdio.h>
#include <unistd.h>int main() {pid_t pid;pid = fork();if (pid == 0) {    // 子进程分支// 等待父进程退出(父进程 PID 变为 1)while (getppid() > 1);printf("Child exiting: pid=%d ppid=%d\n", getpid(), getppid());return 0;} else if (pid > 0) {  // 父进程分支// 父进程立即退出,使子进程成为孤儿进程printf("Parent exiting: pid=%d ppid=%d\n", getpid(), getppid());return 0;}// fork 失败处理perror("Could not create child");return 1;
}
http://www.xdnf.cn/news/7056.html

相关文章:

  • JSON Schema 高效校验 JSON 数据格式
  • 微服务项目->在线oj系统(Java版 - 2)
  • c++编写中遇见的错误
  • 【AWS入门】Amazon SageMaker简介
  • 4:OpenCV—保存图像
  • 解决 Tailwind CSS 代码冗余问题
  • 机器学习(12)——LGBM(1)
  • Python爬虫基础
  • 选择合适的AI模型:解析Trae编辑器中的多款模型及其应用场景
  • Go 语言中的一等公民(First-Class Citizens)
  • Flutter与Kotlin Multiplatform(KMP)深度对比及鸿蒙生态适配解析
  • STM32单片机开发环境搭建 keil/proteus仿真/STM32CubeMX
  • 【OpenGL学习】(三)元素缓冲对象(EBO)的使用
  • Limesurvay系统“48核心92GB服务器”优化方案
  • uniapp的适配方式
  • PDF批量合并拆分+加水印转换 编辑 加密 OCR 识别
  • 软件架构之-论软件系统架构评估以及应用
  • Zookeeper入门(三)
  • 《Vite 报错》ReferenceError: module is not defined in ES module scope
  • 影刀处理 Excel:智能工具带来的高效变革
  • 广域网学习
  • 数据结构与算法——栈和队列
  • Python字符串格式化(一):三种经典格式化方法
  • 从零开始实现大语言模型(十六):加载开源大语言模型参数
  • 《Python星球日记》 第87天:什么是大语言模型 LLM?
  • 1_Spring 【IOC容器的创建】
  • 深入了解linux系统—— 基础IO(下)
  • 【QGIS二次开发】地图编辑-08
  • tauri2项目使用sidcar嵌入可执行文件并使用命令行调用
  • 实战设计模式之状态模式