Skip to main content

Kubernetes 全景解析 (1):工作负载与 Pod 生命周期深度解析

Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡
... VIEWS

"Pods are the atomic unit of scheduling in Kubernetes — not containers."

在 Kubernetes 的世界里,工作负载 (Workload) 是你与应用交互的核心抽象。无论你是部署一个无状态的 Web 服务、一个有状态的数据库,还是在每个节点上运行监控 Agent,K8s 都提供了专门的工作负载资源来满足需求。而所有这些工作负载的基础,都建立在 Pod 之上。

本文将从 Pod 的本质出发,逐层深入解析 Kubernetes 中五大核心工作负载资源的设计理念、编排策略与最佳实践,帮助你在架构选型时做出正确的决策。


一、Pod:K8s 的原子调度单元

1.1 为什么 Pod 是最小部署单元而非容器

许多初学者会困惑:既然 Docker 已经有了容器概念,为什么 Kubernetes 还要引入 Pod?答案在于 "超亲密容器"(Hyper-privileged Containers) 的设计哲学。

在现实世界中,一个应用往往不是孤立运行的。例如:

  • 一个 Web 服务器需要配合一个日志采集 Sidecar
  • 一个主进程需要配合一个健康检查辅助进程
  • 一个数据管道需要同时运行 ingest 和 transform 两个紧密协作的进程

这些进程需要共享网络命名空间(可以通过 localhost 互相通信)、共享存储卷(可以读写同一份数据),并且需要作为一个原子单元被调度到同一个节点上。Pod 正是为了解决这一需求而诞生的。

核心原则

Pod 是 Kubernetes 中最小的可调度单元。一个 Pod 可以包含一个或多个容器,这些容器共享相同的网络和存储命名空间,始终被调度到同一个节点上,并作为一个整体进行生命周期管理。

1.2 Pod 的设计理念

Pod 的设计围绕三个核心能力展开:

能力说明典型场景
共享网络同一 Pod 内的所有容器共享同一个 IP 地址和端口空间,可以通过 localhost 互相访问主容器 + Sidecar 代理
共享存储Pod 可以声明多个 Volume,这些 Volume 可以被 Pod 内的任意容器挂载主容器写日志,Sidecar 读取并转发
原子调度Pod 内的所有容器作为一个整体被调度到同一个节点保证本地通信的低延迟

Sidecar 模式 是 Pod 多容器设计中最经典的模式。例如,Istio 服务网格通过在每个 Pod 中注入一个 Envoy Sidecar 代理来实现流量管理、安全通信和可观测性,而无需修改应用代码。

1.3 Pod 的 YAML 结构详解

下面是一个完整的 Pod YAML 示例,每个字段都附有详细注释:

apiVersion: v1 # API 版本,Pod 属于核心 v1 组
kind: Pod # 资源类型
metadata:
name: nginx-pod # Pod 名称,在同一个 Namespace 内必须唯一
namespace: default # 命名空间,不指定则使用 default
labels: # 标签,用于选择器和组织资源
app: nginx
tier: frontend
annotations: # 注解,用于存储非标识性的元数据
description: "A sample nginx pod"
spec:
# --- 重启策略 ---
restartPolicy: Always # 容器退出后的重启策略:Always / OnFailure / Never

# --- 节点选择 ---
nodeSelector: # 通过标签选择节点
disktype: ssd
tolerations: # 容忍度,用于调度到有特定 Taint 的节点
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"

# --- 容器定义 ---
containers:
- name: nginx # 容器名称
image: nginx:1.27 # 镜像地址(含标签)
imagePullPolicy: IfNotPresent # 镜像拉取策略:Always / IfNotPresent / Never
ports:
- containerPort: 80 # 容器暴露的端口(仅声明,不自动发布)
protocol: TCP
resources: # 资源请求与限制
requests: # 调度时保证的最小资源量
cpu: "100m" # 100 millicores = 0.1 核
memory: "128Mi"
limits: # 容器可使用的最大资源量
cpu: "500m"
memory: "256Mi"
env: # 环境变量
- name: ENVIRONMENT
value: "production"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts: # 挂载存储卷
- name: nginx-data
mountPath: /usr/share/nginx/html
livenessProbe: # 存活探针
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe: # 就绪探针
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
startupProbe: # 启动探针(K8s 1.18+)
httpGet:
path: /startup
port: 80
failureThreshold: 30 # 最多失败 30 次(即最多等待 300 秒)

