跳到主要内容

12 篇博文 含有标签「Kubernetes」

Kubernetes 容器编排平台

查看所有标签

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

· 阅读需 21 分钟
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

"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 官方文档校验,以下为核心参考链接:

Kubernetes 全景解析 (0):架构设计与核心概念

· 阅读需 20 分钟
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

"如果你觉得 Kubernetes 太复杂,那是因为它解决的问题本身就很复杂。"

在云原生(Cloud Native)的世界里,Kubernetes(简称 K8s)已经从"可选技能"变成了"基础设施常识"。无论你是后端工程师、DevOps 工程师,还是架构师,理解 K8s 的设计思想和运行机制,都是构建现代分布式系统的必修课。

然而,K8s 的学习曲线之陡峭也是出了名的。官方文档动辄数千页,概念繁多且相互关联,很容易让人陷入"见树木不见森林"的困境。

本系列文章将从架构设计出发,逐层深入到核心概念、工作负载管理、网络模型、存储体系、调度策略与安全机制,帮助你构建一套完整、系统的 K8s 认知框架。本文作为系列的第零章,将聚焦于最根本的问题:Kubernetes 是什么?它是如何设计的?它由哪些核心部分组成?


一、为什么需要 Kubernetes

1.1 容器化演进的必然之路

要理解 K8s 存在的意义,我们需要先回顾应用部署方式的演进历程:

阶段部署方式隔离性资源利用率启动速度运维复杂度
物理机时代应用直接部署在物理服务器上-
虚拟机时代Hypervisor 划分多个 VM分钟级
容器时代Docker 等容器引擎秒级
编排时代Kubernetes 等编排系统秒级低(自动化)

物理机时代,一个应用独占一台服务器,资源浪费严重。为了提高利用率,我们开始在同一个物理机上部署多个应用,但随之而来的是依赖冲突、端口争抢、一个应用崩溃拖垮整台机器等问题。

虚拟机时代,Hypervisor(如 VMware、KVM)在物理机上虚拟出多个独立的操作系统实例,实现了良好的隔离。但虚拟机本身就很重——一个 VM 动辄几个 GB,启动需要数分钟,而且携带了完整的 Guest OS,大量资源被浪费在运行重复的系统服务上。

容器时代,Docker 横空出世。容器共享宿主机的内核,不需要 Guest OS,一个镜像通常只有几十 MB,启动只需毫秒级。容器通过 Namespace 实现视图隔离,通过 Cgroups 实现资源限制,在轻量和隔离之间找到了一个绝佳的平衡点。

但容器解决的是**"如何打包和运行应用"的问题,却没有解决"如何管理成百上千个容器"**的问题。当你的应用从 3 个容器扩展到 3000 个,跨越几十台机器时,以下问题接踵而至:

  • 哪个容器应该运行在哪台机器上?
  • 容器挂了谁来重启?机器挂了谁来迁移?
  • 如何实现滚动更新而不中断服务?
  • 如何让前端服务发现后端服务的地址?
  • 如何让外部流量均匀地分发到多个实例?

这就是 Kubernetes 登场的时刻。

1.2 K8s 解决的核心问题

Kubernetes 作为一个容器编排平台(Container Orchestration Platform),本质上解决的是一个大规模自动化管理的问题。它将运维人员从手工操作中解放出来,通过声明式配置和自动化控制循环,实现了:

  • 自动部署与回滚:声明期望状态,K8s 负责将实际状态趋近期望状态
  • 服务发现与负载均衡:内置 DNS 和 Service 机制,无需外部注册中心
  • 自动扩缩容:根据 CPU/内存/自定义指标自动调整实例数量
  • 自我修复:容器崩溃自动重启,节点故障自动迁移
  • 滚动更新与蓝绿部署:零停机更新应用

1.3 K8s 的设计哲学

理解 K8s 的设计哲学,比记住一百个命令更有价值。K8s 的三个核心设计理念贯穿了它的每一个组件:

声明式(Declarative)而非命令式(Imperative)

命令式 vs 声明式
  • 命令式:你告诉系统"做什么"——docker run nginxkubectl scale deployment nginx --replicas=3
  • 声明式:你告诉系统"你要什么"——提交一个 YAML 文件描述"我需要 3 个 Nginx 实例",K8s 会持续工作直到实际状态与期望状态一致

声明式的好处是:可重复、可审计、可版本化。同一个 YAML 文件,无论执行多少次,结果都是一致的。

不可变基础设施(Immutable Infrastructure)

