基于 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 的核心资源模型,体现了几个设计原则:

  1. 声明式:用户写 Spec,系统负责实现
  2. 解耦:资源之间通过标签选择器动态关联,而非硬编码引用
  3. 分层:Pod → Node、Service → Endpoints、PV → PVC,每层职责清晰
  4. 可扩展:通过 CRD(Custom Resource Definition)可以定义新资源,复用同样的 Spec/Status 模式
  5. 安全分层:Pod 级安全上下文为默认值,容器级可覆盖,灵活且安全

理解这些核心资源,就掌握了 k8s 的"数据结构基础"。后续的控制器、调度器、网络插件,都是围绕这些资源的生命周期展开的。