# --- Init 容器 ---
initContainers:
- name: init-db
image: busybox:1.36
command: ['sh', '-c', 'until nslookup db-service; do echo waiting for db; sleep 2; done']

# --- 存储卷 ---
volumes:
- name: nginx-data
persistentVolumeClaim:
claimName: nginx-pvc # 引用 PVC
- name: config-volume
configMap:
name: nginx-config # 引用 ConfigMap

# --- DNS 配置 ---
dnsPolicy: ClusterFirst # DNS 策略:ClusterFirst / Default / ClusterFirstWithHostNet / None
最佳实践
  1. 始终设置 resources.requestsresources.limits,避免资源争抢导致节点不稳定。
  2. 使用 imagePullPolicy: IfNotPresent 而非 Always(除非使用 :latest 标签),以减少镜像拉取延迟。
  3. 为生产环境的镜像使用明确的 digest(如 nginx@sha256:abc123...),确保部署的可重复性。

1.4 Pod 生命周期

Pod 从创建到终止会经历一系列状态变化。理解这些状态对于排查问题至关重要。

各状态说明:

状态含义
PendingPod 已被 Kubernetes 集群接受,但一个或多个容器尚未创建并就绪。包括等待调度和下载镜像的时间。
RunningPod 已绑定到节点,所有容器已创建,至少一个容器仍在运行,或正在启动/重启中。
SucceededPod 中的所有容器已成功终止,且不会重启。
FailedPod 中的所有容器已终止,且至少一个容器以失败状态退出(非零退出码或被系统终止)。
Unknown由于某种原因无法获取 Pod 状态,通常是与节点通信失败。
CrashLoopBackOff 和 Terminating 不是 Pod Phase

CrashLoopBackOffTerminating 可能会出现在 kubectl 命令的 Status 输出中,但它们不是 Pod 的 phase 值。Pod phase 是 Kubernetes 数据模型中的显式字段,只有五个值:PendingRunningSucceededFailedUnknown

  • CrashLoopBackOff:容器反复崩溃退出,K8s 在每次重启之间增加指数退避等待时间(10s → 20s → 40s → ...,上限 300s)。
  • Terminating:Pod 正在被删除,处于优雅终止过程中(默认 30 秒宽限期)。

参考文档:Pod Lifecycle - Pod phase

1.5 Probe 机制:Liveness / Readiness / Startup

Kubernetes 通过三种探针来监控容器的健康状态:

探针类型作用失败后果
Liveness Probe检测容器是否活着重启容器
Readiness Probe检测容器是否就绪(能否接收流量)从 Service Endpoints 中移除
Startup Probe检测容器是否启动完成在启动期间禁用其他探针

探针支持四种检测方式:

  • httpGet:向容器发送 HTTP GET 请求,2xx/3xx 状态码视为成功。
  • tcpSocket:尝试与容器的指定端口建立 TCP 连接。
  • exec:在容器内执行命令,返回码为 0 视为成功。
  • grpc(v1.24+ 稳定):使用 gRPC 健康检查协议,服务状态为 SERVING 视为成功。
注意事项
  • 不要省略探针。没有探针的 Pod 在容器进程僵死(如死锁)时无法被自动恢复。
  • Startup Probe 是慢启动应用的救星。如果你的应用启动需要较长时间(如 Java 应用加载类库),务必配置 Startup Probe,否则 Liveness Probe 可能在应用尚未就绪时就杀死容器。
  • Readiness Probe 不应过于严格,否则可能导致滚动更新时出现流量中断。

参考文档:Configure Liveness, Readiness and Startup Probes


二、Deployment:无状态应用的编排之王

Deployment 是 Kubernetes 中最常用的工作负载资源,专门用于管理无状态应用。它提供了声明式更新、滚动发布和回滚等生产级特性。

2.1 ReplicaSet 与 Deployment 的关系

Deployment → 管理 → ReplicaSet → 管理 → Pod

ReplicaSet (RS) 是下一层的控制器,负责确保指定数量的 Pod 副本始终在运行。而 Deployment 是更高层的抽象,它在 ReplicaSet 之上增加了版本管理滚动更新能力。

实践建议

在日常使用中,几乎不需要直接操作 ReplicaSet。你应该始终通过 Deployment 来管理应用,让 K8s 自动处理 ReplicaSet 的创建和清理。

