Pod 核心资源
Pod 是 Kubernetes 最小的调度和部署单元。看似简单,但它的内部机制(Pause 容器、共享 Namespace)、生命周期状态机和多种容器模式决定了你能不能用好它。本章把 Pod 讲透,后续的 Deployment、StatefulSet 等都建立在它之上。
本篇目标:理解 Pause 容器与共享 Namespace 的原理,掌握 Pod 生命周期状态与优雅停机,会配置 Init 容器、Sidecar 与临时调试容器,并理解 Pod 与控制器(谁负责重建它)的关系。

1. Pod 深度理解
1.1 Pause 容器与共享 Namespace
一个 Pod 可以包含多个容器,这些容器共享同一组 Linux Namespace(网络、UTS、IPC、PID 视情况),因此它们:
- 共享同一个 IP 和端口空间(通过
localhost互通); - 共享同一个 hostname;
- 可以共享 IPC 信号量和消息队列;
- 通过共享 volume 共享文件。
这一共享机制由 Pause 容器(k8s.gcr.io/pause) 实现:每个 Pod 在创建业务容器之前,先创建一个 Pause 容器,它负责持有上述 Namespace,业务容器通过 JoinContainers 加入。Pause 容器极小(几十 KB)、无业务逻辑,即使业务容器全部退出它也会一直运行,直到整个 Pod 被删除。
Pod(网络/IP 由 Pause 持有)
├── pause ← 共享 Namespace 的"锚点",始终运行
├── main-app ← 业务容器
└── sidecar ← 日志采集等辅助容器
1.2 Pod 里的端口与资源是容器级的
spec.containers[].ports是声明性的(帮助文档与 Service 发现),不限制监听;resources(requests/limits)按容器配置,QoS 等级按整个 Pod计算(详见第 14 章);- 多容器 Pod 中,日志和探针都要通过
-c <container>指定容器。
1.3 控制器与裸 Pod
Pod 有两种"出身":
| 方式 | 谁来维持 | 异常退出后 |
|---|---|---|
| 裸 Pod(直接创建) | 没有控制器 | 不会被自动重建,仅按 restartPolicy 在节点上重启 |
| 控制器管理(Deployment 等) | Deployment/ReplicaSet | 控制器创建新 Pod 补回副本数 |
除临时调试外,不应直接手工维护裸 Pod。kubectl run 创建的裸 Pod 适合验证,不适合生产。
# 查看 Pod 里的容器与 Pause 的关系
kubectl get pod <pod-name> -n learning -o jsonpath='{.spec.containers[*].name}'
kubectl get pod <pod-name> -n learning -o wide
2. Pod 的生命周期与状态
2.1 状态转换
Pending ──调度成功──▶ Running ──正常退出──▶ Succeeded
│ │
└── 镜像/调度失败 └── 异常退出 ──▶ Failed
│
└── 按 restartPolicy 重启 ◀── CrashLoopBackOff
| 状态 | 含义 | 排障方向 |
|---|---|---|
Pending | 已提交但尚未调度成功,或正在拉镜像 | 资源、污点、选择器、PVC、配额 |
Running | 容器已启动 | 但别轻信——进程可能在初始化,端口未必就绪 |
Succeeded | 所有容器正常退出(重启策略非 Always) | Job 完成,正常 |
Failed | 容器异常退出(重启策略非 Always) | 退出码、日志、OOM |
CrashLoopBackOff | 不断启动失败 → kubelet 延长重启间隔 | logs --previous 是最关键证据 |
Terminating | 收到删除请求,正在优雅退出 | finalizer、挂载、preStop 卡住 |
2.2 容器重启策略
Pod 的 restartPolicy 决定容器退出后的重启行为:
| 策略 | 常见控制器 | 含义 |
|---|---|---|
Always | Deployment / StatefulSet / DaemonSet | 容器退出后由 kubelet 重启 |
OnFailure | Job | 成功退出不重启,失败时重试 |
Never | Job | 容器退出后不在该 Pod 内重启 |
CrashLoopBackOff 不是独立的错误类型,而是容器不断失败、kubelet 逐步延长重启间隔(10s → 20s → 40s → … 上限 5 分钟)的结果。优先看 kubectl logs --previous,不要先删 Pod 掩盖现场。
2.3 优雅停机
容器收到 SIGTERM 后应优雅退出,超时未退出会被 SIGKILL:
spec:
terminationGracePeriodSeconds: 30 # 总共给 30 秒优雅退出
containers:
- name: api
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
- 删除 Pod 时,kubelet 先执行
preStop,再向主进程发 SIGTERM; terminationGracePeriodSeconds是总时限(默认 30 秒),超时强制 SIGKILL;- 生产上优雅停机常与 readiness 探针配合,让 Service 先把流量切走(详见第 15 章与第 21 章)。
3. Pod 进阶特性
3.1 Init 容器:启动前的准备
Init 容器在主容器启动之前运行,完成后退出。典型场景是"等某个依赖就绪再启动主容器":
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command:
- sh
- -c
- |
until nslookup postgres.learning.svc.cluster.local; do
echo "等待数据库 DNS 就绪…"
sleep 2
done
- name: run-migration
image: registry.example.com/app:1.4.2
command: ["./bin/migrate"]
containers:
- name: api
image: registry.example.com/app:1.4.2
关键特性:
- 按顺序执行,前一个成功退出才启动下一个;
- 任何一个 Init 容器失败,整个 Pod 按
restartPolicy重试; - 可以访问与主容器不同的镜像和工具(比如拿
busybox做网络检查,主容器是精简镜像); - Init 容器完成退出后不会被重新启动。
3.2 Sidecar 容器:长期伴随主容器
从 Kubernetes 1.28 起,Init 容器增加 restartPolicy: Always,可作为 Sidecar 使用:在主容器启动前完成准备,之后持续运行(不退出),主容器退出时也会被回收:
spec:
initContainers:
- name: log-agent
image: registry.example.com/log-agent:2.1.0
restartPolicy: Always # 1.28+,作为 Sidecar 持续运行
volumeMounts:
- name: logs
mountPath: /var/log/app
containers:
- name: api
image: registry.example.com/api:1.4.2
适合日志采集、网络代理等"伴随主容器运行"的辅助进程。注意:并非所有环境都支持 Sidecar(需 1.28+ 与容器运行时支持),常用替代是普通 container 或 DaemonSet 采集(见第 7 章)。
3.3 多容器设计模式
| 模式 | 思路 | 示例 |
|---|---|---|
| Sidecar | 为主容器增强能力,共享同一 Pod | 日志采集、网络代理 |
| Ambassador | 代理主容器的外部访问 | 把本地端口转发到外部服务 |
| Adapter | 把主容器的输出标准化 | 把日志格式转为统一 JSON |
选择多容器还是多 Pod:需要共享 IP/端口/生命周期,用多容器;相互独立、各自扩缩,用多 Pod(如 DaemonSet 采集)。
3.4 临时调试容器(Ephemeral Container)
运行中的 Pod 需要调试但不想污染它时,可用 kubectl debug 注入临时容器——它不进入 Pod 的重启逻辑,调试完即删:
kubectl debug <pod-name> -n learning \
--image=netshoot:v0.16 \
--target=<container-name> \
-it -- sh
# 或创建调试副本(不侵入原 Pod)
kubectl debug <pod-name> -n learning \
--image=busybox:1.36 \
--copy-to=debug-pod \
-it -- sh
4. 一份最小 Pod 清单
apiVersion: v1
kind: Pod
metadata:
name: web
namespace: learning
labels:
app.kubernetes.io/name: web
spec:
containers:
- name: web
image: nginx:1.27-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
生产上这份配置应交给 Deployment 等控制器管理(下一章),而不是直接创建裸 Pod。
5. 练习
练习 A
- 用
kubectl run创建一个裸 Pod(nginx:alpine),再delete它,感受裸 Pod 不会被自动重建 - 改用 Deployment 创建同样镜像的 Pod,
delete其中一个 Pod,观察 Deployment 自动补回 - 用
kubectl get pod -o jsonpath='{.spec.containers[*].name}'查看容器列表,结合describe观察 Pause 相关字段
练习 B
- 创建一个带 Init 容器的 Deployment:Init 容器打印一条消息后 sleep 3 秒,主容器用 busybox 持续 sleep
- 观察 Init 容器日志:
kubectl logs <pod-name> -c <init-container-name> - 给容器添加
preStop钩子(sleep 5),删除 Pod 后观察Terminating阶段持续时间 - 故意把
terminationGracePeriodSeconds设为 5,preStop sleep 设为 15,观察 kubelet 在 5 秒后 SIGKILL - 用
kubectl debug给一个运行中的 Pod 注入临时容器,验证可以查看进程和网络
下一篇:Deployment 应用发布。