K8s 中的容器镜像一旦构建就不应该被修改。需要更新时,你应该构建新镜像、创建新版本,而不是 SSH 进容器里改配置。这与传统"登录服务器打补丁"的运维方式截然不同。

最终一致性(Eventual Consistency)

K8s 不保证你的请求立即生效,但保证系统最终会收敛到期望状态。这种设计牺牲了即时性,换取了极高的可靠性和容错能力。即使你同时提交了多个冲突的变更,系统也能通过控制循环最终达到一个一致的状态。


二、K8s 整体架构

Kubernetes 采用经典的主从架构(Master-Worker Architecture),分为**控制面(Control Plane)数据面(Data Plane)**两个层级。理解这两个层面的职责划分,是理解 K8s 一切行为的基础。

2.1 架构全景图

2.2 控制面组件详解

控制面是 K8s 集群的"大脑",负责全局决策和集群状态的维护。在生产环境中,为了保证高可用,控制面组件通常部署在多个独立的 Master 节点上。

kube-apiserver:集群的统一入口

kube-apiserver 是整个 K8s 系统的唯一入口。所有组件——无论是内部的 Scheduler、Controller,还是外部的 kubectl、CI/CD Pipeline——都通过 API Server 进行通信。

为什么所有通信都要经过 API Server?

这种设计被称为 "Hub-and-Spoke" 模式。它的好处是:

  1. 统一鉴权:所有请求都在一个地方进行认证(Authentication)、授权(Authorization)和准入控制(Admission Control)
  2. 解耦:各组件不需要知道彼此的存在,只需要与 API Server 交互
  3. 审计:所有操作都有统一的日志记录

API Server 本身是无状态的,它可以水平扩展。所有的状态数据都存储在 etcd 中。

etcd:集群的"真相之源"

etcd 是一个分布式的、一致的键值存储系统,基于 Raft 共识算法实现。它是 K8s 集群的唯一数据源(Single Source of Truth)——集群中所有的一切:节点信息、Pod 状态、配置数据、Secret……全部存储在 etcd 中。

etcd 是 K8s 的命脉
  • etcd 的性能直接决定了整个集群的响应速度
  • etcd 的数据丢失意味着集群状态的丢失(虽然 Pod 可以重建,但某些运行时状态无法恢复)
  • 生产环境建议部署 3 或 5 个 etcd 节点(奇数个,满足 Raft 多数派要求)
  • 必须定期备份 etcd 数据

kube-scheduler:调度决策者

当你创建一个 Pod 时,API Server 只是将这个 Pod 的信息记录到了 etcd 中——此时 Pod 还处于 Pending 状态,因为它还没有被分配到任何节点上。Scheduler 的职责就是为每个未调度的 Pod 选择一个最合适的节点。

调度过程分为三个阶段:

  1. 过滤(Filtering):排除不满足条件的节点(资源不足、端口冲突、污点容忍不匹配等)
  2. 打分(Scoring):对剩余节点进行优先级打分(亲和性、镜像本地性、负载均衡等),选择得分最高的节点
  3. 绑定(Binding):将调度决策应用到集群,将 Pod 与选定节点进行绑定
调度框架(Scheduling Framework)

从 v1.19 起,Kubernetes 调度器采用插件化架构(Scheduling Framework),上述三个阶段对应调度框架中的核心扩展点。整个调度过程分为调度周期(Scheduling Cycle)绑定周期(Binding Cycle),调度周期串行执行,绑定周期可并发执行。

参考文档:Scheduling Framework

kube-controller-manager:状态守护者

Controller Manager 运行着多个控制器(Controller),每个控制器都是一个独立的控制循环(Reconciliation Loop),负责监控集群的某一部分状态,并持续将其推向期望状态。

常见的内置控制器包括:

控制器职责
Deployment Controller确保 Deployment 管理的 Pod 副本数符合期望
ReplicaSet Controller确保 ReplicaSet 管理的 Pod 副本数符合期望
Node Controller监控节点健康状态,节点失联时触发 Pod 驱逐
Service Account Controller为命名空间创建默认 ServiceAccount
EndpointSlice Controller维护 Service 与 Pod 的映射关系(推荐使用 EndpointSlice 替代已废弃的 Endpoints)
控制器的本质:控制循环

每个控制器的工作模式都是相同的:

while true:
实际状态 = 从 API Server 获取当前状态
期望状态 = 从配置中获取期望状态
if 实际状态 != 期望状态:
执行调谐操作(创建/删除/更新)
sleep(一段时间)

这就是 K8s 所谓的**"调谐(Reconciliation)"**机制。