2.2 滚动更新(Rolling Update)策略

Deployment 支持两种更新策略:

策略说明适用场景
RollingUpdate(默认)逐步替换旧 Pod 为新 Pod,保证零停机生产环境
Recreate先删除所有旧 Pod,再创建新 Pod不兼容多版本共存的场景

RollingUpdate 通过两个关键参数控制更新节奏:

  • maxSurge:更新期间允许超出期望副本数的最大 Pod 数(可以是绝对数或百分比)。
  • maxUnavailable:更新期间允许不可用的最大 Pod 数(可以是绝对数或百分比)。
默认值

Deployment 默认的滚动更新策略为:maxSurge: 25%maxUnavailable: 25%。这意味着在更新期间,可用副本数至少为 75%,最多为 125%。

参考文档:Deployments - Updating a Deployment

2.3 回滚机制(Rollback)

Deployment 的每一次更新都会创建一个新的 ReplicaSet,并保留历史版本(由 revisionHistoryLimit 控制,默认为 10)。这使得回滚操作变得极其简单:

# 查看部署历史
kubectl rollout history deployment/nginx-deployment

# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment

# 回滚到指定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=2

2.4 完整 YAML 示例

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 3 # 期望的 Pod 副本数
revisionHistoryLimit: 10 # 保留的历史 ReplicaSet 数量
strategy:
type: RollingUpdate # 更新策略:RollingUpdate / Recreate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多多创建 1 个 Pod
maxUnavailable: 0 # 滚动更新时最多允许 0 个 Pod 不可用
selector:
matchLabels: # 必须与 Pod template 的 labels 匹配
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
生产环境建议
  • 设置 maxUnavailable: 0 可以确保滚动更新过程中服务容量不会下降,代价是更新期间需要更多资源(maxSurge 需要大于 0)。
  • 配合 Pod Disruption Budget (PDB) 使用,可以在节点维护时确保最少可用副本数。

三、StatefulSet:有状态应用的首选

StatefulSet 专为需要稳定网络标识持久存储的有状态应用设计,如数据库(MySQL、PostgreSQL)、消息队列(Kafka、RabbitMQ)和分布式存储系统(Elasticsearch、etcd)。

3.1 与 Deployment 的核心区别

