基于 Kubernetes v1.37 源码(
pkg/apis/core/types.go)
一、一切始于一个信封 @
Kubernetes 的所有资源对象,都共享同一个"信封"结构:
type Pod struct {
metav1.TypeMeta // API 版本、Kind 等元信息
metav1.ObjectMeta // 名称、命名空间、标签、注解等
Spec PodSpec // 用户声明的期望状态
Status PodStatus // 系统报告的当前状态
}
这不是巧合,而是刻意为之。TypeMeta + ObjectMeta + Spec + Status 的四段式结构,是 k8s 资源设计的统一范式:
| 部分 | 谁写 | 作用 |
|---|---|---|
TypeMeta |
系统 | 识别对象类型(apiVersion / kind) |
ObjectMeta |
用户+系统 | 唯一标识、标签选择、生命周期元数据 |
Spec |
用户 | 声明式配置(“我要什么”) |
Status |
系统 | 实际状态(“现在是什么样”) |
这个设计直接支撑了声明式 API:用户只管写 Spec,控制器负责将 Status 向 Spec 收敛。
二、核心资源群像 @
k8s 核心(core)API 组注册的资源有 16 种之多,本文介绍其中最常用的几个,可分为三类:
┌─────────────────────────────────────────────────────────────┐
│ 计算层 │
│ Pod(容器组)← Node(节点) │
├─────────────────────────────────────────────────────────────┤
│ 网络层 │
│ Service(服务抽象)→ Endpoints(后端地址) │
├─────────────────────────────────────────────────────────────┤
│ 存储层 │
│ ConfigMap / Secret(配置) │
│ PersistentVolume / PersistentVolumeClaim(持久化存储) │
└─────────────────────────────────────────────────────────────┘
2.1 Pod — 最小调度单元 @
Pod 是 k8s 最核心的资源,代表一个或多个共享网络/存储的容器组。
type PodSpec struct {
Volumes []Volume
InitContainers []Container // 初始化容器(顺序执行,全部成功后才启动主容器)
Containers []Container // 主业务容器
RestartPolicy RestartPolicy // Always / OnFailure / Never
NodeSelector map[string]string // 节点选择器
Affinity *Affinity // 亲和性(节点/Pod)
Tolerations []Toleration // 容忍度(允许调度到有污点的节点)
PriorityClassName string // 优先级
// ... 还有 40+ 字段(共 42 个)
}
几个关键设计点:
① InitContainers vs Containers
InitContainers 按顺序执行,必须全部成功。用于准备环境(如等待依赖服务、初始化数据库)。主容器只在 init 容器全部完成后才启动。
② 容器生命周期钩子
type Lifecycle struct {
PostStart *LifecycleHandler // 容器启动后执行
PreStop *LifecycleHandler // 容器终止前执行
}
PreStop 在优雅关闭时极为重要——宽限期(TerminationGracePeriodSeconds)开始后,k8s 先执行 PreStop hook,再向容器发送 SIGTERM,宽限期结束仍未退出则发送 SIGKILL。
③ 三类探针
| 探针 | 作用 | 失败后果 |
|---|---|---|
| LivenessProbe | 容器是否存活 | 重启容器 |
| ReadinessProbe | 容器是否就绪(可接流量) | 从 Service 摘除 |
| StartupProbe | 容器是否启动完成(慢启动用,成功前抑制其他探针) | 累计失败达到 failureThreshold 后重启容器(同 Liveness) |
④ 资源请求与限制
type ResourceRequirements struct {
Requests ResourceList // 最小需求(调度依据)
Limits ResourceList // 最大上限(被 cgroup 限制)
Claims []ResourceClaim // 引用的资源声明(DRA 动态资源分配)
}
调度器根据 Requests 决定 Pod 放到哪个节点;kubelet 根据 Limits 执行资源限制。
⑤ Pod 状态机
Pending → Running → Succeeded/Failed(异常时 Unknown)
Scheduled 不是 Phase,而是下面 Conditions 中的一种(PodScheduled)。每个阶段都有对应的 Conditions:
type PodConditionType string
const (
PodScheduled PodConditionType = "PodScheduled"
PodReady PodConditionType = "Ready"
PodInitialized PodConditionType = "Initialized"
ContainersReady PodConditionType = "ContainersReady"
)
2.2 Node — 工作节点 @
Node 代表集群中的一台机器。
type NodeSpec struct {
PodCIDRs []string // 分配给该节点的 Pod IP 范围
ProviderID string // 云厂商节点 ID
Unschedulable bool // 是否禁止调度(cordon/drain 时设为 true,阻止新 Pod 调度上来)
Taints []Taint // 污点(排斥不相关 Pod)
}
type NodeStatus struct {
Capacity ResourceList // 总资源
Allocatable ResourceList // 可调度资源(Capacity 减去系统预留)
Conditions []NodeCondition
Addresses []NodeAddress
NodeInfo NodeSystemInfo
}
Allocatable 的计算:
Allocatable = Capacity - KubeReserved - SystemReserved - EvictionThreshold
这个值决定了调度器能往这个节点放多少 Pod。
节点条件(Conditions):
| 条件 | 含义 |
|---|---|
Ready |
节点健康,可接收 Pod |
MemoryPressure |
内存压力大,触发驱逐 |
DiskPressure |
磁盘压力大 |
PIDPressure |
PID 压力大 |
NetworkUnavailable |
网络未就绪 |
2.3 Service — 服务抽象 @
Service 为一组 Pod 提供稳定的网络端点。
type ServiceSpec struct {
Selector map[string]string // 选择后端 Pod
Ports []ServicePort // 暴露端口
Type ServiceType // ClusterIP / NodePort / LoadBalancer / ExternalName
SessionAffinity ServiceAffinity // 会话亲和性(ClientIP / None)
ExternalTrafficPolicy ServiceExternalTrafficPolicy // 外部流量策略(Cluster / Local)
}
type ServicePort struct {
Name string
Port int32 // Service 端口
TargetPort intstr.IntOrString // 容器端口
NodePort int32 // 节点端口(NodePort 类型时)
Protocol Protocol // TCP / UDP / SCTP
}
四种类型:
| 类型 | 访问范围 | 用途 |
|---|---|---|
ClusterIP |
集群内部 | 默认,仅内部可达 |
NodePort |
节点 IP + 端口 | 外部直接访问 |
LoadBalancer |
云厂商 LB | 自动创建外部负载均衡器 |
ExternalName |
CNAME 映射 | 映射到外部服务 |
Endpoints 是 Service 的后端实现:
type Endpoints struct {
Subsets []EndpointSubset
}
type EndpointSubset struct {
Addresses []EndpointAddress // 就绪的 Pod IP
NotReadyAddresses []EndpointAddress // 未就绪的 Pod IP
Ports []EndpointPort
}
kube-proxy 监听 Endpoints 变化,更新 iptables/ipvs/nftables 规则,实现流量转发。
2.4 Namespace — 资源隔离边界 @
Namespace 提供逻辑隔离:
type NamespaceSpec struct {
Finalizers []FinalizerName // 删除前必须完成的清理逻辑
}
type NamespaceStatus struct {
Phase NamespacePhase // Active / Terminating
}
预置 Namespace:
| Namespace | 用途 |
|---|---|
default |
默认命名空间 |
kube-system |
k8s 系统组件 |
kube-public |
公开可读的 ConfigMap |
kube-node-lease |
节点心跳租约 |
Finalizers 机制:
删除 Namespace 时,Phase 先变为 Terminating,所有 Finalizer 必须完成清理后才能真正删除。这是 k8s 实现优雅删除的核心机制。
2.5 ConfigMap 与 Secret — 配置管理 @
两者结构几乎相同,区别在于 Secret 用于敏感数据:
type ConfigMap struct {
metav1.TypeMeta
metav1.ObjectMeta
Data map[string]string // 字符串数据(明文)
BinaryData map[string][]byte // 二进制数据
Immutable bool // 是否不可变
}
type Secret struct {
metav1.TypeMeta
metav1.ObjectMeta
Data map[string][]byte // Go 结构体中是原始字节,base64 编码仅发生在 JSON/YAML 序列化层
Type SecretType // Opaque / ServiceAccountToken / Dockercfg 等
Immutable bool
}
注意 BinaryData 仅存在于 ConfigMap;Secret 没有该字段,但外部 API 提供 StringData 作为写时便利字段(写入时合并进 Data,不会被持久化)。
使用方式:
- 挂载为 Volume(文件形式)
- 注入为环境变量
- 通过
immutable: true防止意外修改
2.6 PersistentVolume / PersistentVolumeClaim @
存储抽象层,解耦存储供应与消费:
type PersistentVolumeSpec struct {
Capacity ResourceList
AccessModes []PersistentVolumeAccessMode // RWO / ROX / RWX / RWOP
PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy // Retain / Delete / Recycle(已 DEPRECATED)
StorageClassName string
// 具体存储后端(NFS、CSI、云盘等)
NFS *NFSVolumeSource
CSI *CSIPersistentVolumeSource
// ...
}
type PersistentVolumeClaimSpec struct {
AccessModes []PersistentVolumeAccessMode
Resources VolumeResourceRequirements
StorageClassName *string
VolumeName string // 直接绑定指定 PV
}
生命周期:
Provisioning → Binding → Using → Releasing → Reclaiming
三、几个贯穿始终的设计模式 @
3.1 标签选择器(Label Selector) @
Service 如何找到 Pod?靠标签选择器:
type ServiceSpec struct {
Selector map[string]string // 如 {"app": "nginx", "env": "prod"}
}
后端 Pod 的 metadata.labels 必须完全匹配,才会被纳入 Service 的 Endpoints。
这是 k8s 松散耦合的核心机制:资源之间不直接引用,而是通过标签动态关联。
3.2 亲和与反亲和(Affinity) @
type Affinity struct {
NodeAffinity *NodeAffinity // 节点级:必须/偏好调度到某些节点
PodAffinity *PodAffinity // Pod 级:与某些 Pod 同域
PodAntiAffinity *PodAntiAffinity // Pod 级:与某些 Pod 异域
}
典型用法:
- PodAntiAffinity:同一服务的多个副本分散到不同节点(高可用)
- PodAffinity:应用与缓存尽量同域(减少网络延迟)
3.3 污点与容忍(Taint & Toleration) @
Node 设置 Taint 排斥不相关 Pod,Pod 设置 Toleration 允许被调度到有污点的节点。
type NodeSpec struct {
Taints []Taint // 如 {"key": "node-role.kubernetes.io/master", "effect": "NoSchedule"}
}
type PodSpec struct {
Tolerations []Toleration // 容忍上述污点
}
典型场景:专用节点(如 GPU 节点、master 节点)只运行特定 Pod。
3.4 安全上下文分层 @
安全配置分两层,容器级覆盖 Pod 级:
type PodSecurityContext struct {
RunAsUser *int64
RunAsGroup *int64
SELinuxOptions *SELinuxOptions
// ...
}
type Container struct {
SecurityContext *SecurityContext // 容器级
}
type SecurityContext struct {
RunAsUser *int64
Privileged bool
ReadOnlyRootFilesystem bool
Capabilities *Capabilities
// ...
}
3.5 资源约束 @
type LimitRange struct {
Spec LimitRangeSpec {
Limits []LimitRangeItem {
Type Type // Pod / Container / PersistentVolumeClaim
Default ResourceList // 默认 Limits
DefaultRequest ResourceList // 默认 Requests
Max ResourceList // 最大值
Min ResourceList // 最小值
}
}
}
type ResourceQuota struct {
Spec ResourceQuotaSpec {
Hard ResourceList // 命名空间级总限额
ScopeSelector *ScopeSelector // 按优先级/状态筛选
}
}
作用域:
LimitRange:限制单个 Pod/Container 的资源范围ResourceQuota:限制整个命名空间的总资源量
四、Spec/Status 分离的深层含义 @
为什么要把 Spec 和 Status 分开?
因为 k8s 的控制器模式是"不断收敛":
用户提交 Spec → 控制器读取 Spec → 对比 Status → 执行操作 → 更新 Status → 循环
如果 Spec 和 Status 混在一起,控制器无法知道:
- 这是用户想要的,还是系统当前的状态?
- 哪些字段需要被控制器更新?
一个实际例子:
spec:
replicas: 3 # 用户想要 3 个副本
status:
replicas: 2 # 当前实际运行 2 个
ReplicaSet 控制器发现 status.replicas != spec.replicas,就会创建或删除 Pod,直到两者相等;Deployment 控制器不直接管 Pod,而是管理 ReplicaSet(滚动更新、扩缩 RS 等)。
五、资源之间的关系图 @
┌─────────────────────────────────────────────────────────────┐
│ Namespace │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Deployment / StatefulSet / DaemonSet / Job / CronJob ││
│ │ │ ││
│ │ ▼ ││
│ │ ReplicaSet ───→ Pod ←─── Node ││
│ │ │ ││
│ │ ├──→ Container ││
│ │ │ ├──→ Volume (ConfigMap/Secret/ ││
│ │ │ │ PVC/PV) ││
│ │ │ └──→ Probe (Liveness/Readiness) ││
│ │ │ ││
│ │ └──→ Service ──→ Endpoints ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ConfigMap / Secret / LimitRange / ResourceQuota │
└─────────────────────────────────────────────────────────────┘
六、总结 @
Kubernetes 的核心资源模型,体现了几个设计原则:
- 声明式:用户写 Spec,系统负责实现
- 解耦:资源之间通过标签选择器动态关联,而非硬编码引用
- 分层:Pod → Node、Service → Endpoints、PV → PVC,每层职责清晰
- 可扩展:通过 CRD(Custom Resource Definition)可以定义新资源,复用同样的 Spec/Status 模式
- 安全分层:Pod 级安全上下文为默认值,容器级可覆盖,灵活且安全
理解这些核心资源,就掌握了 k8s 的"数据结构基础"。后续的控制器、调度器、网络插件,都是围绕这些资源的生命周期展开的。