cloud-controller-manager:云平台桥梁

如果你在 AWS、GCP、Azure 等云平台上运行 K8s,CCM 负责与云厂商的 API 交互,管理云平台特有的资源:

  • Node Controller:调用云 API 查询节点地址和状态
  • Route Controller:配置云平台的路由规则
  • Service Controller:创建云平台的负载均衡器(如 AWS ELB)

CCM 的引入使得 K8s 的核心代码不需要耦合任何特定云厂商的 SDK,实现了云平台无关性。

2.3 数据面组件详解

数据面(也叫 Worker Node)是实际运行应用工作负载的地方。每个 Worker 节点上运行着三个核心组件:

kubelet:节点上的"车间主任"

kubelet 是运行在每个 Worker 节点上的代理,它的职责是:

  1. 接收指令:从 API Server 获取分配到本节点的 Pod 规格(Spec)
  2. 管理容器:通过 CRI(Container Runtime Interface)调用容器运行时,创建和管理 Pod 中的容器
  3. 健康检查:定期执行 Liveness Probe、Readiness Probe 和 Startup Probe
  4. 状态上报:将节点和 Pod 的状态信息上报给 API Server

你可以把 kubelet 理解为一个"车间主任"——它不制定生产计划(那是 Scheduler 的事),但负责确保分配到自己车间的生产任务被正确执行。

kube-proxy:网络规则的维护者

kube-proxy 运行在每个节点上,负责维护节点的网络规则,实现 Service 的负载均衡和网络代理。它通过操作 iptables 或 IPVS 规则,将访问 Service 的流量转发到后端的 Pod。

简单来说,当你访问一个 Service 的 ClusterIP 时,kube-proxy 维护的规则会将流量自动转发到该 Service 关联的某个 Pod 上。

kube-proxy 是可选组件(v1.34+)

根据 Kubernetes 官方文档,kube-proxy 是一个可选组件。如果你使用的网络插件(CNI)自身实现了 Service 的数据包转发功能,并提供与 kube-proxy 等效的行为,那么你不需要在集群节点上运行 kube-proxy

例如,Cilium 等现代 CNI 插件可以直接替代 kube-proxy 的功能,通过 eBPF 实现更高效的 Service 负载均衡和网络代理。

参考文档:Kubernetes Architecture - kube-proxy (optional)

Container Runtime:容器的实际执行者

kubelet 本身并不直接运行容器,而是通过 CRI(Container Runtime Interface) 标准接口调用容器运行时。常见的 CRI 兼容运行时包括:

  • containerd:目前最主流的选择,Docker 的核心运行时组件独立出来的版本
  • CRI-O:专为 Kubernetes 设计的轻量级运行时,由 Red Hat 主导
  • Kata Containers:提供虚拟机级别的隔离,适用于安全要求极高的场景
Docker 与 K8s 的"分手"

在 K8s 1.20 之前的版本中,kubelet 通过一个名为 dockershim 的内置组件直接与 Docker 通信。但从 K8s 1.24 开始,dockershim 被正式移除。这并不意味着你不能在 K8s 中运行 Docker 镜像——Docker 镜像遵循 OCI 标准,containerd 和 CRI-O 都能运行它们。移除的只是对 Docker daemon 的直接依赖。


三、核心概念模型

Kubernetes 中的一切都被抽象为 API 对象(API Object)。理解这些对象及其关系,是使用 K8s 的基础。

3.1 API 对象与声明式配置

在 K8s 中,你不需要告诉系统"如何做",而是描述"你要什么"。你通过提交 YAML(或 JSON)文件来定义 API 对象,API Server 会将你的声明持久化到 etcd,然后各个控制器会持续工作,确保实际状态趋近于你声明的期望状态。

3.2 YAML 配置结构解析

每个 K8s API 对象的 YAML 配置都遵循以下结构:

apiVersion: apps/v1 # API 版本,标识对象属于哪个 API 组
kind: Deployment # 对象类型,K8s 内置了几十种对象类型
metadata: # 对象的元数据(名称、标签、注解等)
name: nginx-deployment
namespace: default
labels:
app: nginx
tier: frontend
spec: # 对象的规格(期望状态)
replicas: 3 # 期望运行 3 个 Pod 副本
selector: # 选择器,用于关联管理的 Pod
matchLabels:
app: nginx
template: # Pod 模板,定义如何创建 Pod
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
YAML 配置的四个必填字段
  1. apiVersion:指定 API 版本。v1 是核心 API 组,apps/v1networking.k8s.io/v1 等是扩展 API 组
  2. kind:对象类型,如 Pod、Deployment、Service、ConfigMap 等
  3. metadata:对象的"身份证",至少包含 name,通常还包含 labelsannotations
  4. spec:对象的"期望状态",不同类型的对象有不同的 spec 结构

