Kubernetes 系列【7】Pod(容器组)

📅 2026/7/12 20:07:12 👁️ 阅读次数 📝 编程学习
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只是KubernetesAPI对象,仅仅是一段配置描述,本身不能直接运行程序。真正拉起镜像、创建隔离环境的是容器运行时(containerdCRI-Odocker)。kubelet调用CRI接口,依靠容器运行时去创建容器,没有运行时,Pod只会停留在Pending状态,无法启动。

1.3 共享上下文

Pod的共享上下文由一组Linux命名空间、cgroups以及其他隔离机制构成,和容器自身的隔离技术完全一致。在Pod的整体隔离环境内,单个业务容器还可以再做一层子隔离。

共享命名空间:

  • 整个Pod共用:网络命名空间、UTS主机名命名空间。
  • 所以多个容器共用同一个IP,能够用localhost互相访问。
  • PID、挂载、用户命名空间默认不共享,每个容器内部依然相互隔离。

CgroupsControl Groups,控制组)是Linux内核提供的资源管控技术,用来把一组进程捆在一起,限制它们最多能用多少CPU、内存、磁盘IO

Cgroups资源组:

  • 同一个Pod下所有容器归属同一套CPU、内存限额,可以整体限制资源。

可以把Pod理解为一组共享命名空间与存储卷的容器集合。多个容器被打包进同一个网络环境,并且共用数据卷。

1.4 两种使用场景

Kubernetes集群内的Pod主要有两种使用场景。

只有互相强依赖、必须部署在一起的程序才放进同一个Pod。松耦合服务(前端、后端、数据库)必须分成多个独立Pod

1.4.1 单容器

一个Pod只运行一个容器,是最常用的部署模式。

绝大多数微服务(网关、后端服务、RedisMySQL)都采用该模式:

一个业务实例 = 一个 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列(比如CrashLoopBackOffTerminating)只是给人看的提示,不等于 phase 阶段

phase是集群底层API标准字段,二者要分清。

示例:

NAMESPACE NAME READY STATUS RESTARTS AGE alessandras-namespace alessandras-pod 0/1 CrashLoopBackOff 200 2d9h
  • CrashLoopBackOff:容器反复启动失败,不停崩溃重启
  • TerminatingPod正在删除中

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。推荐通过DeploymentJob这类工作负载资源来创建。如果Pod需要持久化状态,则使用StatefulSet

一个Pod对应应用的单个实例。如果你需要横向扩容(启动更多实例提升整体算力),应当创建多个独立Pod,一个实例对应一个Pod。在Kubernetes里,这种多副本机制被称为副本管理。多副本Pod通常由控制器统一创建、批量管理。

无论由你手动创建,还是由控制器自动创建,新Pod都会被调度到集群某个节点上。Pod会一直驻留在该节点,直到运行结束、对象被删除、因资源不足被驱逐,或是所在节点故障。

注意:重启Pod内部的容器 ≠ 重启整个PodPod不是进程,而是容器的运行环境。只要不被删除,Pod对象会一直存在。

Pod名称必须是合法的DNS子域名,但这可能导致主机名出现异常。为保证最大兼容性,Pod名称建议遵守更严格的DNS标签命名规则。


2.2 指定操作系统

可以通过.spec.os.name字段填写windowslinux,声明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,新增节点自动部署,删除节点自动回收

示例1Deployment(最常用无状态工作负载):

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:OnFailure

Pod创建完成后,大部分核心字段(镜像、命令、挂载等)无法直接就地修改。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 patchkubectl replace等命令就地修改运行中Pod。但官方做了极强的权限限制,仅开放极少数字段更新,绝大多数核心配置、元数据均为永久不可变。

以下元数据字段永久锁定,任何更新操作都会直接报错,是K8s底层强约束:

  • 命名空间metadata.namespace
  • Pod名称metadata.name
  • 资源唯一标识metadata.uid
  • 创建时间戳metadata.creationTimestamp

补充特殊约束:若Pod已设置删除时间戳(进入Terminating终止状态),禁止新增终结器(finalizers)条目,防止删除流程阻塞、资源死锁。

仅开放6类字段支持运行中原地更新:

  • spec.containers[*].image:业务容器镜像版本
  • spec.initContainers[*].image:初始化容器镜像版本
  • spec.activeDeadlineSecondsPod最大运行时长
  • spec.terminationGracePeriodSeconds:优雅终止等待时长
  • spec.tolerations:节点容忍度配置(仅允许新增,禁止删除/修改旧规则)
  • spec.schedulingGates:调度网关配置

针对spec.activeDeadlineSeconds,仅支持两种修改:

  • 将空值改为正数;
  • 将已有正数改得更小(非负数)。

3.1.2 子资源专项变更

常规更新只支持上述字段,其余配置需要通过子资源来变更:

  1. Resize(资源调整):更新容器CPU、内存配额,参考容器资源扩容文档。
  2. Ephemeral Containers(临时容器):向运行中的Pod注入调试容器。
  3. Status(状态):更新Pod状态,仅由kubelet和系统控制器使用。
  4. 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分配唯一IPPod内所有容器共享同一个网络命名空间,共用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直接管理apiserveretcd等控制面组件。

详情查看静态 Pod 文档。

说明:
静态Podspec不能引用其他的API对象(例如:ServiceAccountConfigMapSecret等)。


3.6 容器探针

探针是kubelet 周期性对容器执行的健康检测,支持三种检测方式:

  1. ExecAction:在容器内执行命令
  2. TCPSocketAction:端口连通性检测
  3. HTTPGetActionHTTP接口健康检查

更多内容请查阅 Pod 生命周期文档。