返回首页

2.1 Pod 详解:最小调度单元

这一章我们把 Pod 拆开讲清楚:它为什么是最小调度单元、多个容器如何协作、Init Container 与 Sidecar 分别解决什么问题、Probe 为什么会直接影响流量和重启,以及常见状态与重启策略到底怎么看。::cite[372]::cite[373]::cite[505]

2.1.1 Pod 的本质与设计初衷

官方对 Pod 的定义很直接:Pod 是 Kubernetes 中可以创建和管理的最小可部署计算单元。一个 Pod 可以包含一个或多个容器,这些容器会被 共同调度到同一台节点,并共享网络与存储上下文。::cite[372]

你可以把 Pod 理解成“逻辑主机”。在传统虚拟机里,多个进程共享同一个网络栈、同一个磁盘空间;在 Kubernetes 里,Pod 就承担了这个“共同宿主”的角色。容器本身仍然是隔离的,但它们可以通过 localhost 通信、共享卷中的文件,并被整体地创建、运行、迁移与销毁。::cite[372]

Pod 的设计初衷主要有三点:

  • 把需要紧密协作的容器放在一个调度单元里。
  • 让这些容器天然共享网络和存储,而不是通过复杂的跨节点访问来拼接。
  • 让控制器(如 Deployment)以 Pod 为粒度进行副本管理和故障修复。::cite[372]

为什么不直接把每个容器都独立调度?

因为现实中的应用并不总是单进程模型。很多场景里,主业务进程之外还需要一个辅助进程,例如:

  • 日志采集器
  • 配置渲染器
  • 本地代理
  • 证书刷新器
  • 数据同步程序

如果这些辅助进程必须和业务容器共享本地文件或通过 localhost 协作,把它们放到同一个 Pod 会简单很多。::cite[372]::cite[505]

2.1.2 Pod 中的一个或多个容器如何协作

Pod 中的容器有两个最核心的共享能力:

共享项 说明
网络命名空间 同一个 Pod 内的容器共享 IP 和端口空间,可以直接通过 localhost 通信
存储卷 多个容器可以把同一个 Volume 挂载到不同路径,实现文件共享

这也是为什么“多容器 Pod”通常用于 紧耦合协作,而不是把无关服务硬塞进一个 Pod。::cite[372]

单容器 Pod:最常见形态

大多数业务场景下,一个 Pod 只运行一个主容器。即使如此,你仍然应该把这个容器当作 Pod 的一部分去理解,而不是把 Pod 等同于容器。

多容器 Pod:典型协作方式

常见的协作模式包括:

  1. 主容器 + Sidecar 容器

    • 主容器处理业务。
    • Sidecar 负责日志转发、代理、监控增强等辅助功能。
  2. 主容器 + 本地代理

    • 例如应用容器通过 localhost 调用同 Pod 内的认证代理或缓存代理。
  3. 主容器 + 文件生产者/消费者

    • 一个容器写入共享卷,另一个容器读取共享卷中的文件。::cite[372]::cite[505]

一个简单的双容器协作示意

下面的例子中,主容器持续写日志到共享卷,辅助容器持续读取同一份日志:

apiVersion: v1
kind: Pod
metadata:
  name: two-containers-demo
  labels:
    app: two-containers-demo
spec:
  volumes:
    - name: shared-data
      emptyDir: {}
  containers:
    - name: app
      image: busybox:1.36
      command:
        - /bin/sh
        - -c
        - |
          i=0
          while true; do
            echo "$(date '+%F %T') app log line ${i}" >> /data/app.log
            i=$((i+1))
            sleep 5
          done
      volumeMounts:
        - name: shared-data
          mountPath: /data
    - name: tailer
      image: busybox:1.36
      command:
        - /bin/sh
        - -c
        - |
          touch /data/app.log
          tail -f /data/app.log
      volumeMounts:
        - name: shared-data
          mountPath: /data

实操步骤

  1. 创建 Pod。
kubectl apply -f two-containers-demo.yaml
  1. 查看 Pod 状态。
kubectl get pod two-containers-demo -o wide
  1. 查看辅助容器输出。
kubectl logs two-containers-demo -c tailer
  1. 进入主容器确认共享卷文件。
kubectl exec -it two-containers-demo -c app -- sh

观察重点:两个容器虽然进程隔离,但通过 emptyDir 卷共享了文件数据;同时它们也共享同一个 Pod 网络。::cite[372]

2.1.3 Init Container、Sidecar 与生命周期钩子

这一部分是 Pod 真正“像工程系统”的地方。很多初始化逻辑、依赖等待、优雅下线控制,都是靠这里完成的。

1)Init Container:先做准备,再启动业务

Init Container 是一种先于应用容器运行的特殊容器。它们按顺序执行,必须前一个成功完成,后一个才会开始,直到全部成功后,主业务容器才会启动。::cite[515]