特性DeploymentStatefulSet
Pod 标识随机生成的名称(如 nginx-7b9f...固定的序号名称(如 mysql-0, mysql-1
网络标识Pod IP 随重建而变化每个 Pod 有稳定的 DNS 名称
存储所有 Pod 共享相同的 PVC每个 Pod 有独立的 PVC
部署顺序并行创建按序号顺序创建(0 → 1 → 2 → ...)
删除顺序并行删除按序号逆序删除(... → 2 → 1 → 0)
扩缩容随机选择 Pod 删除/创建严格按序号操作

3.2 有序部署/扩展/删除

StatefulSet 的核心特性之一是有序性 (Ordinality)。当创建或扩展 StatefulSet 时,Pod 会按照序号从 0 开始依次创建,且只有前一个 Pod 进入 Running 且 Ready 状态后,才会创建下一个 Pod。

3.3 稳定的网络标识和持久存储

StatefulSet 为每个 Pod 提供以下稳定性保证:

  • 稳定的网络标识:Pod 名称格式为 <statefulset-name>-<ordinal>(如 mysql-0),且关联的 Headless Service 会为每个 Pod 创建一个稳定的 DNS 记录:<pod-name>.<headless-service>.<namespace>.svc.cluster.local
  • 持久存储:通过 volumeClaimTemplates,StatefulSet 会为每个 Pod 自动创建独立的 PVC。即使 Pod 被重新调度到其他节点,只要绑定了相同的 PVC,数据就不会丢失。

3.4 完整 YAML 示例

apiVersion: v1
kind: Service # Headless Service,用于稳定的网络标识
metadata:
name: mysql
labels:
app: mysql
spec:
clusterIP: None # Headless Service:不分配 ClusterIP
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql # 必须指向关联的 Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
livenessProbe:
exec:
command: ["mysqladmin", "ping", "-h", "localhost"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["mysql", "-h", "localhost", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates: # 为每个 Pod 自动创建独立的 PVC
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 10Gi
注意事项
  • StatefulSet 不会自动创建 Headless Service,你需要手动创建。
  • 删除 StatefulSet 时,默认不会删除关联的 PVC,以防止数据丢失。如需同时删除,需要手动清理。
  • StatefulSet 的滚动更新默认使用 OnDelete 策略(即手动删除 Pod 后才会重建),如需自动滚动更新,需设置 .spec.updateStrategy.type: RollingUpdate

参考文档:StatefulSets


四、DaemonSet:节点级守护进程

DaemonSet 确保集群中的每个(或特定)节点上都运行一个 Pod 副本。当节点加入集群时,DaemonSet 会自动为其创建 Pod;当节点移除时,这些 Pod 也会被自动回收。

4.1 典型使用场景

场景示例
日志收集Fluentd、Filebeat、Promtail
监控 AgentPrometheus Node Exporter、Datadog Agent
网络插件Calico、Cilium、Flannel
存储守护进程Ceph、GlusterFS 客户端
安全合规Falco(运行时安全检测)、Twistlock

4.2 滚动更新策略

DaemonSet 支持三种更新策略:

策略说明
RollingUpdate(默认)逐个节点更新 Pod,可通过 maxUnavailable 控制并发度
OnDelete手动删除旧 Pod 后才会创建新 Pod
Surging(K8s 1.22+)先创建新 Pod 再删除旧 Pod,节点上会短暂运行两个 Pod

4.3 完整 YAML 示例

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 最多允许 1 个节点上的 Pod 不可用
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # 使用宿主机网络(监控场景常见)
hostPID: true # 使用宿主机 PID 命名空间
tolerations: # 容忍所有 Taint,确保在所有节点上运行
- operator: Exists
containers:
- name: node-exporter
image: prom/node-exporter:v1.8.0
args:
- "--web.listen-address=:9100"
- "--path.procfs=/host/proc"
- "--path.sysfs=/host/sys"
ports:
- containerPort: 9100
hostPort: 9100
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
resources:
limits:
cpu: 200m
memory: 100Mi
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
最佳实践
  • DaemonSet 通常需要使用 hostNetwork: truehostPID: truehostPath 卷来访问节点级别的资源。
  • 始终配置 tolerations 以确保 DaemonSet Pod 可以被调度到带有 Taint 的节点(如 Master 节点)。
  • 为 DaemonSet Pod 设置严格的资源限制,避免它们占用过多节点资源影响业务应用。

五、Job 与 CronJob:任务编排

5.1 一次性任务(Job)

Job 用于运行一次性任务,确保 Pod 成功执行完毕后终止。Job 会持续跟踪 Pod 的完成状态,并在失败时根据重试策略重新创建 Pod。

核心字段说明:

字段说明默认值
completions需要成功完成的 Pod 数1
parallelism并行运行的 Pod 数1
backoffLimit最大重试次数6
activeDeadlineSecondsJob 超时时间(秒),超时后标记为失败无限制
ttlSecondsAfterFinishedJob 完成后的自动清理时间(K8s 1.23+)永不清理

5.2 并行任务(Parallelism + Completions)

Job 的 parallelismcompletions 字段可以组合出不同的执行模式:

parallelismcompletions模式
11单次顺序执行
N1N 个 Pod 并行竞争,任一成功即完成
NNN 个 Pod 并行工作队列模式
1N顺序执行 N 个任务

5.3 定时任务(CronJob)

CronJob 基于 Cron 表达式来定期创建 Job。它的调度规则与 Linux 的 crontab 基本一致,格式为:

# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 日 (1 - 31)
# │ │ │ ┌───────────── 月 (1 - 12)
# │ │ │ │ ┌───────────── 星期 (0 - 6, 0 = 周日)
# │ │ │ │ │
# * * * * *
CronJob 时区

从 Kubernetes v1.25 起,CronJob 支持 timeZone 字段,可以指定 Cron 表达式所使用的时区(IANA 时区格式,如 "Asia/Shanghai")。未指定时默认使用 UTC 时区。

参考文档:CronJobs

apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
spec:
schedule: "0 2 * * *" # 每天凌晨 2 点执行
concurrencyPolicy: Forbid # 禁止并发运行
successfulJobsHistoryLimit: 3 # 保留最近 3 个成功的 Job
failedJobsHistoryLimit: 1 # 保留最近 1 个失败的 Job
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 3600 # 超过 1 小时则标记为失败
template:
spec:
containers:
- name: backup
image: postgres:16
command:
- /bin/bash
- -c
- pg_dump -h db-service -U $DB_USER -d $DB_NAME > /backup/$(date +%Y%m%d).sql
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_NAME
value: "myapp"
volumeMounts:
- name: backup-data
mountPath: /backup
restartPolicy: Never # Job 必须设置为 Never 或 OnFailure
volumes:
- name: backup-data
persistentVolumeClaim:
claimName: backup-pvc
重要提醒
  • Job 的 Pod restartPolicy 必须设置为 NeverOnFailure,不能是 Always
  • concurrencyPolicy: Forbid 确保上一次任务尚未完成时不会启动新任务,对于数据库备份等场景至关重要。
  • 务必设置 successfulJobsHistoryLimitfailedJobsHistoryLimit,避免历史 Job 堆积消耗 etcd 存储空间。

5.4 Job 完整 YAML 示例

apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
completions: 1 # 需要成功完成 1 次
parallelism: 1 # 同时运行 1 个 Pod
backoffLimit: 3 # 最多重试 3 次
activeDeadlineSeconds: 600 # 超时 10 分钟
ttlSecondsAfterFinished: 86400 # 完成后 24 小时自动清理
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: myapp:v2.0
command: ["python", "manage.py", "migrate"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url

六、ReplicaSet / ReplicationController(简述)

ReplicationController (RC)

ReplicationController 是 Kubernetes 最早的副本管理机制,用于确保指定数量的 Pod 副本始终运行。它已被 ReplicaSet 取代,目前仅存在于 API 中以保持向后兼容。

ReplicaSet (RS)

ReplicaSet 是 ReplicationController 的升级版,主要改进是支持基于集合的标签选择器(Set-based Selector),使得选择逻辑更加灵活。

特性ReplicationControllerReplicaSet
标签选择器仅支持等值匹配(environment=production支持集合匹配(environment in (production, staging)
推荐使用已废弃作为 Deployment 的底层实现,不直接使用
实践建议

不要直接创建 ReplicaSet。使用 Deployment 来管理无状态应用,Deployment 会在底层自动创建和管理 ReplicaSet。只有在需要执行非常特殊的操作(如手动管理 Pod 副本)时,才考虑直接使用 ReplicaSet。


七、工作负载选择决策树

面对不同的业务需求,如何选择合适的工作负载资源?以下决策树可以帮助你快速做出判断:

快速参考表

工作负载核心特征典型场景Pod 数量
Deployment无状态、可滚动更新、可回滚Web 服务、API 服务、微服务可变(replicas)
StatefulSet有状态、稳定标识、有序部署数据库、消息队列、分布式存储可变(replicas)
DaemonSet每节点一个 Pod日志收集、监控 Agent、网络插件= 节点数
Job一次性任务,完成后终止数据迁移、批处理、CI/CD固定(completions)
CronJob定时创建 Job数据库备份、报表生成、清理任务每次执行创建新 Job

八、本章小结

本文从 Pod 的本质出发,系统地解析了 Kubernetes 中五大核心工作负载资源:

  1. Pod 是 Kubernetes 的原子调度单元,通过共享网络和存储实现了"超亲密容器"的协作模式。理解 Pod 的生命周期和探针机制是排查问题的基础。

  2. Deployment 是无状态应用的首选,通过 ReplicaSet 实现版本管理,支持零停机的滚动更新和一键回滚。

  3. StatefulSet 为有状态应用提供了稳定的网络标识、独立的持久存储和有序的部署/删除策略,是运行数据库和消息队列等场景的最佳选择。

  4. DaemonSet 确保每个节点运行一个 Pod 副本,是部署基础设施组件(日志、监控、网络插件)的标准方式。

  5. Job 与 CronJob 覆盖了一次性任务和定时任务的需求,支持灵活的并行度和重试策略。

选择工作负载资源时,核心判断依据是:应用是否有状态是否需要长期运行是否需要在每个节点上运行。掌握这些工作负载的特性与适用场景,是构建可靠 Kubernetes 应用的基石。

在下一篇文章中,我们将深入探讨 Kubernetes 的 Service 与网络模型,解析 ClusterIP、NodePort、LoadBalancer 和 Ingress 的工作原理与选型策略。


参考文档

本文内容基于 Kubernetes 官方文档校验,以下为核心参考链接:

Logo
RainLib

Exploring the frontiers of technology, design, and distributed systems. Building tools for the future developers.

© 2026 RainLib. Built for the Future.
All rights reserved.
System Normal