Pod 详解:Kubernetes 最小调度单元 Pod
摘要:Pod 是 Kubernetes 最基础也最核心的概念。本文深入讲解 Pod 的内部结构、为什么需要 Pod、Pod 的生命周期以及多容器 Pod 模式。
一、为什么不直接管理容器?
Kubernetes 引入 Pod 而非直接管理容器,是为了支持需要共享网络和存储的紧密协作容器组。
独立容器方案存在网络隔离、无法共享文件、可能被调度到不同节点等问题。Pod 将一组容器作为调度单元,共享网络命名空间和存储卷,确保它们始终在同一节点运行且可通过 localhost 通信。
二、Pod 的内部结构
2.1 Pod 剖析
每个 Pod 包含一个 Pause 容器(Infra 容器)和若干应用容器。Pause 容器持有网络命名空间,应用容器共享该网络栈。
Pause 容器创建并持有网络命名空间,提供共享的 IP 和端口空间。应用容器共享网络命名空间(localhost 互通)、IPC 命名空间和存储卷,但各自拥有独立的文件系统。
2.2 共享与隔离资源
Pod 内容器共享网络、IPC、Volume 和 Pod 级 DNS;文件系统和 PID 命名空间默认隔离,PID 可通过配置共享。
三、Pod 的生命周期
3.1 阶段(Phase)
Pod 从创建到终止经历 Pending、Running、Succeeded/Failed 等阶段。
| 阶段 | 说明 |
|---|---|
| Pending | 已被接受,容器尚未创建(拉镜像或等待调度) |
| Running | 至少一个容器正在运行 |
| Succeeded | 所有容器成功终止,不会重启 |
| Failed | 至少一个容器以非零状态退出 |
| Unknown | 无法获取状态(通常为节点通信问题) |
3.2 创建到运行流程
从 kubectl apply 到 Pod 进入 Running 的完整流程如下:
API Server 持久化 Pod 后,Scheduler 选择节点并绑定;kubelet 创建 Sandbox、运行 Init 容器、启动主容器、执行 postStart Hook,随后持续执行健康检查。
3.3 Pod 终止流程
删除 Pod 时,kubelet 执行优雅关闭流程,确保流量不再进入并给应用预留关闭时间。
Pod 进入 Terminating 后,先从 Service 端点移除,执行 preStop Hook,发送 SIGTERM,等待 terminationGracePeriodSeconds(默认 30 秒),超时后发送 SIGKILL。
四、Init 容器
Init 容器在主容器启动之前按顺序执行,用于初始化环境或等待依赖就绪。
Init 容器按定义顺序执行,每个必须成功完成才能进入下一个。可包含主容器镜像中不存在的工具,常用于等待依赖服务、下载配置、执行数据库迁移等。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z mysql-svc 3306; do echo waiting; sleep 2; done']
- name: init-config
image: busybox
command: ['sh', '-c', 'cp /config/app.conf /app/config/']
volumeMounts:
- name: config-vol
mountPath: /app/config
containers:
- name: myapp
image: myapp:v1
volumeMounts:
- name: config-vol
mountPath: /app/config
volumes:
- name: config-vol
emptyDir: {}
五、多容器 Pod 模式
5.1 常见设计模式
- Sidecar:主容器与辅助容器协作,辅助容器提供日志收集、监控代理、服务网格代理等功能。
- Ambassador:主容器通过本地代理访问外部服务,代理负责连接外部数据库、API 网关等。
- Adapter:主容器输出原始数据,适配器容器负责格式转换后输出给监控或日志系统。
5.2 模式适用场景
| 模式 | 典型场景 |
|---|---|
| Sidecar | 日志收集、监控代理、Envoy 等服务网格 |
| Ambassador | 数据库代理、API 网关代理 |
| Adapter | 日志格式化、监控指标适配 |
六、Pod YAML 详解
完整 Pod 定义示例,涵盖常用字段说明:
apiVersion: v1
kind: Pod
metadata:
name: my-app
namespace: default
labels:
app: my-app
version: v1
annotations:
description: "My application pod"
spec:
restartPolicy: Always # Always | OnFailure | Never
initContainers:
- name: init
image: busybox
command: ['sh', '-c', 'echo init done']
containers:
- name: app
image: nginx:1.24
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
env:
- name: APP_ENV
value: "production"
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 3
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
emptyDir: {}
6.1 顶层字段
| 字段 | 类型 | 说明 |
|---|---|---|
apiVersion | string | API 版本,Pod 固定为 v1 |
kind | string | 资源类型,固定为 Pod |
metadata.name | string | Pod 名称,在 Namespace 内唯一 |
metadata.namespace | string | 所属命名空间,默认 default |
metadata.labels | map | 键值对标签,用于 Service 选择器、调度约束等筛选 |
metadata.annotations | map | 键值对注解,存放非标识性元数据(描述、配置参数等) |
6.2 spec 核心字段
| 字段 | 类型 | 说明 |
|---|---|---|
spec.restartPolicy | string | 重启策略:Always(默认)、OnFailure、Never |
spec.initContainers[] | list | Init 容器列表,按顺序执行,全部成功后才启动主容器 |
spec.containers[] | list | 主容器列表(必填),至少包含一个容器 |
spec.volumes[] | list | 声明 Pod 级别的存储卷,供容器通过 volumeMounts 挂载 |
spec.nodeSelector | map | 节点选择器,通过标签约束 Pod 调度到特定节点 |
spec.tolerations[] | list | 容忍列表,允许 Pod 调度到带有匹配污点的节点 |
spec.serviceAccountName | string | 指定 Pod 使用的 ServiceAccount,影响 RBAC 权限 |
spec.terminationGracePeriodSeconds | int | 优雅终止等待时间(秒),默认 30 |
6.3 containers 字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 容器名称,Pod 内唯一 |
image | string | 容器镜像地址,格式 registry/repo:tag |
ports[].containerPort | int | 容器监听端口,声明性字段(不影响网络行为,用于文档和 Service 映射) |
resources.requests | map | 调度时的资源请求量,Scheduler 据此选择节点 |
resources.limits | map | 运行时的资源上限,超出 CPU 限制会被 throttle,超出内存限制会被 OOMKilled |
env[] | list | 环境变量列表,支持 value 直接赋值或 valueFrom 引用 ConfigMap/Secret |
command | list | 覆盖镜像的 ENTRYPOINT |
args | list | 覆盖镜像的 CMD |
volumeMounts[] | list | 将 spec.volumes 中声明的卷挂载到容器内的指定路径 |
6.4 探针字段
| 字段 | 类型 | 说明 |
|---|---|---|
livenessProbe | object | 存活探针:检测容器是否正常运行,失败则重启容器 |
readinessProbe | object | 就绪探针:检测容器是否准备好接收流量,失败则从 Service Endpoints 中移除 |
startupProbe | object | 启动探针:检测容器是否完成启动,期间 liveness/readiness 不生效,适合慢启动应用 |
探针通用参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
initialDelaySeconds | 0 | 容器启动后等待多少秒开始探测 |
periodSeconds | 10 | 探测间隔(秒) |
timeoutSeconds | 1 | 单次探测超时时间(秒) |
successThreshold | 1 | 连续成功多少次判定为成功 |
failureThreshold | 3 | 连续失败多少次判定为失败 |
探针支持三种检测方式:httpGet(HTTP 请求)、tcpSocket(TCP 连接)、exec(执行命令检查退出码)。
七、重启策略
| 策略 | 适用场景 |
|---|---|
| Always | Web 服务等长期运行应用 |
| OnFailure | 批处理任务 |
| Never | 一次性任务 |
重启采用指数退避:第 1 次立即,第 2 次 10 秒后,之后递增,最大间隔 5 分钟。10 分钟内成功运行后计时器重置。
八、常用 kubectl 命令
# 创建 Pod
kubectl apply -f pod.yaml
# 查看 Pod
kubectl get pods
kubectl get pods -o wide
kubectl get pods --all-namespaces
kubectl get pods -l app=my-app
# 查看详情
kubectl describe pod my-app
# 查看日志
kubectl logs my-app
kubectl logs my-app -c sidecar
kubectl logs my-app -f
kubectl logs my-app --previous
# 进入 Pod
kubectl exec -it my-app -- /bin/sh
kubectl exec -it my-app -c app -- /bin/bash
# 端口转发
kubectl port-forward my-app 8080:80
# 删除 Pod
kubectl delete pod my-app
kubectl delete pod my-app --grace-period=0 --force
九、常见问题
Q1:Pod 一直 Pending 怎么办?
排查顺序:kubectl describe pod 查看 Events;确认 Scheduler 是否因资源不足、污点、亲和性等无法调度;检查节点是否 Ready、资源是否充足。
Q2:Pod 频繁重启如何排查?
查看 kubectl describe pod 的 Last State、Events,以及 kubectl logs --previous。常见原因包括:OOMKilled、liveness 失败、应用崩溃、镜像拉取失败等。
Q3:如何调试崩溃的 Pod?
使用 kubectl logs <pod> --previous 查看上次运行的日志;kubectl describe pod 查看退出码和 Events;必要时使用 kubectl run debug --rm -it --image=busybox 进行网络与存储连通性测试。
十、总结
- Pod 是 Kubernetes 最小调度单元,一组容器共享网络和存储。
- 一般一个 Pod 运行一个主容器,多容器场景使用 Sidecar、Ambassador、Adapter 等模式。
- 生产环境应通过 Deployment 等控制器管理 Pod,避免直接创建裸 Pod。
- Pod 是临时资源,可能因节点故障、驱逐、更新等原因被重建。
更多推荐
所有评论(0)