典型用途:

  • 等待依赖服务就绪
  • 初始化目录与权限
  • 生成配置文件
  • 执行数据库迁移前置检查

Init Container 很适合做“一次性准备工作”,不适合长期驻留。::cite[515]

2)Sidecar:陪跑型辅助容器

在 Kubernetes v1.32 中,原生 Sidecar 容器能力已经可用。它的实现方式是:initContainers 中定义一个 restartPolicy: Always 的容器。这样它既保留了初始化顺序控制,又能在 Pod 生命周期内持续运行。::cite[505]

Sidecar 的关键特点:

  • 与主容器同 Pod 运行,天然共享网络和卷。
  • 可以独立重启,而不影响主应用容器。
  • 在 Pod 终止时,Kubernetes 会先等主应用容器结束,再按相反顺序关闭 Sidecar。::cite[505]

3)生命周期钩子:在关键节点插入动作

Kubernetes 提供两种常用的容器生命周期钩子:

钩子 触发时机 典型用途
postStart 容器启动后 初始化注册、生成运行时文件
preStop 容器终止前 优雅下线、摘流、刷新缓冲

需要注意:postStart 并不保证先于容器主进程执行完;而 preStop 会在终止流程里先执行,如果执行时间较长,你需要相应增大 terminationGracePeriodSeconds。::cite[519]::cite[373]

综合示例:Init + Sidecar + 生命周期钩子

下面是一个完整示例,包含:

  • 一个普通 Init Container:准备初始页面
  • 一个原生 Sidecar:持续跟踪共享目录内容
  • 一个主容器:运行 Nginx
  • postStart / preStop 生命周期钩子
  • 三类 Probe
apiVersion: v1
kind: Pod
metadata:
  name: pod-lifecycle-demo
  labels:
    app: pod-lifecycle-demo
spec:
  restartPolicy: Always
  terminationGracePeriodSeconds: 30
  volumes:
    - name: workdir
      emptyDir: {}
  initContainers:
    - name: init-content
      image: busybox:1.36
      command:
        - /bin/sh
        - -c
        - |
          mkdir -p /work
          echo 'hello from init container' > /work/index.html
      volumeMounts:
        - name: workdir
          mountPath: /work

    - name: file-watcher-sidecar
      image: busybox:1.36
      restartPolicy: Always
      command:
        - /bin/sh
        - -c
        - |
          touch /work/index.html
          tail -f /work/index.html
      volumeMounts:
        - name: workdir
          mountPath: /work
      startupProbe:
        exec:
          command:
            - /bin/sh
            - -c
            - test -f /work/index.html
        failureThreshold: 30
        periodSeconds: 2
      readinessProbe:
        exec:
          command:
            - /bin/sh
            - -c
            - test -f /work/index.html
        periodSeconds: 5

  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80
      volumeMounts:
        - name: workdir
          mountPath: /usr/share/nginx/html
      lifecycle:
        postStart:
          exec:
            command:
              - /bin/sh
              - -c
              - echo 'postStart executed' >> /usr/share/nginx/html/index.html
        preStop:
          exec:
            command:
              - /bin/sh
              - -c
              - sleep 10
      startupProbe:
        httpGet:
          path: /
          port: 80
        failureThreshold: 30
        periodSeconds: 2
      readinessProbe:
        httpGet:
          path: /
          port: 80
        initialDelaySeconds: 3
        periodSeconds: 5
      livenessProbe:
        httpGet:
          path: /
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 10

实操步骤

  1. 创建 Pod。
kubectl apply -f pod-lifecycle-demo.yaml
  1. 查看 Init Container 与主容器状态。
kubectl describe pod pod-lifecycle-demo
  1. 查看 Sidecar 输出。
kubectl logs pod-lifecycle-demo -c file-watcher-sidecar
  1. 验证页面内容。
kubectl exec -it pod-lifecycle-demo -c nginx -- cat /usr/share/nginx/html/index.html
  1. 删除 Pod,观察 preStop 带来的优雅终止。
kubectl delete pod pod-lifecycle-demo

2.1.4 Probe 机制:Liveness、Readiness、Startup

Probe 是 kubelet 定期对容器做的诊断检查。它可以通过 exechttpGettcpSocketgrpc 等方式执行。检查结果有三种:SuccessFailureUnknown。::cite[373]

很多线上问题都和 Probe 配置不合理有关。一个经验法则是:Probe 不是“有没有配”,而是“配得对不对”

三种 Probe 的职责分工

Probe 类型 关注点 失败后会怎样 最典型的使用场景
livenessProbe 容器是否还活着 kubelet 杀掉容器并按重启策略处理 进程死锁、线程卡死、内部状态不可恢复
readinessProbe 容器是否准备好接流量 Pod 会从 Service 后端地址中移除 应用启动中、依赖未就绪、临时摘流
startupProbe 容器是否完成启动 失败会触发重启;成功前禁用其他 Probe 启动慢、预热时间长、需要加载大配置