3.3 API 对象层级关系

K8s 的 API 对象之间存在着清晰的层级关系。上层对象管理下层对象,形成了一个从粗粒度到细粒度的管理链。

Pod:K8s 的最小调度单元

初学者常有一个疑问:为什么 K8s 的最小单位是 Pod 而不是 Container?

Pod 是一个逻辑概念,它可以包含一个或多个紧密耦合的容器。这些容器共享:

  • 网络命名空间:同一个 Pod 中的容器可以通过 localhost 互相访问
  • 存储卷:可以挂载共享的 Volume
  • 运行约束:总是被调度到同一个节点上

一个典型的多容器 Pod 场景是"Sidecar 模式":主容器运行应用逻辑,Sidecar 容器负责日志收集、监控数据导出或代理转发。


四、一次请求的完整旅程

理论讲了不少,现在让我们通过一个具体的场景来串联所有知识:当你执行 kubectl apply -f nginx-deployment.yaml 时,K8s 内部到底发生了什么?

4.1 完整时序图

4.2 控制循环(Reconciliation Loop)详解

时序图展示了一次性的创建流程,但 K8s 的真正威力在于其持续运行的控制循环。让我们深入理解这个机制:

第一步:感知变化(Watch 机制)

K8s 的各个组件并不是定期轮询 API Server,而是通过基于 HTTP 长连接的 Watch 机制 来感知变化。当你创建、修改或删除一个对象时,API Server 会通过 Watch 通道将事件推送给所有订阅者。事件类型包括:

  • ADDED:新对象被创建
  • MODIFIED:对象被更新
  • DELETED:对象被删除

这种基于事件驱动的设计,比轮询更高效,延迟更低。

第二步:计算差异(Diff)

控制器收到事件后,会将实际状态期望状态进行对比。例如,Deployment Controller 发现期望的副本数是 3,但当前只有 2 个 Pod 在运行。

第三步:执行调谐(Reconcile)

控制器计算出需要执行的操作后,会通过 API Server 发起调谐请求。在上面的例子中,Deployment Controller 会创建一个新的 ReplicaSet,ReplicaSet Controller 会创建一个新的 Pod。

第四步:重复

整个过程是一个无限循环。即使某个操作失败了,下一轮循环也会再次尝试。这就是 K8s 实现自愈能力的根本原因。

水平扩展:自定义控制器

K8s 的控制器模式不仅限于内置资源。通过 CRD(Custom Resource Definition)Operator 模式,你可以定义自己的 API 对象和对应的控制器。例如,Prometheus Operator 可以管理 Prometheus 实例的生命周期,Cert-Manager Operator 可以自动化 TLS 证书的申请和续期。这就是 K8s 被称为"平台的平台"的原因。


五、本章小结与下一篇预告

本文作为 Kubernetes 全景解析系列的第零章,我们从宏观视角梳理了 K8s 的全貌:

维度核心要点
设计哲学声明式配置、不可变基础设施、最终一致性
架构分层控制面(决策)+ 数据面(执行)
控制面组件API Server(入口)、etcd(存储)、Scheduler(调度)、Controller Manager(控制循环)
数据面组件kubelet(节点代理)、kube-proxy(网络代理)、CRI(容器运行时)
核心抽象一切皆 API 对象,通过 YAML 声明期望状态
运行机制Watch 事件驱动 + 控制循环持续调谐

掌握这些基础知识后,你将不再对 K8s 感到迷茫——它的每一个行为都可以追溯到上述架构和机制中。

下一篇,我们将深入 K8s 的工作负载管理: 从 Pod 的生命周期到 Deployment、StatefulSet、DaemonSet 等工作负载控制器的使用场景与最佳实践。理解了工作负载,你就能真正开始在 K8s 上部署和运行应用了。


系列导航

章节主题状态
0架构设计与核心概念✅ 已发布
1工作负载与 Pod 生命周期深度解析✅ 已发布
2网络模型与服务发现全链路解析✅ 已发布
3存储体系与配置管理深度剖析✅ 已发布
4调度器、资源管理与弹性伸缩✅ 已发布
5安全体系与可观测性全景✅ 已发布
6生产级微服务架构实战✅ 已发布
7有状态应用与 Operator 模式实战✅ 已发布

参考文档

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