Kubernetes 系列【7】Pod(容器组)
文章目录
- 1. 基本介绍
- 1.1 是什么
- 1.2 容器运行时
- 1.3 共享上下文
- 1.4 两种使用场景
- 1.4.1 单容器
- 1.4.2 多容器
- 1.5 Pod 整体阶段五种状态
- 1.6 容器的三种状态
- 2. 基础使用
- 2.1 创建
- 2.2 指定操作系统
- 2.3 使用控制器
- 2.4 模板
- 3. 进阶使用
- 3.1 更新与重建
- 3.1.1 可更新字段
- 3.1.2 子资源专项变更
- 3.1.3 版本计数
- 3.2 资源共享与进程通信
- 3.2.1 存储
- 3.2.2 网络
- 3.3 安全配置
- 3.4 资源配额:请求与限制
- 3.5 静态 Pod
- 3.6 容器探针
1. 基本介绍
Pod(容器组)是Kubernetes中最小的可调度计算单元,一个Pod代表一组紧密耦合的容器。
国内官方汉化统一译作容器组
1.1 是什么
英文单词Pod:
- 本义
1:豆荚,一个豆荚里包裹好几颗豆子; - 本义
2:鲸群,一群鲸鱼结伴同行。
K8s借用这个词来做比喻: 一个Pod= 一个封闭的荚壳,内部包裹多个容器。
Pod由一个或多个容器组成,这些容器共享存储与网络资源,同时拥有统一的运行配置。同一个Pod内的所有容器始终被调度到同一节点、协同运行,处在同一个隔离上下文环境中。
传统虚拟机场景中,我们在一台Linux虚拟机上同时运行Nginx、日志采集程序、监控代理多个进程。这些进程共用同一IP、同一磁盘目录,互相可以用localhost通信,整机一起启停,无法把其中某一个进程单独拆分到另一台机器。
K8s云场景中,Pod就等价于这一整台虚拟机,称为逻辑主机。Pod内部多个容器,对应虚拟机里的多个进程。它们共用一套网络、一套存储,整体作为调度整体,不能把容器拆开调度到不同节点。
在Kuboard中的容器组菜单:
1.2 容器运行时
集群内每个节点都必须预先安装容器运行时,Pod 才能正常运行。
Pod只是Kubernetes的API对象,仅仅是一段配置描述,本身不能直接运行程序。真正拉起镜像、创建隔离环境的是容器运行时(containerd、CRI-O、docker)。kubelet调用CRI接口,依靠容器运行时去创建容器,没有运行时,Pod只会停留在Pending状态,无法启动。
1.3 共享上下文
Pod的共享上下文由一组Linux命名空间、cgroups以及其他隔离机制构成,和容器自身的隔离技术完全一致。在Pod的整体隔离环境内,单个业务容器还可以再做一层子隔离。
共享命名空间:
- 整个
Pod共用:网络命名空间、UTS主机名命名空间。 - 所以多个容器共用同一个
IP,能够用localhost互相访问。 PID、挂载、用户命名空间默认不共享,每个容器内部依然相互隔离。
Cgroups(Control Groups,控制组)是Linux内核提供的资源管控技术,用来把一组进程捆在一起,限制它们最多能用多少CPU、内存、磁盘IO。
Cgroups资源组:
- 同一个
Pod下所有容器归属同一套CPU、内存限额,可以整体限制资源。
可以把
Pod理解为一组共享命名空间与存储卷的容器集合。多个容器被打包进同一个网络环境,并且共用数据卷。
1.4 两种使用场景
Kubernetes集群内的Pod主要有两种使用场景。
只有互相强依赖、必须部署在一起的程序才放进同一个Pod。松耦合服务(前端、后端、数据库)必须分成多个独立Pod。
1.4.1 单容器
一个Pod只运行一个容器,是最常用的部署模式。
绝大多数微服务(网关、后端服务、Redis、MySQL)都采用该模式:
一个业务实例 = 一个 Pod = 一个容器。1.4.2 多容器
Pod可以封装一套由多个紧耦合容器组成的应用,容器之间需要共享资源。同一Pod内的多个容器共同构成一个完整的服务单元。
多个组件必须满足三个条件才能放到同一个Pod:
- 必须运行在同一台节点,不能分开部署;
- 用网络与存储,需要
localhost互相调用; - 生命周期完全绑定,同时启动、同时销毁。
多容器Pod仅用于紧耦合组件,多用于主容器加边车辅助容器,多个容器共享网络与存储,整体不可拆分调度。
例如,你可能有一个容器,为共享卷中的文件提供Web服务器支持,以及一个单独的 边车(Sidecar) 容器负责从远端更新这些文件:
开启SidecarContainers特性门控后,可以给初始化容器设置restartPolicy: Always。这类容器会作为常驻边车,在Pod 整个生命周期持续运行:先于主应用启动,直到Pod销毁才退出,常用于服务网格、日志采集等辅助组件。
Pod内部多容器不能用来做水平扩容;业务扩副本要新建多个独立Pod,借助工作负载控制器完成伸缩与自愈。
1.5 Pod 整体阶段五种状态
每个Pod都有一个status状态对象,里面有个phase字段,用来简单标记Pod当前处在生命周期哪个阶段。
这个阶段只是一个粗略大分类,不会把容器所有细微状态都写进去,也不是一套完整精细的状态流转规则。
Pod整体阶段(phase)五种状态表:
| Pod阶段 | 通俗解释 | 典型场景 |
|---|---|---|
| Pending 待启动 | 集群已经接收Pod,但容器还没准备好运行 | 正在分配节点、拉取镜像、加载配置 |
| Running 运行中 | Pod已分配到机器,容器全部创建完成,至少一个容器正在工作 | 业务正常对外提供服务、容器重启过程中 |
| Succeeded 执行成功 | 所有容器全部正常跑完退出,不会自动重启 | 一次性定时任务、执行完就销毁的Pod |
| Failed 运行失败 | 所有容器都停止,至少一个容器异常退出,且不自动重启 | 程序报错崩溃、启动参数错误、资源不足无法运行 |
| Unknown 状态未知 | 集群无法获取Pod状态信息 | Pod所在节点宕机、节点和集群断开通信 |
平时敲kubectl看到的STATUS列(比如CrashLoopBackOff、Terminating)只是给人看的提示,不等于 phase 阶段。
phase是集群底层API标准字段,二者要分清。
示例:
NAMESPACE NAME READY STATUS RESTARTS AGE alessandras-namespace alessandras-pod 0/1 CrashLoopBackOff 200 2d9hCrashLoopBackOff:容器反复启动失败,不停崩溃重启Terminating:Pod正在删除中
Pod删除相关说明:
- 默认删除
Pod会预留30秒优雅关闭时间; - 加
--force参数可强制立刻删除; K8s 1.27规则:删除Pod前会先标记为Succeeded/Failed,再清理,两种例外:静态Pod、无finalizer强制删除的Pod;- 节点失联宕机后,该节点上所有
Pod都会被标记为Failed。
1.6 容器的三种状态
除了Pod整体大阶段,集群还会单独记录Pod里每一个容器的实时状态。可以配置容器生命周期钩子,在容器启动、关闭前后执行自定义脚本。
调度器把Pod分配到机器后,kubelet会创建容器,容器只有三种状态:等待中、运行中、已终止。
查看命令:kubectl describe pod容器名。
内部容器状态对照表:
| 容器状态 | 通俗解释 | 常见行为 |
|---|---|---|
| Waiting 等待中 | 容器还没正式启动,在做准备工作 | 拉镜像、加载密钥Secret、等待资源 |
| Running 运行中 | 容器正常稳定运行 | 若配置postStart启动钩子,钩子已执行完毕 |
| Terminated 已终止 | 容器启动过,之后正常结束或异常退出 | 可查看退出码、终止原因、启停时间;配置preStop停止钩子会先执行再终止 |
2. 基础使用
2.1 创建
下面是一个Pod示例,仅运行nginx:latest镜像:
apiVersion:v1kind:Podmetadata:name:nginxspec:containers:-name:nginximage:nginx:latestports:-containerPort:80执行创建命令:
kubectl apply-fsimple-pod.yaml查看集群内所有Pod(确认是否运行):
kubectl get pods# 输出简化版,显示名称、状态、重启次数、运行时长kubectl get pod nginx# 只看这个 nginx podkubectl get pod nginx-owide# -o wide 额外输出:节点IP、PodIP、镜像绝大多数场景都不需要直接创建Pod,哪怕是单实例Pod。推荐通过Deployment、Job这类工作负载资源来创建。如果Pod需要持久化状态,则使用StatefulSet。
一个Pod对应应用的单个实例。如果你需要横向扩容(启动更多实例提升整体算力),应当创建多个独立Pod,一个实例对应一个Pod。在Kubernetes里,这种多副本机制被称为副本管理。多副本Pod通常由控制器统一创建、批量管理。
无论由你手动创建,还是由控制器自动创建,新Pod都会被调度到集群某个节点上。Pod会一直驻留在该节点,直到运行结束、对象被删除、因资源不足被驱逐,或是所在节点故障。
注意:重启
Pod内部的容器 ≠ 重启整个Pod。Pod不是进程,而是容器的运行环境。只要不被删除,Pod对象会一直存在。
Pod名称必须是合法的DNS子域名,但这可能导致主机名出现异常。为保证最大兼容性,Pod名称建议遵守更严格的DNS标签命名规则。
2.2 指定操作系统
可以通过.spec.os.name字段填写windows或linux,声明Pod期望运行的操作系统。目前Kubernetes仅支持这两种操作系统,未来会继续扩展。
示例Pod配置:
apiVersion:v1kind:Podmetadata:name:linux-podspec:os:name:linux# 声明为Linux容器containers:-name:nginximage:nginx在Kubernetes v1.36版本中,该字段不会影响调度器选择节点。spec.os.name只是标记字段,不参与调度过滤。调度器不会自动根据该字段筛选同系统节点,可能会出现:Linux Pod被调度到Windows节点,镜像直接启动失败。
正确配套方案:
- 所有节点自动自带标签:
kubernetes.io/os=linux/kubernetes.io/os=windows; Pod增加nodeSelector强制匹配系统节点
示例:
spec:os:name:linuxnodeSelector:kubernetes.io/os:linux同时,Pod的安全策略也会读取此字段,避免对不匹配的系统执行无关策略。
2.3 使用控制器
直接手动创建Pod有巨大缺陷,Pod是临时资源,节点宕机、Pod崩溃后不会自动重建,也不支持批量扩容、滚动更新。
借助工作负载资源可以批量创建并管理Pod。资源对应的控制器负责处理副本扩缩、版本发布,以及Pod异常时的自动恢复。
例如某个节点宕机,控制器会检测到该节点上的Pod全部失效,并新建替代Pod,调度器会把新Pod分配到健康节点。
以下是可以管理Pod的常用工作负载资源:
| 资源 | 适用场景 | 核心特点 |
|---|---|---|
| Deployment | 无状态服务(Nginx、后端 API、微服务) | 普通无状态应用,支持滚动更新、扩缩容,Pod 无固定身份、无稳定网络标识 |
| StatefulSet | 有状态服务(MySQL、Redis、Zookeeper) | Pod 有序创建 / 删除,每个 Pod 固定主机名、稳定存储,适配需要持久身份的中间件 / 数据库 |
| DaemonSet | 节点级代理(日志收集、监控、网络代理) | 集群每个节点自动运行 1 个 Pod,新增节点自动部署,删除节点自动回收 |
示例1,Deployment(最常用无状态工作负载):
apiVersion:apps/v1kind:Deployment# 工作负载资源metadata:name:nginx-deployspec:replicas:3# 期望3个Pod副本,控制器维持数量始终为3selector:matchLabels:app:nginxtemplate:# Pod模板,控制器根据模板批量创建Podmetadata:labels:app:nginxspec:containers:-name:nginximage:nginx:latestports:-containerPort:80默认情况下,Kubernetes逐个调度每一个Pod。但部分紧耦合应用要求一组Pod同时被调度,才能正常运行。
你可以通过spec.schedulingGroup调度组字段,将多个Pod归入同一个PodGroup。调度器会识别分组,对整组Pod统一执行协同调度策略。
控制组功能状态:
Kubernetes v1.35内测版(默认关闭)
2.4 模板
工作负载控制器会依据Pod模板批量创建Pod,并全权接管生命周期管理。
如果手动创建Pod,要逐个写yaml、逐个管理,工作负载(Deployment/Job/DaemonSet)把Pod的统一配置抽成spec.template,只写一份模板,控制器自动批量生成多个Pod,统一管控。
PodTemplate不是独立API资源,嵌套在工作负载spec下,是工作负载「期望运行什么Pod」的标准描述。
创建Pod时,可以在模板内为容器配置环境变量,所有Pod统一的配置(镜像、端口、环境变量、资源限制、探针、存储挂载)全部写在template里,批量生效。
Job模板示例:
apiVersion:batch/v1kind:Job# Job 控制器根据这份模板生成一次性任务 Podmetadata:name:hellospec:# 关键:template 就是 PodTemplatetemplate:spec:containers:-name:helloimage:busybox:1.28command:['sh','-c','echo "Hello, Kubernetes!" && sleep 3600']restartPolicy:OnFailurePod创建完成后,大部分核心字段(镜像、命令、挂载等)无法直接就地修改。K8s更新模板统一策略:用新模板生成全新Pod,逐步替换旧Pod,不改动正在运行的旧Pod。
举个例子:StatefulSet控制器会保证所有运行中的Pod严格匹配当前模板。一旦你修改了模板,控制器就会逐步新建Pod,最终把所有旧实例全部替换完成。
每一种工作负载都有独立的模板更新策略。不同控制器实现更新逻辑不一样,不能一概而论,比如StatefulSet默认不自动滚动更新,需要手动触发更新。
上层控制器管理模板更新,底层
kubelet只负责运行Pod,二者互不感知,架构易扩展。
3. 进阶使用
3.1 更新与重建
3.1.1 可更新字段
在Kubernetes生态中,所有常规业务Pod均由工作负载控制器通过Pod模板统一创建与管理。Pod模板变更不会修改存量运行Pod,只会新建新版Pod完成替换更新。
Pod是不可变主体,绝大多数核心配置一经创建便无法修改,以此保障集群调度稳定性、运行一致性与故障可追溯性。
K8s并未完全禁止直接修改Pod对象,支持通过kubectl patch、kubectl replace等命令就地修改运行中Pod。但官方做了极强的权限限制,仅开放极少数字段更新,绝大多数核心配置、元数据均为永久不可变。
以下元数据字段永久锁定,任何更新操作都会直接报错,是K8s底层强约束:
- 命名空间
metadata.namespace Pod名称metadata.name- 资源唯一标识
metadata.uid - 创建时间戳
metadata.creationTimestamp
补充特殊约束:若Pod已设置删除时间戳(进入Terminating终止状态),禁止新增终结器(finalizers)条目,防止删除流程阻塞、资源死锁。
仅开放6类字段支持运行中原地更新:
spec.containers[*].image:业务容器镜像版本spec.initContainers[*].image:初始化容器镜像版本spec.activeDeadlineSeconds:Pod最大运行时长spec.terminationGracePeriodSeconds:优雅终止等待时长spec.tolerations:节点容忍度配置(仅允许新增,禁止删除/修改旧规则)spec.schedulingGates:调度网关配置
针对spec.activeDeadlineSeconds,仅支持两种修改:
- 将空值改为正数;
- 将已有正数改得更小(非负数)。
3.1.2 子资源专项变更
常规更新只支持上述字段,其余配置需要通过子资源来变更:
- Resize(资源调整):更新容器
CPU、内存配额,参考容器资源扩容文档。 - Ephemeral Containers(临时容器):向运行中的
Pod注入调试容器。 - Status(状态):更新
Pod状态,仅由kubelet和系统控制器使用。 - Binding(绑定):通过绑定请求指定节点,仅调度器使用。
3.1.3 版本计数
metadata.generation是版本号字段,由系统自动维护:新创建Pod版本号为1,每修改一次可变更的spec配置,版本号自动+1。
status.observedGeneration记录当前Pod状态对应的配置版本,由kubelet维护,外部控制器禁止修改。不同状态字段会关联不同版本:
- 直接状态更新(对应当前版本
N) - 间接状态更新(对应上一轮版本
N-1)
直接状态更新时,配置变更会直接体现在状态中:
- 资源扩容状态
- 扩容后已分配资源
- 新增临时容器且处于等待阶段
间接状态更新时,配置变更需要一段时间才能生效,状态会滞后一个版本:
- 容器镜像
ID(要等到镜像拉取完成才会更新) - 扩容过程中实际占用资源依旧是旧配额
- 需要重启的容器在扩容期间仍然沿用旧资源
- 超时时长、优雅终止时长、删除时间戳,状态生效会滞后一轮同步
3.2 资源共享与进程通信
同一个Pod内的容器可以共享数据、互相通信。
3.2.1 存储
Pod可以定义一组共享存储卷,所有容器都能读写这份存储空间,实现数据互通。即便其中某个容器重启,卷内的数据依然可以保留。
3.2.2 网络
每个IP协议族都会给Pod分配唯一IP。Pod内所有容器共享同一个网络命名空间,共用IP和端口。
- 在
Pod内部,容器之间可以直接通过localhost互相访问; - 访问外部服务时,多个容器需要协调端口占用,避免冲突;
- 除了网络调用,还可以使用
SystemV信号量、POSIX共享内存这类本机进程通信方式; - 不同
Pod拥有独立IP,不做特殊配置就无法使用本机IPC通信,跨Pod调用必须走网络IP。
Pod内所有容器看到的主机名,都等于Pod的名称,详情见网络章节。
3.3 安全配置
通过Pod配置中的securityContext字段来约束容器权限,可以精细化管控Pod或单个容器的行为。基础安全规范建议遵循基线安全标准,以非root用户运行容器。
简单安全上下文示例:
apiVersion:v1kind:Podmetadata:name:security-context-demospec:securityContext:runAsUser:1000runAsGroup:3000fsGroup:2000containers:-name:sec-ctx-demoimage:busyboxcommand:["sh","-c","sleep 1h"]有关更多详细信息,请参阅 Pod 高级配置。
如需配置内核权限、seccomp等高级策略,请阅读安全概念章节。
3.4 资源配额:请求与限制
定义Pod时,可以为容器声明资源配额,最常用的是CPU和内存。
- requests(请求):调度器依靠该值判断节点资源是否充足,决定把
Pod调度到哪台机器; - limits(上限):
kubelet强制限制资源用量,容器不得超出该数值。
CPU超限会被内核限流;内存超出限制会触发OOM杀死进程。
说明:设置
CPU上限需要权衡利弊。
配额可以防止单个业务耗尽节点资源,避免租户之间互相抢占资源,多租户环境必不可少。但即便节点还有空闲算力,CPU限流依然会触发,可能拉高延迟敏感型业务的耗时。是否开启CPU上限,要结合集群环境、业务特征和隔离要求综合判断。
资源单位、限流规则与配置示例,参考 Pod 与容器资源管理文档。
3.5 静态 Pod
静态Pod直接由节点本地的kubelet托管,不受apiserver管控。普通Pod由控制平面管理,而静态Pod完全由kubelet自主拉起、异常自动重启。
静态Pod只能绑定到某一台节点的kubelet。最典型的用途是搭建自托管控制平面,用kubelet直接管理apiserver、etcd等控制面组件。
详情查看静态 Pod 文档。
说明:
静态Pod的spec不能引用其他的API对象(例如:ServiceAccount、ConfigMap、Secret等)。
3.6 容器探针
探针是kubelet 周期性对容器执行的健康检测,支持三种检测方式:
ExecAction:在容器内执行命令TCPSocketAction:端口连通性检测HTTPGetAction:HTTP接口健康检查
更多内容请查阅 Pod 生命周期文档。