官方文档明确说明:如果配置了 startupProbe,那么在它成功之前,livenessProbereadinessProbe 都不会生效。这样做是为了避免“应用其实还在启动中,却被 liveness 误杀”。::cite[373]

常见配置思路

场景 1:普通 Web 应用

  • readinessProbe 检查 /ready
  • livenessProbe 检查 /healthz
  • 通常不一定需要 startupProbe

场景 2:启动慢的 Java / AI / 大模型推理服务

  • startupProbe 给足预热时间
  • readinessProbe 在依赖准备完后再放流量
  • livenessProbe 仅负责发现真正的死锁或卡死

场景 3:需要优雅摘流

  • 删除 Pod 时,Kubernetes 会先把 Pod 变为不 Ready,再执行终止流程
  • 如果还需要额外清理,可配合 preStop 完成优雅关闭。::cite[373]

Probe 配置误区

  • 把 liveness 和 readiness 检查写成完全一样:容易导致暂时不可用也被误判成要重启。
  • 启动慢却没有 startupProbe:应用还没启动完就被 liveness 打死,形成 CrashLoopBackOff
  • 检查逻辑太重:特别是 exec 探针,会带来额外进程创建开销。::cite[373]

2.1.5 Pod 常见状态与重启策略

Pod Phase:高层生命周期摘要

Pod 的 phase 是一个高层摘要,不等于你在 kubectl get pod 里看到的所有展示状态。官方定义的常见 phase 如下:::cite[373]

Phase 含义
Pending Pod 已被接受,但还没完成调度、拉镜像或容器准备
Running Pod 已绑定节点,且至少有一个容器在运行或启动中
Succeeded 所有容器成功退出,且不再重启
Failed 所有容器都已退出,且至少有一个失败退出
Unknown 无法获取 Pod 状态,通常与节点通信异常有关

注意:CrashLoopBackOff 不是 Pod Phase

这是一个非常容易混淆的点。

CrashLoopBackOffkubectl 展示给你的用户友好状态,不是 Pod API 中定义的 phase。它表示容器反复失败、并进入指数退避重启。::cite[373]

容器状态 vs Pod 状态

容器级别还有三种常见状态:

容器状态 含义
Waiting 容器还在等待启动,如拉镜像、挂载 Secret
Running 容器已运行
Terminated 容器已退出,可能成功也可能失败

定位问题时,要同时看:

  • kubectl get pod
  • kubectl describe pod
  • kubectl logs

restartPolicy:容器退出后的处理方式

Pod 级别的 restartPolicy 取值有三种:

策略 含义 常见场景
Always 任何退出都自动重启 长期运行服务,默认值
OnFailure 仅异常退出时重启 批处理任务、一次性任务
Never 退出后不重启 手动调试、只跑一次的任务

需要注意两点:

  1. Pod 级别 restartPolicy 适用于应用容器和普通 Init Container。
  2. 原生 Sidecar 容器会忽略 Pod 级别的这个字段,因为它自己在 initContainers 中通过 restartPolicy: Always 定义行为。::cite[373]::cite[505]

当容器连续崩溃时,kubelet 会采用指数退避方式重启:10 秒、20 秒、40 秒……上限 300 秒;如果容器稳定运行约 10 分钟后再失败,这个退避计时会被重置。::cite[373]

2.1.6 实战排错清单

当一个 Pod 启不来时,建议按这个顺序排查:

  1. 看整体状态。
kubectl get pod
  1. 看详细事件。
kubectl describe pod <pod-name>
  1. 看容器日志。
kubectl logs <pod-name> -c <container-name>
  1. 如果是多容器 Pod,逐个容器看日志。
kubectl logs <pod-name> -c <sidecar-name>
  1. 如果怀疑 Probe 配置问题,重点检查:
  • 端口是否正确
  • 路径是否正确
  • 应用是否真的在那个时间点可用
  • initialDelaySeconds / failureThreshold / periodSeconds 是否合理

2.1.7 本章小结

这一章最重要的结论有四个:

  1. Pod 不是容器,而是最小调度单元。
  2. 一个 Pod 内多个容器共享网络和卷,适合紧耦合协作。
  3. Init Container 负责启动前准备,Sidecar 负责运行期辅助,生命周期钩子负责关键时机动作。
  4. Probe 与重启策略直接决定服务稳定性,配置错误会制造大量伪故障。

真正写业务 YAML 时,建议优先保持 Pod 简单:

  • 单容器优先
  • 多容器只在确有强协作关系时使用
  • Probe 配置从保守开始
  • 对终止流程有要求时,一定明确 preStopterminationGracePeriodSeconds

📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

Chapter 6.5:Admission Controller

下一篇

3.1 调度器原理:Pod 为什么会落到这台节点